[JFFS2] Correct handling of JFFS2_FEATURE_RWCOMPAT_COPY nodes.
authorDavid Woodhouse <dwmw2@infradead.org>
Sat, 20 May 2006 23:02:06 +0000 (00:02 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Sat, 20 May 2006 23:02:06 +0000 (00:02 +0100)
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>
fs/jffs2/gc.c
fs/jffs2/nodelist.h
fs/jffs2/scan.c
fs/jffs2/summary.c

index 23587f8a221fffb29be42cd647fcaa8b1fc9623d..b0a5c407b47635e577fde206936cf1014ee71f70 100644 (file)
@@ -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)));
 
index bac4ec35bbd00f89f45286483fd6cb5f8d66098f..1f5d5b0100aa2f097bf8eed160ba80fa19f688a2 100644 (file)
@@ -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
index 3cbe9f029e01e93524aafa875e51a011cb704e01..06637050749d602c3de0d39a8aac0404a684771c 100644 (file)
@@ -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;
+                               }
                        }
                }
        }
index 95b5bf8f4a99b59cf92c52159de6ef4e363ae981..53a84b468cfe223a38f669a1e4168d600ecc43ed 100644 (file)
@@ -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 */
+                               }
                        }
                }