Skip to content

Commit

Permalink
[JFFS2] Trigger garbage collection when very_dirty_list size becomes …
Browse files Browse the repository at this point in the history
…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 <[email protected]>
  • Loading branch information
dwmw2 committed Oct 6, 2007
1 parent 49defc0 commit 8fb870d
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
10 changes: 10 additions & 0 deletions fs/jffs2/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions fs/jffs2/jffs2_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
14 changes: 12 additions & 2 deletions fs/jffs2/nodemgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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;
}

0 comments on commit 8fb870d

Please sign in to comment.