Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / fs / jffs2 / summary.c
index 11ea54c..be1acc3 100644 (file)
@@ -43,7 +43,7 @@ int jffs2_sum_init(struct jffs2_sb_info *c)
                return -ENOMEM;
        }
 
-       dbg_summary("returned succesfully\n");
+       dbg_summary("returned successfully\n");
 
        return 0;
 }
@@ -369,13 +369,25 @@ no_mem:
        return -ENOMEM;
 }
 
+static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c,
+                                                   struct jffs2_eraseblock *jeb,
+                                                   uint32_t ofs, uint32_t len,
+                                                   struct jffs2_inode_cache *ic)
+{
+       /* If there was a gap, mark it dirty */
+       if ((ofs & ~3) > c->sector_size - jeb->free_size) {
+               /* Ew. Summary doesn't actually tell us explicitly about dirty space */
+               jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size));
+       }
+
+       return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic);
+}
 
 /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
 
 static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                struct jffs2_raw_summary *summary, uint32_t *pseudo_random)
 {
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_inode_cache *ic;
        struct jffs2_full_dirent *fd;
        void *sp;
@@ -387,6 +399,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
        for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
                dbg_summary("processing summary index %d\n", i);
 
+               /* Make sure there's a spare ref for dirty space */
+               err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
+               if (err)
+                       return err;
+
                switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
                        case JFFS2_NODETYPE_INODE: {
                                struct jffs2_sum_inode_flash *spi;
@@ -394,28 +411,18 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
 
                                ino = je32_to_cpu(spi->inode);
 
-                               dbg_summary("Inode at 0x%08x\n",
-                                                       jeb->offset + je32_to_cpu(spi->offset));
-
-                               raw = jffs2_alloc_raw_node_ref();
-                               if (!raw) {
-                                       JFFS2_NOTICE("allocation of node reference failed\n");
-                                       return -ENOMEM;
-                               }
+                               dbg_summary("Inode at 0x%08x-0x%08x\n",
+                                           jeb->offset + je32_to_cpu(spi->offset),
+                                           jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen));
 
                                ic = jffs2_scan_make_ino_cache(c, ino);
                                if (!ic) {
                                        JFFS2_NOTICE("scan_make_ino_cache failed\n");
-                                       jffs2_free_raw_node_ref(raw);
                                        return -ENOMEM;
                                }
 
-                               raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
-
-                               raw->next_in_ino = ic->nodes;
-                               ic->nodes = raw;
-
-                               jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)));
+                               sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED,
+                                                 PAD(je32_to_cpu(spi->totlen)), ic);
 
                                *pseudo_random += je32_to_cpu(spi->version);
 
@@ -428,8 +435,10 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                struct jffs2_sum_dirent_flash *spd;
                                spd = sp;
 
-                               dbg_summary("Dirent at 0x%08x\n",
-                                                       jeb->offset + je32_to_cpu(spd->offset));
+                               dbg_summary("Dirent at 0x%08x-0x%08x\n",
+                                           jeb->offset + je32_to_cpu(spd->offset),
+                                           jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));
+
 
                                fd = jffs2_alloc_full_dirent(spd->nsize+1);
                                if (!fd)
@@ -438,27 +447,15 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                memcpy(&fd->name, spd->name, spd->nsize);
                                fd->name[spd->nsize] = 0;
 
-                               raw = jffs2_alloc_raw_node_ref();
-                               if (!raw) {
-                                       jffs2_free_full_dirent(fd);
-                                       JFFS2_NOTICE("allocation of node reference failed\n");
-                                       return -ENOMEM;
-                               }
-
                                ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
                                if (!ic) {
                                        jffs2_free_full_dirent(fd);
-                                       jffs2_free_raw_node_ref(raw);
                                        return -ENOMEM;
                                }
 
-                               raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
-                               raw->next_in_ino = ic->nodes;
-                               ic->nodes = raw;
-
-                               jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)));
+                               fd->raw = sum_link_node_ref(c, jeb,  je32_to_cpu(spd->offset) | REF_UNCHECKED,
+                                                           PAD(je32_to_cpu(spd->totlen)), ic);
 
-                               fd->raw = raw;
                                fd->next = NULL;
                                fd->version = je32_to_cpu(spd->version);
                                fd->ino = je32_to_cpu(spd->ino);
@@ -477,22 +474,16 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                        case JFFS2_NODETYPE_XATTR: {
                                struct jffs2_xattr_datum *xd;
                                struct jffs2_sum_xattr_flash *spx;
-                               uint32_t ofs;
 
                                spx = (struct jffs2_sum_xattr_flash *)sp;
-                               ofs = jeb->offset + je32_to_cpu(spx->offset);
-                               dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs,
+                               dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", 
+                                           jeb->offset + je32_to_cpu(spx->offset),
+                                           jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen),
                                            je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
