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/jffs2 | |
| 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/jffs2')
| -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 eded819df2..95be264fe9 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 | ||
