]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
f2fs: don't hold cmd_lock during waiting discard command
authorChao Yu <yuchao0@huawei.com>
Wed, 26 Apr 2017 09:39:54 +0000 (17:39 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 3 May 2017 04:19:50 +0000 (21:19 -0700)
Previously, with protection of cmd_lock, we will wait for end io of
discard command which potentially may lead long latency, making worse
concurrency.

So, in this patch, we try to add reference into discard entry to prevent
the entry being released by other thread, then we can avoid holding
global cmd_lock during waiting discard to finish.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/f2fs.h
fs/f2fs/segment.c

index 9228a36ded4112139896fc39828169a2f998bbfc..5759671fc948bf180b160c8ccac5bff19e36b4b6 100644 (file)
@@ -219,6 +219,7 @@ struct discard_cmd {
        struct list_head list;          /* command list */
        struct completion wait;         /* compleation */
        struct block_device *bdev;      /* bdev */
+       unsigned short ref;             /* reference count */
        int state;                      /* state */
        int error;                      /* bio error */
 };
index b0babb73a0769eea65dcd25d6738a8a071faf08b..656e1515ff56a81e1e5419e00932505a0a3d0244 100644 (file)
@@ -688,6 +688,7 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
        dc->lstart = lstart;
        dc->start = start;
        dc->len = len;
+       dc->ref = 0;
        dc->state = D_PREP;
        dc->error = 0;
        init_completion(&dc->wait);
@@ -1007,6 +1008,8 @@ static void __wait_discard_cmd(struct f2fs_sb_info *sbi, bool wait_cond)
        mutex_lock(&dcc->cmd_lock);
        list_for_each_entry_safe(dc, tmp, wait_list, list) {
                if (!wait_cond || dc->state == D_DONE) {
+                       if (dc->ref)
+                               continue;
                        wait_for_completion_io(&dc->wait);
                        __remove_discard_cmd(sbi, dc);
                }
@@ -1019,17 +1022,29 @@ void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
 {
        struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
        struct discard_cmd *dc;
+       bool need_wait = false;
 
        mutex_lock(&dcc->cmd_lock);
-
        dc = (struct discard_cmd *)__lookup_rb_tree(&dcc->root, NULL, blkaddr);
        if (dc) {
-               if (dc->state != D_PREP)
-                       wait_for_completion_io(&dc->wait);
-               __punch_discard_cmd(sbi, dc, blkaddr);
+               if (dc->state == D_PREP) {
+                       __punch_discard_cmd(sbi, dc, blkaddr);
+               } else {
+                       dc->ref++;
+                       need_wait = true;
+               }
        }
-
        mutex_unlock(&dcc->cmd_lock);
+
+       if (need_wait) {
+               wait_for_completion_io(&dc->wait);
+               mutex_lock(&dcc->cmd_lock);
+               f2fs_bug_on(sbi, dc->state != D_DONE);
+               dc->ref--;
+               if (!dc->ref)
+                       __remove_discard_cmd(sbi, dc);
+               mutex_unlock(&dcc->cmd_lock);
+       }
 }
 
 /* This comes from f2fs_put_super */