[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>
This commit is contained in:
parent
85becc535b
commit
2665ea842d
|
@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||||
struct jffs2_inode_cache *ic;
|
struct jffs2_inode_cache *ic;
|
||||||
struct jffs2_eraseblock *jeb;
|
struct jffs2_eraseblock *jeb;
|
||||||
struct jffs2_raw_node_ref *raw;
|
struct jffs2_raw_node_ref *raw;
|
||||||
|
uint32_t gcblock_dirty;
|
||||||
int ret = 0, inum, nlink;
|
int ret = 0, inum, nlink;
|
||||||
int xattr = 0;
|
int xattr = 0;
|
||||||
|
|
||||||
|
@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
raw = jeb->gc_node;
|
raw = jeb->gc_node;
|
||||||
|
gcblock_dirty = jeb->dirty_size;
|
||||||
|
|
||||||
while(ref_obsolete(raw)) {
|
while(ref_obsolete(raw)) {
|
||||||
D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(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 {
|
} else {
|
||||||
ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
|
ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
|
||||||
}
|
}
|
||||||
goto release_sem;
|
goto test_gcnode;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||||
|
|
||||||
if (ret != -EBADFD) {
|
if (ret != -EBADFD) {
|
||||||
spin_unlock(&c->inocache_lock);
|
spin_unlock(&c->inocache_lock);
|
||||||
goto release_sem;
|
goto test_gcnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fall through if it wanted us to, with inocache_lock held */
|
/* 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);
|
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:
|
release_sem:
|
||||||
up(&c->alloc_sem);
|
up(&c->alloc_sem);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue