[JFFS2] Check whether garbage-collection actually obsoleted its victim.
authorDavid Woodhouse <dwmw2@infradead.org>
Sat, 13 Oct 2007 10:31:23 +0000 (11:31 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Sat, 13 Oct 2007 10:31:23 +0000 (11:31 +0100)
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>
fs/jffs2/gc.c

index eded819df235863fe55684c2d63ce8813d5ce9e0..95be264fe9b604961fc0062e891eea5ab6b85ed6 100644 (file)
@@ -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);