summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2017-04-26 17:39:54 +0800
committerJaegeuk Kim <jaegeuk@kernel.org>2017-05-08 16:31:07 -0700
commit7ec84ed608e4fe4b00189ed36363da553c092eaf (patch)
tree0c719af9952ae991305bca1a88cea8c1ca3c4e9c
parent5abcd71d0fd8a642d848a13de041e2112df21a23 (diff)
f2fs: don't hold cmd_lock during waiting discard command
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>
-rw-r--r--fs/f2fs/f2fs.h1
-rw-r--r--fs/f2fs/segment.c25
2 files changed, 21 insertions, 5 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 635bca168078..b20b3b29bc27 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -286,6 +286,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 */
};
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 9fcc2f9aa732..6a79d0b3b423 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -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);
@@ -1086,6 +1087,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);
}
@@ -1098,17 +1101,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 */