aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-10-06 15:12:58 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-10-06 15:12:58 -0400
commit8fb870df5a1f261294b833dd807bcba3bacface6 (patch)
tree2e6018f0256feca906797b248603202962302fa6 /fs/jffs2
parent49defc015ff58fda46a3afa3462dfdfa69bc8401 (diff)
[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@infradead.org>
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/build.c10
-rw-r--r--fs/jffs2/jffs2_fs_sb.h2
-rw-r--r--fs/jffs2/nodemgmt.c14
3 files changed, 24 insertions, 2 deletions
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 0ca2fff2617f..8c27c12816ba 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)
285 than actually making progress? */ 285 than actually making progress? */
286 c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; 286 c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
287 287
288 /* What number of 'very dirty' eraseblocks do we allow before we
289 trigger the GC thread even if we don't _need_ the space. When we
290 can't mark nodes obsolete on the medium, the old dirty nodes cause
291 performance problems because we have to inspect and discard them. */
292 c->vdirty_blocks_gctrigger = c->resv_blocks_gcmerge;
293 if (jffs2_can_mark_obsolete(c))
294 c->vdirty_blocks_gctrigger *= 10;
295
288 /* If there's less than this amount of dirty space, don't bother 296 /* If there's less than this amount of dirty space, don't bother
289 trying to GC to make more space. It'll be a fruitless task */ 297 trying to GC to make more space. It'll be a fruitless task */
290 c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); 298 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)
303 c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); 311 c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
304 dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", 312 dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
305 c->nospc_dirty_size); 313 c->nospc_dirty_size);
314 dbg_fsbuild("Very dirty blocks before GC triggered: %d\n",
315 c->vdirty_blocks_gctrigger);
306} 316}
307 317
308int jffs2_do_mount_fs(struct jffs2_sb_info *c) 318int 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 ae99cd7fd43b..3a2197f3c812 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -69,6 +69,8 @@ struct jffs2_sb_info {
69 uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ 69 uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */
70 uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ 70 uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */
71 uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ 71 uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */
72 /* Number of 'very dirty' blocks before we trigger immediate GC */
73 uint8_t vdirty_blocks_gctrigger;
72 74
73 uint32_t nospc_dirty_size; 75 uint32_t nospc_dirty_size;
74 76
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 5b49bff364b4..1b79534e9d48 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)
722{ 722{
723 int ret = 0; 723 int ret = 0;
724 uint32_t dirty; 724 uint32_t dirty;
725 int nr_very_dirty = 0;
726 struct jffs2_eraseblock *jeb;
725 727
726 if (c->unchecked_size) { 728 if (c->unchecked_size) {
727 D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", 729 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)
743 (dirty > c->nospc_dirty_size)) 745 (dirty > c->nospc_dirty_size))
744 ret = 1; 746 ret = 1;
745 747
746 D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", 748 list_for_each_entry(jeb, &c->very_dirty_list, list) {
747 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); 749 nr_very_dirty++;
750 if (nr_very_dirty == c->vdirty_blocks_gctrigger) {
751 ret = 1;
752 D1(break);
753 }
754 }
755
756 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",
757 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no"));
748 758
749 return ret; 759 return ret;
750} 760}