[JFFS2] Trigger garbage collection when very_dirty_list size becomes excessive

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Sat Oct 6 15:59:01 EDT 2007


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=8fb870df5a1f261294b833dd807bcba3bacface6
Commit:     8fb870df5a1f261294b833dd807bcba3bacface6
Parent:     49defc015ff58fda46a3afa3462dfdfa69bc8401
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sat Oct 6 15:12:58 2007 -0400
Committer:  David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sat Oct 6 15:12:58 2007 -0400

    [JFFS2] Trigger garbage collection when very_dirty_list size becomes excessive
    
    With huge amounts of free space, we weren't bothering to GC for while a
    while, and pathological numbers of obsolete nodes were accumulating,
    seriously affecting performance on NAND flash (OLPC trac #3978)
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/build.c       |   10 ++++++++++
 fs/jffs2/jffs2_fs_sb.h |    2 ++
 fs/jffs2/nodemgmt.c    |   14 ++++++++++++--
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 0ca2fff..8c27c12 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -285,6 +285,14 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
 	   than actually making progress? */
 	c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
 
+	/* What number of 'very dirty' eraseblocks do we allow before we
+	   trigger the GC thread even if we don't _need_ the space. When we
+	   can't mark nodes obsolete on the medium, the old dirty nodes cause
+	   performance problems because we have to inspect and discard them. */
+	c->vdirty_blocks_gctrigger = c->resv_blocks_gcmerge;
+	if (jffs2_can_mark_obsolete(c))
+		c->vdirty_blocks_gctrigger *= 10;
+
 	/* If there's less than this amount of dirty space, don't bother
 	   trying to GC to make more space. It'll be a fruitless task */
 	c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
@@ -303,6 +311,8 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
 		  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
 	dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
 		  c->nospc_dirty_size);
+	dbg_fsbuild("Very dirty blocks before GC triggered: %d\n",
+		  c->vdirty_blocks_gctrigger);
 }
 
 int jffs2_do_mount_fs(struct jffs2_sb_info *c)
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index ae99cd7..3a2197f 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -69,6 +69,8 @@ struct jffs2_sb_info {
 	uint8_t resv_blocks_gctrigger;	/* ... wake up the GC thread */
 	uint8_t resv_blocks_gcbad;	/* ... pick a block from the bad_list to GC */
 	uint8_t resv_blocks_gcmerge;	/* ... merge pages when garbage collecting */
+	/* Number of 'very dirty' blocks before we trigger immediate GC */
+	uint8_t vdirty_blocks_gctrigger;
 
 	uint32_t nospc_dirty_size;
 
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 5b49bff..1b79534 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -722,6 +722,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
 {
 	int ret = 0;
 	uint32_t dirty;
+	int nr_very_dirty = 0;
+	struct jffs2_eraseblock *jeb;
 
 	if (c->unchecked_size) {
 		D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
@@ -743,8 +745,16 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
 			(dirty > c->nospc_dirty_size))
 		ret = 1;
 
-	D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
-		  c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
+	list_for_each_entry(jeb, &c->very_dirty_list, list) {
+		nr_very_dirty++;
+		if (nr_very_dirty == c->vdirty_blocks_gctrigger) {
+			ret = 1;
+			D1(break);
+		}
+	}
+
+	D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n",
+		  c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no"));
 
 	return ret;
 }



More information about the linux-mtd-cvs mailing list