From 6171586a7ae5198988774e8480631e8d15f65dfe Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 00:02:06 +0100 Subject: [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 --- fs/jffs2/gc.c | 49 +++++++++++++++++++++++++++++-------------------- fs/jffs2/nodelist.h | 5 +++++ fs/jffs2/scan.c | 15 +++++++++++++-- fs/jffs2/summary.c | 9 ++++++++- 4 files changed, 55 insertions(+), 23 deletions(-) (limited to 'fs/jffs2') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 23587f8a221f..b0a5c407b476 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -256,10 +256,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (!raw->next_in_ino) { /* 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); - 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); 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))); - 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 don't want to force wastage of the end of a block if splitting would work. */ - ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + - JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen); - /* this is not the exact summary size of it, - it is only an upper estimation */ + if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) + alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN; + + 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) return ret; @@ -605,9 +610,12 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, } break; default: - 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; + /* If it's inode-less, we don't _know_ what it is. Just copy it intact */ + if (ic) { + 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(); @@ -674,15 +682,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, nraw->flash_offset |= REF_PRISTINE; jffs2_add_physical_node_ref(c, nraw); - /* Link into per-inode list. This is safe because of the ic - state being INO_STATE_GC. Note that if we're doing this - for an inode which is in-core, the 'nraw' pointer is then - going to be fetched from ic->nodes by our caller. */ - spin_lock(&c->erase_completion_lock); - nraw->next_in_ino = ic->nodes; - ic->nodes = nraw; - spin_unlock(&c->erase_completion_lock); - + if (ic) { + /* Link into per-inode list. This is safe because of the ic + state being INO_STATE_GC. Note that if we're doing this + for an inode which is in-core, the 'nraw' pointer is then + going to be fetched from ic->nodes by our caller. */ + spin_lock(&c->erase_completion_lock); + nraw->next_in_ino = ic->nodes; + ic->nodes = nraw; + spin_unlock(&c->erase_completion_lock); + } jffs2_mark_node_obsolete(c, raw); D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bac4ec35bbd0..1f5d5b0100aa 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -97,6 +97,11 @@ struct jffs2_raw_node_ref #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) +/* 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 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 diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3cbe9f029e01..06637050749d 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -851,11 +851,22 @@ scan_more: ofs += PAD(je32_to_cpu(node->totlen)); 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)); - 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)); break; + } } } } diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 95b5bf8f4a99..53a84b468cfe 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -760,7 +760,14 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock } #endif 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 */ + } } } -- cgit v1.2.3