diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-10-13 06:31:23 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-10-13 06:31:23 -0400 |
commit | 2665ea842dc9f4c04bdb57f8b7c2023759ac8c85 (patch) | |
tree | eb7fa11e07a8760d4ed819211d9fb936727c4c5f /fs | |
parent | 85becc535b7f33be5aefdb8ecea9fac4998e4b6f (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>
Diffstat (limited to 'fs')
-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) | |||
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 | ||