Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 721bd4d5 authored by Gu Zheng's avatar Gu Zheng Committed by Jaegeuk Kim
Browse files

f2fs: use lock-less list(llist) to simplify the flush cmd management



We use flush cmd control to collect many flush cmds, and flush them
together. In this case, we use two list to manage the flush cmds
(collect and dispatch), and one spin lock is used to protect this.
In fact, the lock-less list(llist) is very suitable to this case,
and we use simplify this routine.

-
v2:
-use llist_for_each_entry_safe to fix possible use-after-free issue.
-remove the unused field from struct flush_cmd.
Thanks for Yu's suggestion.
-

Signed-off-by: default avatarGu Zheng <guz.fnst@cn.fujitsu.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 184a5cd2
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -347,18 +347,16 @@ enum {
};

struct flush_cmd {
	struct flush_cmd *next;
	struct completion wait;
	struct llist_node llnode;
	int ret;
};

struct flush_cmd_control {
	struct task_struct *f2fs_issue_flush;	/* flush thread */
	wait_queue_head_t flush_wait_queue;	/* waiting queue for wake-up */
	struct flush_cmd *issue_list;		/* list for command issue */
	struct flush_cmd *dispatch_list;	/* list for command dispatch */
	spinlock_t issue_lock;			/* for issue list lock */
	struct flush_cmd *issue_tail;		/* list tail of issue list */
	struct llist_head issue_list;		/* list for command issue */
	struct llist_node *dispatch_list;	/* list for command dispatch */
};

struct f2fs_sm_info {
+9 −20
Original line number Diff line number Diff line
@@ -206,24 +206,20 @@ static int issue_flush_thread(void *data)
	if (kthread_should_stop())
		return 0;

	spin_lock(&fcc->issue_lock);
	if (fcc->issue_list) {
		fcc->dispatch_list = fcc->issue_list;
		fcc->issue_list = fcc->issue_tail = NULL;
	}
	spin_unlock(&fcc->issue_lock);

	if (fcc->dispatch_list) {
	if (!llist_empty(&fcc->issue_list)) {
		struct bio *bio = bio_alloc(GFP_NOIO, 0);
		struct flush_cmd *cmd, *next;
		int ret;

		fcc->dispatch_list = llist_del_all(&fcc->issue_list);
		fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list);

		bio->bi_bdev = sbi->sb->s_bdev;
		ret = submit_bio_wait(WRITE_FLUSH, bio);

		for (cmd = fcc->dispatch_list; cmd; cmd = next) {
		llist_for_each_entry_safe(cmd, next,
					  fcc->dispatch_list, llnode) {
			cmd->ret = ret;
			next = cmd->next;
			complete(&cmd->wait);
		}
		bio_put(bio);
@@ -231,7 +227,7 @@ static int issue_flush_thread(void *data)
	}

	wait_event_interruptible(*q,
			kthread_should_stop() || fcc->issue_list);
		kthread_should_stop() || !llist_empty(&fcc->issue_list));
	goto repeat;
}

@@ -250,15 +246,8 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi)
		return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL);

	init_completion(&cmd.wait);
	cmd.next = NULL;

	spin_lock(&fcc->issue_lock);
	if (fcc->issue_list)
		fcc->issue_tail->next = &cmd;
	else
		fcc->issue_list = &cmd;
	fcc->issue_tail = &cmd;
	spin_unlock(&fcc->issue_lock);
	llist_add(&cmd.llnode, &fcc->issue_list);

	if (!fcc->dispatch_list)
		wake_up(&fcc->flush_wait_queue);
@@ -277,8 +266,8 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi)
	fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
	if (!fcc)
		return -ENOMEM;
	spin_lock_init(&fcc->issue_lock);
	init_waitqueue_head(&fcc->flush_wait_queue);
	init_llist_head(&fcc->issue_list);
	SM_I(sbi)->cmd_control_info = fcc;
	fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
				"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));