JFFS2: add UBI support
[safe/jmp/linux-2.6] / fs / jffs2 / scan.c
index 6fce703..7fb45bd 100644 (file)
@@ -67,8 +67,11 @@ static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
 
 static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
-       int ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size);
-       if (ret)
+       int ret;
+
+       if ((ret = jffs2_prealloc_raw_node_refs(c, jeb, 1)))
+               return ret;
+       if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size)))
                return ret;
        /* Turned wasted size into dirty, since we apparently 
           think it's recoverable now. */
@@ -125,17 +128,19 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        }
 
        if (jffs2_sum_active()) {
-               s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+               s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
                if (!s) {
+                       kfree(flashbuf);
                        JFFS2_WARNING("Can't allocate memory for summary\n");
                        return -ENOMEM;
                }
-               memset(s, 0, sizeof(struct jffs2_summary));
        }
 
        for (i=0; i<c->nr_blocks; i++) {
                struct jffs2_eraseblock *jeb = &c->blocks[i];
 
+               cond_resched();
+
                /* reset summary info for next eraseblock scan */
                jffs2_sum_reset_collected(s);
 
@@ -244,11 +249,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
 
                D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n",
                          skip));
-               c->nextblock->wasted_size += skip;
-               c->wasted_size += skip;
-
-               c->nextblock->free_size -= skip;
-               c->free_size -= skip;
+               jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
+               jffs2_scan_dirty_space(c, c->nextblock, skip);
        }
 #endif
        if (c->nr_erasing_blocks) {
@@ -274,8 +276,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        return ret;
 }
 
-int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
-                               uint32_t ofs, uint32_t len)
+static int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
+                              uint32_t ofs, uint32_t len)
 {
        int ret;
        size_t retlen;
@@ -295,7 +297,7 @@ int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
 int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
        if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
-               && (!jeb->first_node || !jeb->first_node->next_phys) )
+           && (!jeb->first_node || !ref_next(jeb->first_node)) )
                return BLK_STATE_CLEANMARKER;
 
        /* move blocks with max 4 byte dirty space to cleanlist */
@@ -317,21 +319,23 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                                 struct jffs2_summary *s)
 {
        struct jffs2_xattr_datum *xd;
-       struct jffs2_raw_node_ref *raw;
-       uint32_t totlen, crc;
+       uint32_t xid, version, totlen, crc;
        int err;
 
        crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
        if (crc != je32_to_cpu(rx->node_crc)) {
-               if (je32_to_cpu(rx->node_crc) != 0xffffffff)
-                       JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                     ofs, je32_to_cpu(rx->node_crc), crc);
+               JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                             ofs, je32_to_cpu(rx->node_crc), crc);
                if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen))))
                        return err;
                return 0;
        }
 
-       totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
+       xid = je32_to_cpu(rx->xid);
+       version = je32_to_cpu(rx->version);
+
+       totlen = PAD(sizeof(struct jffs2_raw_xattr)
+                       + rx->name_len + 1 + je16_to_cpu(rx->value_len));
        if (totlen != je32_to_cpu(rx->totlen)) {
                JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
                              ofs, je32_to_cpu(rx->totlen), totlen);
@@ -340,30 +344,24 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                return 0;
        }
 
-       raw =  jffs2_alloc_raw_node_ref();
-       if (!raw)
-               return -ENOMEM;
-
-       xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
-       if (IS_ERR(xd)) {
-               jffs2_free_raw_node_ref(raw);
-               if (PTR_ERR(xd) == -EEXIST) {
-                       if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen)))))
-                               return err;
-                       return 0;
-               }
+       xd = jffs2_setup_xattr_datum(c, xid, version);
+       if (IS_ERR(xd))
                return PTR_ERR(xd);
-       }
-       xd->xprefix = rx->xprefix;
-       xd->name_len = rx->name_len;
-       xd->value_len = je16_to_cpu(rx->value_len);
-       xd->data_crc = je32_to_cpu(rx->data_crc);
-       xd->node = raw;
 
-       raw->flash_offset = ofs | REF_PRISTINE;
+       if (xd->version > version) {
+               struct jffs2_raw_node_ref *raw
+                       = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
+               raw->next_in_ino = xd->node->next_in_ino;
+               xd->node->next_in_ino = raw;
+       } else {
+               xd->version = version;
+               xd->xprefix = rx->xprefix;
+               xd->name_len = rx->name_len;
+               xd->value_len = je16_to_cpu(rx->value_len);
+               xd->data_crc = je32_to_cpu(rx->data_crc);
 
-       jffs2_link_node_ref(c, jeb, raw, totlen, NULL);
-       /* FIXME */ raw->next_in_ino = (void *)xd;
+               jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, (void *)xd);
+       }
 
        if (jffs2_sum_active())
                jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
@@ -377,22 +375,20 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
                                struct jffs2_summary *s)
 {
        struct jffs2_xattr_ref *ref;
-       struct jffs2_raw_node_ref *raw;
        uint32_t crc;
        int err;
 
        crc = crc32(0, rr, sizeof(*rr) - 4);
        if (crc != je32_to_cpu(rr->node_crc)) {
-               if (je32_to_cpu(rr->node_crc) != 0xffffffff)
-                       JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                     ofs, je32_to_cpu(rr->node_crc), crc);
+               JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                             ofs, je32_to_cpu(rr->node_crc), crc);
                if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen)))))
                        return err;
                return 0;
        }
 
        if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) {
-               JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
+               JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%zd\n",
                              ofs, je32_to_cpu(rr->totlen),
                              PAD(sizeof(struct jffs2_raw_xref)));
                if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rr->totlen))))
@@ -404,13 +400,8 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
        if (!ref)
                return -ENOMEM;
 
-       raw =  jffs2_alloc_raw_node_ref();
-       if (!raw) {
-               jffs2_free_xattr_ref(ref);
-               return -ENOMEM;
-       }
-
        /* BEFORE jffs2_build_xattr_subsystem() called, 
+        * and AFTER xattr_ref is marked as a dead xref,
         * ref->xid is used to store 32bit xid, xd is not used
         * ref->ino is used to store 32bit inode-number, ic is not used
         * Thoes variables are declared as union, thus using those
@@ -418,16 +409,15 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
         * used to chain all xattr_ref object. It's re-chained to
         * jffs2_inode_cache in jffs2_build_xattr_subsystem() correctly.
         */
-       ref->node = raw;
        ref->ino = je32_to_cpu(rr->ino);
        ref->xid = je32_to_cpu(rr->xid);
+       ref->xseqno = je32_to_cpu(rr->xseqno);
+       if (ref->xseqno > c->highest_xseqno)
+               c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
        ref->next = c->xref_temp;
        c->xref_temp = ref;
 
-       raw->flash_offset = ofs | REF_PRISTINE;
-
-       jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen)), NULL);
-       /* FIXME */ raw->next_in_ino = (void *)ref;
+       jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), (void *)ref);
 
        if (jffs2_sum_active())
                jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
@@ -460,16 +450,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        if (jffs2_cleanmarker_oob(c)) {
-               int ret = jffs2_check_nand_cleanmarker(c, jeb);
+               int ret;
+
+               if (c->mtd->block_isbad(c->mtd, jeb->offset))
+                       return BLK_STATE_BADBLOCK;
+
+               ret = jffs2_check_nand_cleanmarker(c, jeb);
                D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
+
                /* Even if it's not found, we still scan to see
                   if the block is empty. We use this information
                   to decide whether to erase it or not. */
                switch (ret) {
                case 0:         cleanmarkerfound = 1; break;
                case 1:         break;
-               case 2:         return BLK_STATE_BADBLOCK;
-               case 3:         return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
                default:        return ret;
                }
        }
@@ -482,7 +476,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
              
                if (!buf_size) {
                        /* XIP case. Just look, point at the summary if it's there */
-                       sm = (void *)buf + jeb->offset - sizeof(*sm);
+                       sm = (void *)buf + c->sector_size - sizeof(*sm);
                        if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
                                sumptr = buf + je32_to_cpu(sm->offset);
                                sumlen = c->sector_size - je32_to_cpu(sm->offset);
@@ -581,6 +575,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
        if (ofs) {
                D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
                          jeb->offset + ofs));
+               if ((err = jffs2_prealloc_raw_node_refs(c, jeb, 1)))
+                       return err;
                if ((err = jffs2_scan_dirty_space(c, jeb, ofs)))
                        return err;
        }
@@ -597,6 +593,11 @@ scan_more:
 
                jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