-                               raw = jffs2_alloc_raw_node_ref();
-                               if (!raw) {
-                                       JFFS2_NOTICE("allocation of node reference failed\n");
-                                       kfree(summary);
-                                       return -ENOMEM;
-                               }
+
                                xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
                                                                je32_to_cpu(spx->version));
                                if (IS_ERR(xd)) {
-                                       jffs2_free_raw_node_ref(raw);
                                        if (PTR_ERR(xd) == -EEXIST) {
                                                /* a newer version of xd exists */
                                                if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen))))
@@ -501,15 +492,12 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                                break;
                                        }
                                        JFFS2_NOTICE("allocation of xattr_datum failed\n");
-                                       kfree(summary);
                                        return PTR_ERR(xd);
                                }
-                               xd->node = raw;
-
-                               raw->flash_offset = ofs | REF_UNCHECKED;
-                               raw->next_in_ino = (void *)xd;
 
-                               jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen)));
+                               xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+                                                            PAD(je32_to_cpu(spx->totlen)), NULL);
+                               /* FIXME */ xd->node->next_in_ino = (void *)xd;
 
                                *pseudo_random += je32_to_cpu(spx->xid);
                                sp += JFFS2_SUMMARY_XATTR_SIZE;
@@ -519,37 +507,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                        case JFFS2_NODETYPE_XREF: {
                                struct jffs2_xattr_ref *ref;
                                struct jffs2_sum_xref_flash *spr;
-                               uint32_t ofs;
 
                                spr = (struct jffs2_sum_xref_flash *)sp;
-                               ofs = jeb->offset + je32_to_cpu(spr->offset);
-                               dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs,
-                                           je32_to_cpu(spr->xid), je32_to_cpu(spr->ino));
-                               raw = jffs2_alloc_raw_node_ref();
-                               if (!raw) {
-                                       JFFS2_NOTICE("allocation of node reference failed\n");
-                                       kfree(summary);
-                                       return -ENOMEM;
-                               }
+                               dbg_summary("xref at %#08x-%#08x\n",
+                                           jeb->offset + je32_to_cpu(spr->offset),
+                                           jeb->offset + je32_to_cpu(spr->offset) + 
+                                           (uint32_t)PAD(sizeof(struct jffs2_raw_xref)));
+
                                ref = jffs2_alloc_xattr_ref();
                                if (!ref) {
                                        JFFS2_NOTICE("allocation of xattr_datum failed\n");
-                                       jffs2_free_raw_node_ref(raw);
-                                       kfree(summary);
                                        return -ENOMEM;
                                }
                                ref->ino = 0xfffffffe;
                                ref->xid = 0xfffffffd;
-                               ref->node = raw;
                                ref->next = c->xref_temp;
                                c->xref_temp = ref;
 
-                               raw->flash_offset = ofs | REF_UNCHECKED;
-                               raw->next_in_ino = (void *)ref;
-
-                               jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref)));
+                               ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
+                                                             PAD(sizeof(struct jffs2_raw_xref)), NULL);
+                               /* FIXME */ ref->node->next_in_ino = (void *)ref;
 
-                               *pseudo_random += ofs;
+                               *pseudo_random += ref->node->flash_offset;
                                sp += JFFS2_SUMMARY_XREF_SIZE;
 
                                break;
@@ -569,12 +548,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0;
                                jeb->free_size = c->sector_size;
 
-                               jffs2_free_all_node_refs(c, jeb);
+                               jffs2_free_jeb_node_refs(c, jeb);
                                return -ENOTRECOVERABLE;
                        }
                }
        }
-
        return 0;
 }
 
@@ -584,15 +562,13 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
                           uint32_t *pseudo_random)
 {
        struct jffs2_unknown_node crcnode;
-       struct jffs2_raw_node_ref *cache_ref;
        int ret, ofs;
        uint32_t crc;
-       int err;
 
-       ofs = jeb->offset + c->sector_size - sumsize;
+       ofs = c->sector_size - sumsize;
 
        dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
-                   jeb->offset, ofs, sumsize);
+                   jeb->offset, jeb->offset + ofs, sumsize);
 
        /* OK, now check for node validity and CRC */
        crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -629,36 +605,26 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
 
                dbg_summary("Summary : CLEANMARKER node \n");
 
+               ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
+               if (ret)
+                       return ret;
+
                if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
                        dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
                                je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
-                       if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
-                               return err;
+                       if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
+                               return ret;
                } else if (jeb->first_node) {
                        dbg_summary("CLEANMARKER node not first node in block "
                                        "(0x%08x)\n", jeb->offset);
-                       if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
-                               return err;
+                       if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
+                               return ret;
                } else {
-                       struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
-
-                       if (!marker_ref) {
-                               JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
-                               return -ENOMEM;
-                       }
-
-                       marker_ref->flash_offset = jeb->offset | REF_NORMAL;
-                       marker_ref->next_in_ino = NULL;
-
-                       jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr));
+                       jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL,
+                                           je32_to_cpu(summary->cln_mkr), NULL);
                }
        }
 
