Commit 721bd4d5c3f957f98157b6dcac9c4a4dd828e3ff

Authored by Gu Zheng
Committed by Jaegeuk Kim
1 parent 184a5cd2ce

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: Gu Zheng <guz.fnst@cn.fujitsu.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

Showing 2 changed files with 12 additions and 25 deletions Side-by-side Diff

... ... @@ -347,18 +347,16 @@
347 347 };
348 348  
349 349 struct flush_cmd {
350   - struct flush_cmd *next;
351 350 struct completion wait;
  351 + struct llist_node llnode;
352 352 int ret;
353 353 };
354 354  
355 355 struct flush_cmd_control {
356 356 struct task_struct *f2fs_issue_flush; /* flush thread */
357 357 wait_queue_head_t flush_wait_queue; /* waiting queue for wake-up */
358   - struct flush_cmd *issue_list; /* list for command issue */
359   - struct flush_cmd *dispatch_list; /* list for command dispatch */
360   - spinlock_t issue_lock; /* for issue list lock */
361   - struct flush_cmd *issue_tail; /* list tail of issue list */
  358 + struct llist_head issue_list; /* list for command issue */
  359 + struct llist_node *dispatch_list; /* list for command dispatch */
362 360 };
363 361  
364 362 struct f2fs_sm_info {
... ... @@ -206,24 +206,20 @@
206 206 if (kthread_should_stop())
207 207 return 0;
208 208  
209   - spin_lock(&fcc->issue_lock);
210   - if (fcc->issue_list) {
211   - fcc->dispatch_list = fcc->issue_list;
212   - fcc->issue_list = fcc->issue_tail = NULL;
213   - }
214   - spin_unlock(&fcc->issue_lock);
215   -
216   - if (fcc->dispatch_list) {
  209 + if (!llist_empty(&fcc->issue_list)) {
217 210 struct bio *bio = bio_alloc(GFP_NOIO, 0);
218 211 struct flush_cmd *cmd, *next;
219 212 int ret;
220 213  
  214 + fcc->dispatch_list = llist_del_all(&fcc->issue_list);
  215 + fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list);
  216 +
221 217 bio->bi_bdev = sbi->sb->s_bdev;
222 218 ret = submit_bio_wait(WRITE_FLUSH, bio);
223 219  
224   - for (cmd = fcc->dispatch_list; cmd; cmd = next) {
  220 + llist_for_each_entry_safe(cmd, next,
  221 + fcc->dispatch_list, llnode) {
225 222 cmd->ret = ret;
226   - next = cmd->next;
227 223 complete(&cmd->wait);
228 224 }
229 225 bio_put(bio);
... ... @@ -231,7 +227,7 @@
231 227 }
232 228  
233 229 wait_event_interruptible(*q,
234   - kthread_should_stop() || fcc->issue_list);
  230 + kthread_should_stop() || !llist_empty(&fcc->issue_list));
235 231 goto repeat;
236 232 }
237 233  
238 234  
... ... @@ -250,15 +246,8 @@
250 246 return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL);
251 247  
252 248 init_completion(&cmd.wait);
253   - cmd.next = NULL;
254 249  
255   - spin_lock(&fcc->issue_lock);
256   - if (fcc->issue_list)
257   - fcc->issue_tail->next = &cmd;
258   - else
259   - fcc->issue_list = &cmd;
260   - fcc->issue_tail = &cmd;
261   - spin_unlock(&fcc->issue_lock);
  250 + llist_add(&cmd.llnode, &fcc->issue_list);
262 251  
263 252 if (!fcc->dispatch_list)
264 253 wake_up(&fcc->flush_wait_queue);
265 254  
... ... @@ -277,8 +266,8 @@
277 266 fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
278 267 if (!fcc)
279 268 return -ENOMEM;
280   - spin_lock_init(&fcc->issue_lock);
281 269 init_waitqueue_head(&fcc->flush_wait_queue);
  270 + init_llist_head(&fcc->issue_list);
282 271 SM_I(sbi)->cmd_control_info = fcc;
283 272 fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
284 273 "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));