+               /* Make sure there are node refs available for use */
+               err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
+               if (err)
+                       return err;
+
                cond_resched();
 
                if (ofs & 3) {
@@ -661,7 +662,7 @@ scan_more:
                        /* If we're only checking the beginning of a block with a cleanmarker,
                           bail now */
                        if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
-                           c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) {
+                           c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) {
                                D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
                                return BLK_STATE_CLEANMARKER;
                        }
@@ -733,6 +734,15 @@ scan_more:
                        ofs += 4;
                        continue;
                }
+               /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */
+               if (!je32_to_cpu(node->hdr_crc) && !je16_to_cpu(node->nodetype) &&
+                   !je16_to_cpu(node->magic) && !je32_to_cpu(node->totlen)) {
+                       noisy_printk(&noise, "jffs2_scan_eraseblock(): All zero node header at 0x%08x.\n", ofs);
+                       if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
+                               return err;
+                       ofs += 4;
+                       continue;
+               }
 
                if (ofs + je32_to_cpu(node->totlen) >
                    jeb->offset + c->sector_size) {
@@ -839,14 +849,7 @@ scan_more:
                                        return err;
                                ofs += PAD(sizeof(struct jffs2_unknown_node));
                        } else {
-                               struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
-                               if (!marker_ref) {
-                                       printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n");
-                                       return -ENOMEM;
-                               }
-                               marker_ref->flash_offset = ofs | REF_NORMAL;
-
-                               jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL);
+                               jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL);
 
                                ofs += PAD(c->cleanmarker_size);
                        }
@@ -884,14 +887,9 @@ scan_more:
                                break;
 
                        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));
 
-                               ref = jffs2_alloc_raw_node_ref();
-                               if (!ref)
-                                       return -ENOMEM;
-                               ref->flash_offset = ofs | REF_PRISTINE;
-                               jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)), NULL);
+                               jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL);
 
                                /* We can't summarise nodes we don't grok */
                                jffs2_sum_disable_collecting(s);
@@ -910,9 +908,9 @@ scan_more:
                }
        }
 
-       D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
-                 jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
-
+       D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
+                 jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size));
+       
        /* mark_node_obsolete can add to wasted !! */
        if (jeb->wasted_size) {
                jeb->dirty_size += jeb->wasted_size;
@@ -953,7 +951,6 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin
 static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s)
 {
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_inode_cache *ic;
        uint32_t ino = je32_to_cpu(ri->ino);
        int err;
@@ -969,12 +966,6 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
           Which means that the _full_ amount of time to get to proper write mode with GC
           operational may actually be _longer_ than before. Sucks to be me. */
 
-       raw = jffs2_alloc_raw_node_ref();
-       if (!raw) {
-               printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n");
-               return -ENOMEM;
-       }
-
        ic = jffs2_get_ino_cache(c, ino);
        if (!ic) {
                /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
@@ -988,21 +979,15 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                        /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
                        if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen)))))
                                return err;
-                       jffs2_free_raw_node_ref(raw);
                        return 0;
                }
                ic = jffs2_scan_make_ino_cache(c, ino);
-               if (!ic) {
-                       jffs2_free_raw_node_ref(raw);
+               if (!ic)
                        return -ENOMEM;
-               }
        }
 
        /* Wheee. It worked */
-
-       raw->flash_offset = ofs | REF_UNCHECKED;
-
-       jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)), ic);
+       jffs2_link_node_ref(c, jeb, ofs | REF_UNCHECKED, PAD(je32_to_cpu(ri->totlen)), ic);
 
        D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
                  je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
@@ -1021,7 +1006,6 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                  struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
 {
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_full_dirent *fd;
        struct jffs2_inode_cache *ic;
        uint32_t crc;
@@ -1063,23 +1047,14 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
                        return err;
                return 0;
        }
-       raw = jffs2_alloc_raw_node_ref();
-       if (!raw) {
-               jffs2_free_full_dirent(fd);
-               printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
-               return -ENOMEM;
-       }
        ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
        if (!ic) {
                jffs2_free_full_dirent(fd);
-               jffs2_free_raw_node_ref(raw);
                return -ENOMEM;
        }
 
-       raw->flash_offset = ofs | REF_PRISTINE;
-       jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic);
+       fd->raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rd->totlen)), ic);
 
-       fd->raw = raw;
        fd->next = NULL;
        fd->version = je32_to_cpu(rd->version);
        fd->ino = je32_to_cpu(rd->ino);