-       if (je32_to_cpu(summary->padded)) {
-               if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(summary->padded))))
-                       return err;
-       }
-
        ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
        /* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full
           scan of this eraseblock. So return zero */
@@ -668,23 +634,20 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
                return ret;             /* real error */
 
        /* for PARANOIA_CHECK */
-       cache_ref = jffs2_alloc_raw_node_ref();
-
-       if (!cache_ref) {
-               JFFS2_NOTICE("Failed to allocate node ref for cache\n");
-               return -ENOMEM;
-       }
-
-       cache_ref->next_in_ino = NULL;
-       cache_ref->next_phys = NULL;
-       cache_ref->flash_offset = ofs | REF_NORMAL;
+       ret = jffs2_prealloc_raw_node_refs(c, jeb, 2);
+       if (ret)
+               return ret;
 
-       jffs2_link_node_ref(c, jeb, cache_ref, sumsize);
+       sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL);
 
-       jeb->wasted_size += jeb->free_size;
-       c->wasted_size += jeb->free_size;
-       c->free_size -= jeb->free_size;
-       jeb->free_size = 0;
+       if (unlikely(jeb->free_size)) {
+               JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n",
+                             jeb->free_size, jeb->offset);
+               jeb->wasted_size += jeb->free_size;
+               c->wasted_size += jeb->free_size;
+               c->free_size -= jeb->free_size;
+               jeb->free_size = 0;
+       }
 
        return jffs2_scan_classify_jeb(c, jeb);
 
@@ -703,6 +666,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
        union jffs2_sum_mem *temp;
        struct jffs2_sum_marker *sm;
        struct kvec vecs[2];
+       uint32_t sum_ofs;
        void *wpage;
        int ret;
        size_t retlen;
@@ -815,25 +779,34 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
        vecs[1].iov_base = c->summary->sum_buf;
        vecs[1].iov_len = datasize;
 
-       dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n",
-                       jeb->offset + c->sector_size - jeb->free_size);
+       sum_ofs = jeb->offset + c->sector_size - jeb->free_size;
 
-       spin_unlock(&c->erase_completion_lock);
-       ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size -
-                               jeb->free_size, &retlen, 0);
-       spin_lock(&c->erase_completion_lock);
+       dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n",
+                   sum_ofs);
 
+       ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0);
 
        if (ret || (retlen != infosize)) {
+
                JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
-                       infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
+                             infosize, sum_ofs, ret, retlen);
+
+               if (retlen) {
+                       /* Waste remaining space */
+                       spin_lock(&c->erase_completion_lock);
+                       jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL);
+                       spin_unlock(&c->erase_completion_lock);
+               }
 
                c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
-               jffs2_scan_dirty_space(c, jeb, infosize);
 
-               return 1;
+               return 0;
        }
 
+       spin_lock(&c->erase_completion_lock);
+       jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL);
+       spin_unlock(&c->erase_completion_lock);
+
        return 0;
 }
 
@@ -841,13 +814,16 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
 
 int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
 {
-       struct jffs2_raw_node_ref *summary_ref;
-       int datasize, infosize, padsize, ret;
+       int datasize, infosize, padsize;
        struct jffs2_eraseblock *jeb;
+       int ret;
 
        dbg_summary("called\n");
 
+       spin_unlock(&c->erase_completion_lock);
+
        jeb = c->nextblock;
+       jffs2_prealloc_raw_node_refs(c, jeb, 1);
 
        if (!c->summary->sum_num || !c->summary->sum_list_head) {
                JFFS2_WARNING("Empty summary info!!!\n");
@@ -866,27 +842,11 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
                jffs2_sum_disable_collecting(c->summary);
 
                JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize);
+               spin_lock(&c->erase_completion_lock);
                return 0;
        }
 
        ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
-       if (ret)
-               return 0; /* can't write out summary, block is marked as NOSUM_SIZE */
-
-       /* for ACCT_PARANOIA_CHECK */
-       spin_unlock(&c->erase_completion_lock);
-       summary_ref = jffs2_alloc_raw_node_ref();
        spin_lock(&c->erase_completion_lock);
-
-       if (!summary_ref) {
-               JFFS2_NOTICE("Failed to allocate node ref for summary\n");
-               return -ENOMEM;
-       }
-
-       summary_ref->next_in_ino = NULL;
-       summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL;
-
-       jffs2_link_node_ref(c, jeb, summary_ref, infosize);
-
-       return 0;
+       return ret;
 }