All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yunlong Song <yunlong.song@huawei.com>
To: <jaegeuk@kernel.org>, <chao@kernel.org>, <yuchao0@huawei.com>,
	<sylinux@163.com>, <yunlong.song@huawei.com>
Cc: <miaoxie@huawei.com>, <bintian.wang@huawei.com>,
	<linux-fsdevel@vger.kernel.org>,
	<linux-f2fs-devel@lists.sourceforge.net>,
	<linux-kernel@vger.kernel.org>
Subject: [PATCH] f2fs: let __get_victim successfully get a segno in corner case
Date: Fri, 14 Jul 2017 19:57:12 +0800	[thread overview]
Message-ID: <1500033432-57620-1-git-send-email-yunlong.song@huawei.com> (raw)

Suppose that the valid blocks of each section are all over sbi->fggc_threshold,
and even has_not_enough_free_secs is true, f2fs_gc cannot do its job since the
no_fggc_candidate always returns true. As a result, the reserved segments can be
used up, and finally there is no free segment at all, and get_new_segment cannot
get a free segment, filesystem will trap into a wrong status.

To fix this, we record the segno which has a rough minimum cost and return it to
__get_victim to continue f2fs_gc's job.

Signed-off-by: Yunlong Song <yunlong.song@huawei.com>
---
 fs/f2fs/gc.c      | 19 ++++++++++++++-----
 fs/f2fs/segment.h | 17 ++++++++++++++---
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index fa3d2e2..965e783 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -178,6 +178,8 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
 		p->offset = 0;
 	else
 		p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
+
+	p->min_cost_r = UINT_MAX;
 }
 
 static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
@@ -194,7 +196,7 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
 		return 0;
 }
 
-static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
+static unsigned int check_bg_victims(struct f2fs_sb_info *sbi, struct victim_sel_policy *p)
 {
 	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
 	unsigned int secno;
@@ -208,11 +210,12 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
 		if (sec_usage_check(sbi, secno))
 			continue;
 
-		if (no_fggc_candidate(sbi, secno))
+		p->cur_segno_r = GET_SEG_FROM_SEC(sbi, secno);
+		if (no_fggc_candidate(sbi, secno, p))
 			continue;
 
 		clear_bit(secno, dirty_i->victim_secmap);
-		return GET_SEG_FROM_SEC(sbi, secno);
+		return p->cur_segno_r;
 	}
 	return NULL_SEGNO;
 }
@@ -332,7 +335,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 
 	last_victim = sm->last_victim[p.gc_mode];
 	if (p.alloc_mode == LFS && gc_type == FG_GC) {
-		p.min_segno = check_bg_victims(sbi);
+		p.min_segno = check_bg_victims(sbi, &p);
 		if (p.min_segno != NULL_SEGNO)
 			goto got_it;
 	}
@@ -369,8 +372,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 			goto next;
 		if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
 			goto next;
+		p.cur_segno_r = segno;
 		if (gc_type == FG_GC && p.alloc_mode == LFS &&
-					no_fggc_candidate(sbi, secno))
+					no_fggc_candidate(sbi, secno, &p))
 			goto next;
 
 		cost = get_gc_cost(sbi, segno, &p);
@@ -403,6 +407,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 		trace_f2fs_get_victim(sbi->sb, type, gc_type, &p,
 				sbi->cur_victim_sec,
 				prefree_segments(sbi), free_segments(sbi));
+	} else if (has_not_enough_free_secs(sbi, 0, 0)) {
+		p.min_segno = p.min_segno_r;
+		if (p.alloc_mode == LFS && gc_type == FG_GC)
+			clear_bit(GET_SEC_FROM_SEG(sbi, p.min_segno), dirty_i->victim_secmap);
+		goto got_it;
 	}
 out:
 	mutex_unlock(&dirty_i->seglist_lock);
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 6b871b4..7d2d0f3 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -169,6 +169,9 @@ struct victim_sel_policy {
 	unsigned int ofs_unit;		/* bitmap search unit */
 	unsigned int min_cost;		/* minimum cost */
 	unsigned int min_segno;		/* segment # having min. cost */
+	unsigned int min_cost_r;		/* rough minimum cost */
+	unsigned int min_segno_r;		/* segment # having rough min. cost */
+	unsigned int cur_segno_r;		/* segment # rough process is handling */
 };
 
 struct seg_entry {
@@ -743,11 +746,19 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
 }
 
 static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi,
-						unsigned int secno)
+						unsigned int secno, struct victim_sel_policy *p)
 {
-	if (get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true) >=
-						sbi->fggc_threshold)
+	unsigned int cur_cost;
+
+	cur_cost = get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true);
+	if (cur_cost >= sbi->fggc_threshold) {
+		if (p->min_cost_r > cur_cost) {
+			p->min_cost_r = cur_cost;
+			p->min_segno_r = p->cur_segno_r;
+		}
 		return true;
+	}
+
 	return false;
 }
 
-- 
1.8.5.2

WARNING: multiple messages have this Message-ID (diff)
From: Yunlong Song <yunlong.song@huawei.com>
To: jaegeuk@kernel.org, chao@kernel.org, yuchao0@huawei.com,
	sylinux@163.com, yunlong.song@huawei.com
Cc: miaoxie@huawei.com, bintian.wang@huawei.com,
	linux-fsdevel@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org
Subject: [PATCH] f2fs: let __get_victim successfully get a segno in corner case
Date: Fri, 14 Jul 2017 19:57:12 +0800	[thread overview]
Message-ID: <1500033432-57620-1-git-send-email-yunlong.song@huawei.com> (raw)

