]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - fs/jffs2/jffs2_1pass.c
JFFS2: Improve speed reading flash files
[karo-tx-uboot.git] / fs / jffs2 / jffs2_1pass.c
index 11b66ab4b30847dc6b4f28ef9d72fb1cda7dc0a2..e58e7d25cff128b248db26b99b0f50a73428a9bf 100644 (file)
 #include <common.h>
 #include <config.h>
 #include <malloc.h>
+#include <div64.h>
 #include <linux/stat.h>
 #include <linux/time.h>
 #include <watchdog.h>
 #include <jffs2/jffs2.h>
 #include <jffs2/jffs2_1pass.h>
-#include <linux/mtd/compat.h>
+#include <linux/compat.h>
+#include <asm/errno.h>
 
 #include "jffs2_private.h"
 
@@ -146,11 +148,7 @@ static struct part_info *current_part;
 
 #if (defined(CONFIG_JFFS2_NAND) && \
      defined(CONFIG_CMD_NAND) )
-#if defined(CONFIG_NAND_LEGACY)
-#include <linux/mtd/nand_legacy.h>
-#else
 #include <nand.h>
-#endif
 /*
  * Support for jffs2 on top of NAND-flash
  *
@@ -161,12 +159,6 @@ static struct part_info *current_part;
  *
  */
 
-#if defined(CONFIG_NAND_LEGACY)
-/* this one defined in nand_legacy.c */
-int read_jffs2_nand(size_t start, size_t len,
-               size_t * retlen, u_char * buf, int nanddev);
-#endif
-
 #define NAND_PAGE_SIZE 512
 #define NAND_PAGE_SHIFT 9
 #define NAND_PAGE_MASK (~(NAND_PAGE_SIZE-1))
@@ -201,15 +193,6 @@ static int read_nand_cached(u32 off, u32 size, u_char *buf)
                                }
                        }
 
-#if defined(CONFIG_NAND_LEGACY)
-                       if (read_jffs2_nand(nand_cache_off, NAND_CACHE_SIZE,
-                                               &retlen, nand_cache, id->num) < 0 ||
-                                       retlen != NAND_CACHE_SIZE) {
-                               printf("read_nand_cached: error reading nand off %#x size %d bytes\n",
-                                               nand_cache_off, NAND_CACHE_SIZE);
-                               return -1;
-                       }
-#else
                        retlen = NAND_CACHE_SIZE;
                        if (nand_read(&nand_info[id->num], nand_cache_off,
                                                &retlen, nand_cache) != 0 ||
@@ -218,7 +201,6 @@ static int read_nand_cached(u32 off, u32 size, u_char *buf)
                                                nand_cache_off, NAND_CACHE_SIZE);
                                return -1;
                        }
-#endif
                }
                cpy_bytes = nand_cache_off + NAND_CACHE_SIZE - (off + bytes_read);
                if (cpy_bytes > size - bytes_read)
@@ -417,23 +399,26 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
 {
        struct mtdids *id = current_part->dev->id;
 
+       switch(id->type) {
 #if defined(CONFIG_CMD_FLASH)
-       if (id->type == MTD_DEV_TYPE_NOR) {
+       case MTD_DEV_TYPE_NOR:
                return get_fl_mem_nor(off, size, ext_buf);
-       }
+               break;
 #endif
-
 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
-       if (id->type == MTD_DEV_TYPE_NAND)
+       case MTD_DEV_TYPE_NAND:
                return get_fl_mem_nand(off, size, ext_buf);
+               break;
 #endif
-
 #if defined(CONFIG_CMD_ONENAND)
-       if (id->type == MTD_DEV_TYPE_ONENAND)
+       case MTD_DEV_TYPE_ONENAND:
                return get_fl_mem_onenand(off, size, ext_buf);
+               break;
 #endif
-
-       printf("get_fl_mem: unknown device type, using raw offset!\n");
+       default:
+               printf("get_fl_mem: unknown device type, " \
+                       "using raw offset!\n");
+       }
        return (void*)off;
 }
 
