[JFFS2] Correct handling of JFFS2_FEATURE_RWCOMPAT_COPY nodes.
We should preserve these when we come to garbage collect them, not let them get erased. Use jffs2_garbage_collect_pristine() for this, and make sure the summary code copes -- just refrain from writing a summary for any block which contains a node we don't understand. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
This commit is contained in:
parent
fb9fbbcc93
commit
6171586a7a
|
@ -256,10 +256,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||||
|
|
||||||
if (!raw->next_in_ino) {
|
if (!raw->next_in_ino) {
|
||||||
/* Inode-less node. Clean marker, snapshot or something like that */
|
/* Inode-less node. Clean marker, snapshot or something like that */
|
||||||
/* FIXME: If it's something that needs to be copied, including something
|
|
||||||
we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
|
|
||||||
spin_unlock(&c->erase_completion_lock);
|
spin_unlock(&c->erase_completion_lock);
|
||||||
jffs2_mark_node_obsolete(c, raw);
|
if (ref_flags(raw) == REF_PRISTINE) {
|
||||||
|
/* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */
|
||||||
|
jffs2_garbage_collect_pristine(c, NULL, raw);
|
||||||
|
} else {
|
||||||
|
/* Just mark it obsolete */
|
||||||
|
jffs2_mark_node_obsolete(c, raw);
|
||||||
|
}
|
||||||
up(&c->alloc_sem);
|
up(&c->alloc_sem);
|
||||||
goto eraseit_lock;
|
goto eraseit_lock;
|
||||||
}
|
}
|
||||||
|
@ -533,15 +537,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
||||||
|
|
||||||
D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
|
D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
|
||||||
|
|
||||||
rawlen = ref_totlen(c, c->gcblock, raw);
|
alloclen = rawlen = ref_totlen(c, c->gcblock, raw);
|
||||||
|
|
||||||
/* Ask for a small amount of space (or the totlen if smaller) because we
|
/* Ask for a small amount of space (or the totlen if smaller) because we
|
||||||
don't want to force wastage of the end of a block if splitting would
|
don't want to force wastage of the end of a block if splitting would
|
||||||
work. */
|
work. */
|
||||||
ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
|
if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
|
||||||
JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
|
alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN;
|
||||||
/* this is not the exact summary size of it,
|
|
||||||
it is only an upper estimation */
|
ret = jffs2_reserve_space_gc(c, alloclen, &phys_ofs, &alloclen, rawlen);
|
||||||
|
/* 'rawlen' is not the exact summary size; it is only an upper estimation */
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -605,9 +610,12 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
|
/* If it's inode-less, we don't _know_ what it is. Just copy it intact */
|
||||||
ref_offset(raw), je16_to_cpu(node->u.nodetype));
|
if (ic) {
|
||||||
goto bail;
|
printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
|
||||||
|
ref_offset(raw), je16_to_cpu(node->u.nodetype));
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nraw = jffs2_alloc_raw_node_ref();
|
nraw = jffs2_alloc_raw_node_ref();
|
||||||
|
@ -674,15 +682,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
||||||
nraw->flash_offset |= REF_PRISTINE;
|
nraw->flash_offset |= REF_PRISTINE;
|
||||||
jffs2_add_physical_node_ref(c, nraw);
|
jffs2_add_physical_node_ref(c, nraw);
|
||||||
|
|
||||||
/* Link into per-inode list. This is safe because of the ic
|
if (ic) {
|
||||||
state being INO_STATE_GC. Note that if we're doing this
|
/* Link into per-inode list. This is safe because of the ic
|
||||||
for an inode which is in-core, the 'nraw' pointer is then
|
state being INO_STATE_GC. Note that if we're doing this
|
||||||
going to be fetched from ic->nodes by our caller. */
|
for an inode which is in-core, the 'nraw' pointer is then
|
||||||
spin_lock(&c->erase_completion_lock);
|
going to be fetched from ic->nodes by our caller. */
|
||||||
nraw->next_in_ino = ic->nodes;
|
spin_lock(&c->erase_completion_lock);
|
||||||
ic->nodes = nraw;
|
nraw->next_in_ino = ic->nodes;
|
||||||
spin_unlock(&c->erase_completion_lock);
|
ic->nodes = nraw;
|
||||||
|
spin_unlock(&c->erase_completion_lock);
|
||||||
|
}
|
||||||
jffs2_mark_node_obsolete(c, raw);
|
jffs2_mark_node_obsolete(c, raw);
|
||||||
D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
|
D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,11 @@ struct jffs2_raw_node_ref
|
||||||
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
|
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
|
||||||
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
|
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
|
||||||
|
|
||||||
|
/* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates
|
||||||
|
it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get
|
||||||
|
copied. If you need to do anything different to GC inode-less nodes, then
|
||||||
|
you need to modify gc.c accordingly. */
|
||||||
|
|
||||||
/* For each inode in the filesystem, we need to keep a record of
|
/* For each inode in the filesystem, we need to keep a record of
|
||||||
nlink, because it would be a PITA to scan the whole directory tree
|
nlink, because it would be a PITA to scan the whole directory tree
|
||||||
at read_inode() time to calculate it, and to keep sufficient information
|
at read_inode() time to calculate it, and to keep sufficient information
|
||||||
|
|
|
@ -851,11 +851,22 @@ scan_more:
|
||||||
ofs += PAD(je32_to_cpu(node->totlen));
|
ofs += PAD(je32_to_cpu(node->totlen));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JFFS2_FEATURE_RWCOMPAT_COPY:
|
case JFFS2_FEATURE_RWCOMPAT_COPY: {
|
||||||
|
struct jffs2_raw_node_ref *ref;
|
||||||
D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
|
D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
|
||||||
USED_SPACE(PAD(je32_to_cpu(node->totlen)));
|
|
||||||
|
ref = jffs2_alloc_raw_node_ref();
|
||||||
|
if (!ref)
|
||||||
|
return -ENOMEM;
|
||||||
|
ref->flash_offset = ofs | REF_PRISTINE;
|
||||||
|
ref->next_in_ino = 0;
|
||||||
|
jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)));
|
||||||
|
|
||||||
|
/* We can't summarise nodes we don't grok */
|
||||||
|
jffs2_sum_disable_collecting(s);
|
||||||
ofs += PAD(je32_to_cpu(node->totlen));
|
ofs += PAD(je32_to_cpu(node->totlen));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -760,7 +760,14 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
default : {
|
default : {
|
||||||
BUG(); /* unknown node in summary information */
|
if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK)
|
||||||
|
== JFFS2_FEATURE_RWCOMPAT_COPY) {
|
||||||
|
dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n",
|
||||||
|
je16_to_cpu(temp->u.nodetype));
|
||||||
|
jffs2_sum_disable_collecting(c->summary);
|
||||||
|
} else {
|
||||||
|
BUG(); /* unknown node in summary information */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue