diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-10-13 14:31:23 +0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-10-13 14:31:23 +0400 |
commit | 2665ea842dc9f4c04bdb57f8b7c2023759ac8c85 (patch) | |
tree | eb7fa11e07a8760d4ed819211d9fb936727c4c5f | |
parent | 85becc535b7f33be5aefdb8ecea9fac4998e4b6f (diff) | |
download | linux-2665ea842dc9f4c04bdb57f8b7c2023759ac8c85.tar.xz |
[JFFS2] Check whether garbage-collection actually obsoleted its victim.
In OLPC trac #4184 we found a case where a corrupted node didn't
actually get obsoleted when we tried to garbage-collect it. So we wrote
out many million copies of it, in repeated attempts to obsolete it,
until the flash became full. Don't Do That.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r-- | fs/jffs2/gc.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index eded819df235..95be264fe9b6 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) struct jffs2_inode_cache *ic; struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; + uint32_t gcblock_dirty; int ret = 0, inum, nlink; int xattr = 0; @@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } raw = jeb->gc_node; + gcblock_dirty = jeb->dirty_size; while(ref_obsolete(raw)) { D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); @@ -282,7 +284,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } else { ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); } - goto release_sem; + goto test_gcnode; } #endif @@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (ret != -EBADFD) { spin_unlock(&c->inocache_lock); - goto release_sem; + goto test_gcnode; } /* Fall through if it wanted us to, with inocache_lock held */ @@ -407,6 +409,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) jffs2_gc_release_inode(c, f); + test_gcnode: + if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { + /* Eep. This really should never happen. GC is broken */ + printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node)); + ret = -ENOSPC; + } else if (ref_offset(jeb->gc_node) == 0x1c616bdc) + printk(KERN_ERR "Wheee. Correctly GC'd node at %08x\n", ref_offset(jeb->gc_node)); + release_sem: up(&c->alloc_sem); |