@@ -441,23 +426,27 @@ static inline void *get_node_mem(u32 off, void *ext_buf)
 {
        struct mtdids *id = current_part->dev->id;
 
+       switch(id->type) {
 #if defined(CONFIG_CMD_FLASH)
-       if (id->type == MTD_DEV_TYPE_NOR)
+       case MTD_DEV_TYPE_NOR:
                return get_node_mem_nor(off, ext_buf);
+               break;
 #endif
-
 #if defined(CONFIG_JFFS2_NAND) && \
     defined(CONFIG_CMD_NAND)
-       if (id->type == MTD_DEV_TYPE_NAND)
+       case MTD_DEV_TYPE_NAND:
                return get_node_mem_nand(off, ext_buf);
+               break;
 #endif
-
 #if defined(CONFIG_CMD_ONENAND)
-       if (id->type == MTD_DEV_TYPE_ONENAND)
+       case MTD_DEV_TYPE_ONENAND:
                return get_node_mem_onenand(off, ext_buf);
+               break;
 #endif
-
-       printf("get_node_mem: unknown device type, using raw offset!\n");
+       default:
+               printf("get_fl_mem: unknown device type, " \
+                       "using raw offset!\n");
+       }
        return (void*)off;
 }
 
@@ -490,9 +479,8 @@ static char *compr_names[] = {
        "COPY",
        "DYNRUBIN",
        "ZLIB",
-#if defined(CONFIG_JFFS2_LZO_LZARI)
+#if defined(CONFIG_JFFS2_LZO)
        "LZO",
-       "LZARI",
 #endif
 };
 
@@ -610,14 +598,18 @@ insert_node(struct b_list *list, u32 offset)
  */
 static int compare_inodes(struct b_node *new, struct b_node *old)
 {
-       struct jffs2_raw_inode ojNew;
-       struct jffs2_raw_inode ojOld;
-       struct jffs2_raw_inode *jNew =
-               (struct jffs2_raw_inode *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew);
-       struct jffs2_raw_inode *jOld =
-               (struct jffs2_raw_inode *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld);
-
-       return jNew->version > jOld->version;
+       /*
+        * Only read in the version info from flash, not the entire inode.
+        * This can make a big difference to speed if flash is slow.
+        */
+       u32 new_version;
+       u32 old_version;
+       get_fl_mem(new->offset + offsetof(struct jffs2_raw_inode, version),
+                  sizeof(new_version), &new_version);
+       get_fl_mem(old->offset + offsetof(struct jffs2_raw_inode, version),
+                  sizeof(old_version), &old_version);
+
+       return new_version > old_version;
 }
 
 /* Sort directory entries so all entries in the same directory
@@ -627,42 +619,45 @@ static int compare_inodes(struct b_node *new, struct b_node *old)
  */
 static int compare_dirents(struct b_node *new, struct b_node *old)
 {
-       struct jffs2_raw_dirent ojNew;
-       struct jffs2_raw_dirent ojOld;
-       struct jffs2_raw_dirent *jNew =
-               (struct jffs2_raw_dirent *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew);
-       struct jffs2_raw_dirent *jOld =
-               (struct jffs2_raw_dirent *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld);
-       int cmp;
-
-       /* ascending sort by pino */
-       if (jNew->pino != jOld->pino)
-               return jNew->pino > jOld->pino;
-
-       /* pino is the same, so use ascending sort by nsize, so
-        * we don't do strncmp unless we really must.
+       /*
+        * Using NULL as the buffer for NOR flash prevents the entire node
+        * being read. This makes most comparisons much quicker as only one
+        * or two entries from the node will be used most of the time.
         */
-       if (jNew->nsize != jOld->nsize)
-               return jNew->nsize > jOld->nsize;
-
-       /* length is also the same, so use ascending sort by name
-        */
-       cmp = strncmp((char *)jNew->name, (char *)jOld->name, jNew->nsize);
-       if (cmp != 0)
-               return cmp > 0;
-
-       /* we have duplicate names in this directory, so use ascending
-        * sort by version
-        */
-       if (jNew->version > jOld->version) {
-               /* since jNew is newer, we know jOld is not valid, so
-                * mark it with inode 0 and it will not be used
+       struct jffs2_raw_dirent *jNew = get_node_mem(new->offset, NULL);
+       struct jffs2_raw_dirent *jOld = get_node_mem(old->offset, NULL);
+       int cmp;
+       int ret;
+
+       if (jNew->pino != jOld->pino) {
+               /* ascending sort by pino */
+               ret = jNew->pino > jOld->pino;
+       } else if (jNew->nsize != jOld->nsize) {
+               /*
+                * pino is the same, so use ascending sort by nsize,
+                * so we don't do strncmp unless we really must.
                 */
-               jOld->ino = 0;
-               return 1;
+               ret = jNew->nsize > jOld->nsize;
+       } else {
+               /*
+                * length is also the same, so use ascending sort by name
+                */
+               cmp = strncmp((char *)jNew->name, (char *)jOld->name,
+                       jNew->nsize);
+               if (cmp != 0) {
+                       ret = cmp > 0;
+               } else {
+                       /*
+                        * we have duplicate names in this directory,
+                        * so use ascending sort by version
+                        */
+                       ret = jNew->version > jOld->version;
+               }
        }
+       put_fl_mem(jNew, NULL);
+       put_fl_mem(jOld, NULL);
 
-       return 0;
+       return ret;
 }
 #endif
 