Suppose that the valid blocks of each section are all over sbi->fggc_threshold,
and even has_not_enough_free_secs is true, f2fs_gc cannot do its job since the
no_fggc_candidate always returns true. As a result, the reserved segments can be
used up, and finally there is no free segment at all, and get_new_segment cannot
get a free segment, filesystem will trap into a wrong status.

To fix this, we record the segno which has a rough minimum cost and return it to
__get_victim to continue f2fs_gc's job.

Signed-off-by: Yunlong Song <yunlong.song@huawei.com>
---
 fs/f2fs/gc.c      | 19 ++++++++++++++-----
 fs/f2fs/segment.h | 17 ++++++++++++++---
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index fa3d2e2..965e783 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -178,6 +178,8 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
 		p->offset = 0;
 	else
 		p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
+
+	p->min_cost_r = UINT_MAX;
 }
 
 static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
@@ -194,7 +196,7 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
 		return 0;
 }
 
-static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
+static unsigned int check_bg_victims(struct f2fs_sb_info *sbi, struct victim_sel_policy *p)
 {
 	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
 	unsigned int secno;
@@ -208,11 +210,12 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
 		if (sec_usage_check(sbi, secno))
 			continue;
 
-		if (no_fggc_candidate(sbi, secno))
+		p->cur_segno_r = GET_SEG_FROM_SEC(sbi, secno);
+		if (no_fggc_candidate(sbi, secno, p))
 			continue;
 
 		clear_bit(secno, dirty_i->victim_secmap);
-		return GET_SEG_FROM_SEC(sbi, secno);
+		return p->cur_segno_r;
 	}
 	return NULL_SEGNO;
 }
@@ -332,7 +335,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 
 	last_victim = sm->last_victim[p.gc_mode];
 	if (p.alloc_mode == LFS && gc_type == FG_GC) {
-		p.min_segno = check_bg_victims(sbi);
+		p.min_segno = check_bg_victims(sbi, &p);
 		if (p.min_segno != NULL_SEGNO)
 			goto got_it;
 	}
@@ -369,8 +372,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 			goto next;
 		if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
 			goto next;
+		p.cur_segno_r = segno;
 		if (gc_type == FG_GC && p.alloc_mode == LFS &&
-					no_fggc_candidate(sbi, secno))
+					no_fggc_candidate(sbi, secno, &p))
 			goto next;
 
 		cost = get_gc_cost(sbi, segno, &p);
@@ -403,6 +407,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 		trace_f2fs_get_victim(sbi->sb, type, gc_type, &p,
 				sbi->cur_victim_sec,
 				prefree_segments(sbi), free_segments(sbi));
+	} else if (has_not_enough_free_secs(sbi, 0, 0)) {
+		p.min_segno = p.min_segno_r;
+		if (p.alloc_mode == LFS && gc_type == FG_GC)
+			clear_bit(GET_SEC_FROM_SEG(sbi, p.min_segno), dirty_i->victim_secmap);
+		goto got_it;
 	}
 out:
 	mutex_unlock(&dirty_i->seglist_lock);
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 6b871b4..7d2d0f3 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -169,6 +169,9 @@ struct victim_sel_policy {
 	unsigned int ofs_unit;		/* bitmap search unit */
 	unsigned int min_cost;		/* minimum cost */
 	unsigned int min_segno;		/* segment # having min. cost */
+	unsigned int min_cost_r;		/* rough minimum cost */
+	unsigned int min_segno_r;		/* segment # having rough min. cost */
+	unsigned int cur_segno_r;		/* segment # rough process is handling */
 };
 
 struct seg_entry {
@@ -743,11 +746,19 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
 }
 
 static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi,
-						unsigned int secno)
+						unsigned int secno, struct victim_sel_policy *p)
 {
-	if (get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true) >=
-						sbi->fggc_threshold)
+	unsigned int cur_cost;
+
+	cur_cost = get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true);
+	if (cur_cost >= sbi->fggc_threshold) {
+		if (p->min_cost_r > cur_cost) {
+			p->min_cost_r = cur_cost;
+			p->min_segno_r = p->cur_segno_r;
+		}
 		return true;
+	}
+
 	return false;
 }
 
-- 
1.8.5.2

             reply	other threads:[~2017-07-14 11:58 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-14 11:57 Yunlong Song [this message]
2017-07-14 11:57 ` [PATCH] f2fs: let __get_victim successfully get a segno in corner case Yunlong Song
2017-07-16  1:09 ` Jaegeuk Kim
2017-07-17  1:51   ` Yunlong Song
2017-07-17  1:51     ` Yunlong Song
     [not found]   ` <3b3c1eba.b25.15d495786fe.Coremail.sylinux@163.com>
2017-07-17 16:56     ` Jaegeuk Kim
2017-07-20 12:27       ` Yunlong Song
2017-07-20 12:27         ` Yunlong Song
2017-07-21 21:07         ` Jaegeuk Kim
2017-07-24  9:18           ` Yunlong Song
2017-07-24  9:18             ` Yunlong Song
2017-07-25 18:55 ` Jaegeuk Kim
2017-07-27  2:56   ` Yunlong Song
2017-07-27  2:56     ` Yunlong Song

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1500033432-57620-1-git-send-email-yunlong.song@huawei.com \
    --to=yunlong.song@huawei.com \
    --cc=bintian.wang@huawei.com \
    --cc=chao@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=miaoxie@huawei.com \
    --cc=sylinux@163.com \
    --cc=yuchao0@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.