aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-10-13 06:31:23 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-10-13 06:31:23 -0400
commit2665ea842dc9f4c04bdb57f8b7c2023759ac8c85 (patch)
treeeb7fa11e07a8760d4ed819211d9fb936727c4c5f
parent85becc535b7f33be5aefdb8ecea9fac4998e4b6f (diff)
[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.c14
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)
122 struct jffs2_inode_cache *ic; 122 struct jffs2_inode_cache *ic;
123 struct jffs2_eraseblock *jeb; 123 struct jffs2_eraseblock *jeb;
124 struct jffs2_raw_node_ref *raw; 124 struct jffs2_raw_node_ref *raw;
125 uint32_t gcblock_dirty;
125 int ret = 0, inum, nlink; 126 int ret = 0, inum, nlink;
126 int xattr = 0; 127 int xattr = 0;
127 128
@@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
236 } 237 }
237 238
238 raw = jeb->gc_node; 239 raw = jeb->gc_node;
240 gcblock_dirty = jeb->dirty_size;
239 241
240 while(ref_obsolete(raw)) { 242 while(ref_obsolete(raw)) {
241 D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); 243 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)
282 } else { 284 } else {
283 ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); 285 ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
284 } 286 }
285 goto release_sem; 287 goto test_gcnode;
286 } 288 }
287#endif 289#endif
288 290
@@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
376 378
377 if (ret != -EBADFD) { 379 if (ret != -EBADFD) {
378 spin_unlock(&c->inocache_lock); 380 spin_unlock(&c->inocache_lock);
379 goto release_sem; 381 goto test_gcnode;
380 } 382 }
381 383
382 /* Fall through if it wanted us to, with inocache_lock held */ 384 /* 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)
407 409
408 jffs2_gc_release_inode(c, f); 410 jffs2_gc_release_inode(c, f);
409 411
412 test_gcnode:
413 if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) {
414 /* Eep. This really should never happen. GC is broken */
415 printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node));
416 ret = -ENOSPC;
417 } else if (ref_offset(jeb->gc_node) == 0x1c616bdc)
418 printk(KERN_ERR "Wheee. Correctly GC'd node at %08x\n", ref_offset(jeb->gc_node));
419
410 release_sem: 420 release_sem:
411 up(&c->alloc_sem); 421 up(&c->alloc_sem);
412 422