@@ -709,7 +704,6 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
        u32 latestVersion = 0;
        uchar *lDest;
        uchar *src;
-       long ret;
        int i;
        u32 counter = 0;
 #ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
@@ -732,12 +726,23 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                }
                put_fl_mem(jNode, pL->readbuf);
        }
+       /*
+        * If no destination is provided, we are done.
+        * Just return the total size.
+        */
+       if (!dest)
+               return totalSize;
 #endif
 
        for (b = pL->frag.listHead; b != NULL; b = b->next) {
-               jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset,
-                                                               pL->readbuf);
-               if ((inode == jNode->ino)) {
+               /*
+                * Copy just the node and not the data at this point,
+                * since we don't yet know if we need this data.
+                */
+               jNode = (struct jffs2_raw_inode *)get_fl_mem(b->offset,
+                               sizeof(struct jffs2_raw_inode),
+                               pL->readbuf);
+               if (inode == jNode->ino) {
 #if 0
                        putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen);
                        putLabeledWord("read_inode: inode = ", jNode->ino);
@@ -760,7 +765,15 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
 #endif
 
                        if(dest) {
-                               src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode);
+                               /*
+                                * Now that the inode has been checked,
+                                * read the entire inode, including data.
+                                */
+                               put_fl_mem(jNode, pL->readbuf);
+                               jNode = (struct jffs2_raw_inode *)
+                                       get_node_mem(b->offset, pL->readbuf);
+                               src = ((uchar *)jNode) +
+                                       sizeof(struct jffs2_raw_inode);
                                /* ignore data behind latest known EOF */
                                if (jNode->offset > totalSize) {
                                        put_fl_mem(jNode, pL->readbuf);
@@ -781,36 +794,30 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
 #endif
                                switch (jNode->compr) {
                                case JFFS2_COMPR_NONE:
-                                       ret = (unsigned long) ldr_memcpy(lDest, src, jNode->dsize);
+                                       ldr_memcpy(lDest, src, jNode->dsize);
                                        break;
                                case JFFS2_COMPR_ZERO:
-                                       ret = 0;
                                        for (i = 0; i < jNode->dsize; i++)
                                                *(lDest++) = 0;
                                        break;
                                case JFFS2_COMPR_RTIME:
-                                       ret = 0;
                                        rtime_decompress(src, lDest, jNode->csize, jNode->dsize);
                                        break;
                                case JFFS2_COMPR_DYNRUBIN:
                                        /* this is slow but it works */
-                                       ret = 0;
                                        dynrubin_decompress(src, lDest, jNode->csize, jNode->dsize);
                                        break;
                                case JFFS2_COMPR_ZLIB:
-                                       ret = zlib_decompress(src, lDest, jNode->csize, jNode->dsize);
+                                       zlib_decompress(src, lDest, jNode->csize, jNode->dsize);
                                        break;
-#if defined(CONFIG_JFFS2_LZO_LZARI)
+#if defined(CONFIG_JFFS2_LZO)
                                case JFFS2_COMPR_LZO:
-                                       ret = lzo_decompress(src, lDest, jNode->csize, jNode->dsize);
-                                       break;
-                               case JFFS2_COMPR_LZARI:
-                                       ret = lzari_decompress(src, lDest, jNode->csize, jNode->dsize);
+                                       lzo_decompress(src, lDest, jNode->csize, jNode->dsize);
                                        break;
 #endif
                                default:
                                        /* unknown */
-                                       putLabeledWord("UNKOWN COMPRESSION METHOD = ", jNode->compr);
+                                       putLabeledWord("UNKNOWN COMPRESSION METHOD = ", jNode->compr);
                                        put_fl_mem(jNode, pL->readbuf);
                                        return -1;
                                        break;
@@ -819,7 +826,6 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
 
 #if 0
                        putLabeledWord("read_inode: totalSize = ", totalSize);
-                       putLabeledWord("read_inode: compr ret = ", ret);
 #endif
                }
                counter++;
@@ -852,7 +858,6 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
                jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset,
                                                                pL->readbuf);
                if ((pino == jDir->pino) && (len == jDir->nsize) &&
-                   (jDir->ino) &&      /* 0 for unlink */
                    (!strncmp((char *)jDir->name, name, len))) {        /* a match */
                        if (jDir->version < version) {
                                put_fl_mem(jDir, pL->readbuf);
@@ -973,16 +978,47 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)
        for (b = pL->dir.listHead; b; b = b->next) {
                jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset,
                                                                pL->readbuf);
-               if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */
+               if (pino == jDir->pino) {
                        u32 i_version = 0;
-                       struct jffs2_raw_inode ojNode;
                        struct jffs2_raw_inode *jNode, *i = NULL;
-                       struct b_node *b2 = pL->frag.listHead;
+                       struct b_node *b2;
+
+#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
+                       /* Check for more recent versions of this file */
+                       int match;
+                       do {
+                               struct b_node *next = b->next;
+                               struct jffs2_raw_dirent *jDirNext;
+                               if (!next)
+                                       break;
+                               jDirNext = (struct jffs2_raw_dirent *)
+                                       get_node_mem(next->offset, NULL);
+                               match = jDirNext->pino == jDir->pino &&
+                                       jDirNext->nsize == jDir->nsize &&
+                                       strncmp((char *)jDirNext->name,
+                                               (char *)jDir->name,
+                                               jDir->nsize) == 0;
+                               if (match) {
+                                       /* Use next. It is more recent */
+                                       b = next;
+                                       /* Update buffer with the new info */
+                                       *jDir = *jDirNext;
+                               }
+                               put_fl_mem(jDirNext, NULL);
+                       } while (match);
+#endif
+                       if (jDir->ino == 0) {
+                               /* Deleted file */
+                               put_fl_mem(jDir, pL->readbuf);
+                               continue;
+                       }
 
-                       while (b2) {
+                       for (b2 = pL->frag.listHead; b2; b2 = b2->next) {
                                jNode = (struct jffs2_raw_inode *)
-                                       get_fl_mem(b2->offset, sizeof(ojNode), &ojNode);
-                               if (jNode->ino == jDir->ino && jNode->version >= i_version) {
+                                       get_fl_mem(b2->offset, sizeof(*jNode),
+                                                  NULL);
+                               if (jNode->ino == jDir->ino &&
+                                   jNode->version >= i_version) {
                                        i_version = jNode->version;
                                        if (i)
                                                put_fl_mem(i, NULL);
@@ -995,7 +1031,7 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)
                                                               sizeof(*i),
                                                               NULL);
                                }
-                               b2 = b2->next;
+                               put_fl_mem(jNode, NULL);
                        }
 
                        dump_inode(pL, jDir, i);
@@ -1220,8 +1256,30 @@ jffs2_1pass_rescan_needed(struct part_info *part)
        return 0;
 }
 
+#ifdef CONFIG_JFFS2_SUMMARY
+static u32 sum_get_unaligned32(u32 *ptr)
+{
+       u32 val;
+       u8 *p = (u8 *)ptr;
+
+       val = *p | (*(p + 1) << 8) | (*(p + 2) << 16) | (*(p + 3) << 24);
+
+       return __le32_to_cpu(val);
+}
+
+static u16 sum_get_unaligned16(u16 *ptr)
+{
+       u16 val;
+       u8 *p = (u8 *)ptr;
+
+       val = *p | (*(p + 1) << 8);
+
+       return __le16_to_cpu(val);
+}
+
 #define dbg_summary(...) do {} while (0);
-/* Process the stored summary information - helper function for
+/*
+ * Process the stored summary information - helper function for
  * jffs2_sum_scan_sumnode()
  */
 
@@ -1230,54 +1288,64 @@ static int jffs2_sum_process_sum_data(struct part_info *part, uint32_t offset,
                                struct b_lists *pL)
 {
        void *sp;
-       int i;
+       int i, pass;
+       void *ret;
 
-       sp = summary->sum;
+       for (pass = 0; pass < 2; pass++) {
+               sp = summary->sum;
 
-       for (i = 0; i < summary->sum_num; i++) {
-               dbg_summary("processing summary index %d\n", i);
+               for (i = 0; i < summary->sum_num; i++) {
+                       struct jffs2_sum_unknown_flash *spu = sp;
+                       dbg_summary("processing summary index %d\n", i);
 
-               switch (((struct jffs2_sum_unknown_flash *)sp)->nodetype) {
-                       case JFFS2_NODETYPE_INODE: {
+                       switch (sum_get_unaligned16(&spu->nodetype)) {
+                               case JFFS2_NODETYPE_INODE: {
                                struct jffs2_sum_inode_flash *spi;
-                               spi = sp;
+                                       if (pass) {
+                                               spi = sp;
 
-                               dbg_summary("Inode at 0x%08x-0x%08x\n",
-                                           offset + spi->offset,
-                                           offset + spi->offset + spi->totlen);
+                                               ret = insert_node(&pL->frag,
+                                                       (u32)part->offset +
+                                                       offset +
+                                                       sum_get_unaligned32(
+                                                               &spi->offset));
+                                               if (ret == NULL)
+                                                       return -1;
+                                       }
 
-                               if (insert_node(&pL->frag, (u32) part->offset +
-                                               offset + spi->offset) == NULL)
-                                       return -1;
+                                       sp += JFFS2_SUMMARY_INODE_SIZE;
 
-                               sp += JFFS2_SUMMARY_INODE_SIZE;
-
-                               break;
-                       }
-
-                       case JFFS2_NODETYPE_DIRENT: {
-                               struct jffs2_sum_dirent_flash *spd;
-                               spd = sp;
-
-                               dbg_summary("Dirent at 0x%08x-0x%08x\n",
-                                           offset + spd->offset,
-                                           offset + spd->offset + spd->totlen);
-
-                               if (insert_node(&pL->dir, (u32) part->offset +
-                                               offset + spd->offset) == NULL)
-                                       return -1;
-
-                               sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+                                       break;
+                               }
+                               case JFFS2_NODETYPE_DIRENT: {
+                                       struct jffs2_sum_dirent_flash *spd;
+                                       spd = sp;
+                                       if (pass) {
+                                               ret = insert_node(&pL->dir,
+                                                       (u32) part->offset +
+                                                       offset +
+                                                       sum_get_unaligned32(
+                                                               &spd->offset));
+                                               if (ret == NULL)
+                                                       return -1;
+                                       }
+
+                                       sp += JFFS2_SUMMARY_DIRENT_SIZE(
+                                                       spd->nsize);
 
-                               break;
-                       }
-                       default : {
-                               uint16_t nodetype =
-                                       ((struct jffs2_sum_unknown_flash *)
-                                        sp)->nodetype;
-                               printf("Unsupported node type %x found in "
-                                               "summary!\n", nodetype);
-                               break;
+                                       break;
+                               }
+                               default : {
+                                       uint16_t nodetype = sum_get_unaligned16(
+                                                               &spu->nodetype);
+                                       printf("Unsupported node type %x found"
+                                                       " in summary!\n",
+                                                       nodetype);
+                                       if ((nodetype & JFFS2_COMPAT_MASK) ==
+                                                       JFFS2_FEATURE_INCOMPAT)
+                                               return -EIO;
+                                       return -EBADMSG;
+                               }
                        }
                }
        }
@@ -1335,6 +1403,8 @@ int jffs2_sum_scan_sumnode(struct part_info *part, uint32_t offset,
                dbg_summary("Summary : CLEANMARKER node \n");
 
        ret = jffs2_sum_process_sum_data(part, offset, summary, pL);
+       if (ret == -EBADMSG)
+               return 0;
        if (ret)
                return ret;             /* real error */
 
@@ -1345,6 +1415,7 @@ crc_err:
 
        return 0;
 }
+#endif /* CONFIG_JFFS2_SUMMARY */
 
 #ifdef DEBUG_FRAGMENTS
 static void
@@ -1424,7 +1495,7 @@ jffs2_1pass_build_lists(struct part_info * part)
 {
        struct b_lists *pL;
        struct jffs2_unknown_node *node;
-       u32 nr_sectors = part->size/part->sector_size;
+       u32 nr_sectors;
        u32 i;
        u32 counter4 = 0;
        u32 counterF = 0;
@@ -1433,6 +1504,7 @@ jffs2_1pass_build_lists(struct part_info * part)
        u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE;
        char *buf;
 
+       nr_sectors = lldiv(part->size, part->sector_size);
        /* turn off the lcd.  Refreshing the lcd adds 50% overhead to the */
        /* jffs2 list building enterprise nope.  in newer versions the overhead is */
        /* only about 5 %.  not enough to inconvenience people for. */
@@ -1450,13 +1522,16 @@ jffs2_1pass_build_lists(struct part_info * part)
                uint32_t buf_ofs = sector_ofs;
                uint32_t buf_len;
                uint32_t ofs, prevofs;
+#ifdef CONFIG_JFFS2_SUMMARY
                struct jffs2_sum_marker *sm;
                void *sumptr = NULL;
                uint32_t sumlen;
                int ret;
+#endif
 
                WATCHDOG_RESET();
 
+#ifdef CONFIG_JFFS2_SUMMARY
                buf_len = sizeof(*sm);
 
                /* Read as much as we want into the _end_ of the preallocated
@@ -1477,6 +1552,8 @@ jffs2_1pass_build_lists(struct part_info * part)
                                if (!sumptr) {
                                        putstr("Can't get memory for summary "
                                                        "node!\n");
+                                       free(buf);
+                                       jffs2_free_cache(part);
                                        return 0;
                                }
                                memcpy(sumptr + sumlen - buf_len, buf +
@@ -1498,12 +1575,16 @@ jffs2_1pass_build_lists(struct part_info * part)
 
                        if (buf_size && sumlen > buf_size)
                                free(sumptr);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               free(buf);
+                               jffs2_free_cache(part);
                                return 0;
+                       }
                        if (ret)
                                continue;
 
                }
+#endif /* CONFIG_JFFS2_SUMMARY */
 
                buf_len = EMPTY_SCAN_SIZE(part->sector_size);
 
@@ -1547,9 +1628,8 @@ jffs2_1pass_build_lists(struct part_info * part)
 
                        if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
                                uint32_t inbuf_ofs;
-                               uint32_t empty_start, scan_end;
+                               uint32_t scan_end;
 
-                               empty_start = ofs;
                                ofs += 4;
                                scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(
                                                        part->sector_size)/8,
@@ -1612,8 +1692,11 @@ jffs2_1pass_build_lists(struct part_info * part)
                                       break;
 
                                if (insert_node(&pL->frag, (u32) part->offset +
-                                               ofs) == NULL)
+                                               ofs) == NULL) {
+                                       free(buf);
+                                       jffs2_free_cache(part);
                                        return 0;
+                               }
                                if (max_totlen < node->totlen)
                                        max_totlen = node->totlen;
                                break;
@@ -1639,8 +1722,11 @@ jffs2_1pass_build_lists(struct part_info * part)
                                if (! (counterN%100))
                                        puts ("\b\b.  ");
                                if (insert_node(&pL->dir, (u32) part->offset +
-                                               ofs) == NULL)
+                                               ofs) == NULL) {
+                                       free(buf);
+                                       jffs2_free_cache(part);
                                        return 0;
+                               }
                                if (max_totlen < node->totlen)
                                        max_totlen = node->totlen;
                                counterN++;