jffs2: add buffer to cache flash accesses
authorIlya Yanok <yanok@emcraft.com>
Thu, 13 Nov 2008 16:49:34 +0000 (19:49 +0300)
committerWolfgang Denk <wd@denx.de>
Tue, 9 Dec 2008 22:39:58 +0000 (23:39 +0100)
With this patch JFFS2 code allocates memory buffer of max_totlen size
(size of the largest node, calculated during scan time) and uses it to
store entire node. Speeds up loading. If malloc fails we use old ways
to do things.

Signed-off-by: Alexey Neyman <avn@emcraft.com>
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
fs/jffs2/jffs2_1pass.c
fs/jffs2/jffs2_private.h

index 30a6dba6e00f6c0026adcd3c48b9e8f89f0add24..73d3ddc9e137fa7e68cc8e1855e9186d3fffeeaa 100644 (file)
@@ -245,7 +245,7 @@ static void *get_fl_mem_nand(u32 off, u32 size, void *ext_buf)
        return buf;
 }
 
-static void *get_node_mem_nand(u32 off)
+static void *get_node_mem_nand(u32 off, void *ext_buf)
 {
        struct jffs2_unknown_node node;
        void *ret = NULL;
@@ -255,7 +255,7 @@ static void *get_node_mem_nand(u32 off)
 
        if (!(ret = get_fl_mem_nand(off, node.magic ==
                               JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node),
-                              NULL))) {
+                              ext_buf))) {
                printf("off = %#x magic %#x type %#x node.totlen = %d\n",
                       off, node.magic, node.nodetype, node.totlen);
        }
@@ -344,7 +344,7 @@ static void *get_fl_mem_onenand(u32 off, u32 size, void *ext_buf)
        return buf;
 }
 
-static void *get_node_mem_onenand(u32 off)
+static void *get_node_mem_onenand(u32 off, void *ext_buf)
 {
        struct jffs2_unknown_node node;
        void *ret = NULL;
@@ -354,7 +354,7 @@ static void *get_node_mem_onenand(u32 off)
 
        ret = get_fl_mem_onenand(off, node.magic ==
                        JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node),
-                       NULL);
+                       ext_buf);
        if (!ret) {
                printf("off = %#x magic %#x type %#x node.totlen = %d\n",
                       off, node.magic, node.nodetype, node.totlen);
@@ -377,7 +377,7 @@ static void put_fl_mem_onenand(void *buf)
  * NOR flash memory is mapped in processor's address space,
  * just return address.
  */
-static inline void *get_fl_mem_nor(u32 off)
+static inline void *get_fl_mem_nor(u32 off, u32 size, void *ext_buf)
 {
        u32 addr = off;
        struct mtdids *id = current_part->dev->id;
@@ -386,18 +386,22 @@ static inline void *get_fl_mem_nor(u32 off)
        flash_info_t *flash = &flash_info[id->num];
 
        addr += flash->start[0];
+       if (ext_buf) {
+               memcpy(ext_buf, (void *)addr, size);
+               return ext_buf;
+       }
        return (void*)addr;
 }
 
-static inline void *get_fl_mem_nor_copy(u32 off, u32 size, void *ext_buf)
+static inline void *get_node_mem_nor(u32 off, void *ext_buf)
 {
-       memcpy(ext_buf, get_fl_mem_nor(off), size);
-       return ext_buf;
-}
+       struct jffs2_unknown_node *pNode;
 
-static inline void *get_node_mem_nor(u32 off)
-{
-       return (void*)get_fl_mem_nor(off);
+       /* pNode will point directly to flash - don't provide external buffer
+          and don't care about size */
+       pNode = get_fl_mem_nor(off, 0, NULL);
+       return (void *)get_fl_mem_nor(off, pNode->magic == JFFS2_MAGIC_BITMASK ?
+                       pNode->totlen : sizeof(*pNode), ext_buf);
 }
 #endif
 
@@ -412,9 +416,7 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
 
 #if defined(CONFIG_CMD_FLASH)
        if (id->type == MTD_DEV_TYPE_NOR) {
-               if (ext_buf)
-                       return get_fl_mem_nor_copy(off, size, ext_buf);
-               return get_fl_mem_nor(off);
+               return get_fl_mem_nor(off, size, ext_buf);
        }
 #endif
 
@@ -432,34 +434,38 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
        return (void*)off;
 }
 
-static inline void *get_node_mem(u32 off)
+static inline void *get_node_mem(u32 off, void *ext_buf)
 {
        struct mtdids *id = current_part->dev->id;
 
 #if defined(CONFIG_CMD_FLASH)
        if (id->type == MTD_DEV_TYPE_NOR)
-               return get_node_mem_nor(off);
+               return get_node_mem_nor(off, ext_buf);
 #endif
 
 #if defined(CONFIG_JFFS2_NAND) && \
     defined(CONFIG_CMD_NAND)
        if (id->type == MTD_DEV_TYPE_NAND)
-               return get_node_mem_nand(off);
+               return get_node_mem_nand(off, ext_buf);
 #endif
 
 #if defined(CONFIG_CMD_ONENAND)
        if (id->type == MTD_DEV_TYPE_ONENAND)
-               return get_node_mem_onenand(off);
+               return get_node_mem_onenand(off, ext_buf);
 #endif
 
        printf("get_node_mem: unknown device type, using raw offset!\n");
        return (void*)off;
 }
 
-static inline void put_fl_mem(void *buf)
+static inline void put_fl_mem(void *buf, void *ext_buf)
 {
        struct mtdids *id = current_part->dev->id;
 
+       /* If buf is the same as ext_buf, it was provided by the caller -
+          we shouldn't free it then. */
+       if (buf == ext_buf)
+               return;
        switch (id->type) {
 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
        case MTD_DEV_TYPE_NAND:
@@ -666,6 +672,7 @@ jffs2_free_cache(struct part_info *part)
                pL = (struct b_lists *)part->jffs2_priv;
                free_nodes(&pL->frag);
                free_nodes(&pL->dir);
+               free(pL->readbuf);
                free(pL);
        }
 }
@@ -712,7 +719,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
         */
        for (b = pL->frag.listHead; b != NULL; b = b->next) {
                jNode = (struct jffs2_raw_inode *) get_fl_mem(b->offset,
-                       sizeof(struct jffs2_raw_inode), NULL);
+                       sizeof(struct jffs2_raw_inode), pL->readbuf);
                if ((inode == jNode->ino)) {
                        /* get actual file length from the newest node */
                        if (jNode->version >= latestVersion) {
@@ -720,12 +727,13 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                                latestVersion = jNode->version;
                        }
                }
-               put_fl_mem(jNode);
+               put_fl_mem(jNode, pL->readbuf);
        }
 #endif
 
        for (b = pL->frag.listHead; b != NULL; b = b->next) {
-               jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset);
+               jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset,
+                                                               pL->readbuf);
                if ((inode == jNode->ino)) {
 #if 0
                        putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen);
@@ -752,11 +760,11 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                                src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode);
                                /* ignore data behind latest known EOF */
                                if (jNode->offset > totalSize) {
-                                       put_fl_mem(jNode);
+                                       put_fl_mem(jNode, pL->readbuf);
                                        continue;
                                }
                                if (!data_crc(jNode)) {
-                                       put_fl_mem(jNode);
+                                       put_fl_mem(jNode, pL->readbuf);
                                        continue;
                                }
 
@@ -797,7 +805,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                                default:
                                        /* unknown */
                                        putLabeledWord("UNKOWN COMPRESSION METHOD = ", jNode->compr);
-                                       put_fl_mem(jNode);
+                                       put_fl_mem(jNode, pL->readbuf);
                                        return -1;
                                        break;
                                }
@@ -809,7 +817,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
 #endif
                }
                counter++;
-               put_fl_mem(jNode);
+               put_fl_mem(jNode, pL->readbuf);
        }
 
 #if 0
@@ -835,12 +843,13 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
        counter = 0;
        /* we need to search all and return the inode with the highest version */
        for(b = pL->dir.listHead; b; b = b->next, counter++) {
-               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset);
+               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);
+                               put_fl_mem(jDir, pL->readbuf);
                                continue;
                        }
 
@@ -862,7 +871,7 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
                putLabeledWord("b = ", (u32) b);
                putLabeledWord("counter = ", counter);
 #endif
-               put_fl_mem(jDir);
+               put_fl_mem(jDir, pL->readbuf);
        }
        return inode;
 }
@@ -956,7 +965,8 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)
        struct jffs2_raw_dirent *jDir;
 
        for (b = pL->dir.listHead; b; b = b->next) {
-               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset);
+               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset,
+                                                               pL->readbuf);
                if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */
                        u32 i_version = 0;
                        struct jffs2_raw_inode ojNode;
@@ -969,20 +979,23 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)
                                if (jNode->ino == jDir->ino && jNode->version >= i_version) {
                                        i_version = jNode->version;
                                        if (i)
-                                               put_fl_mem(i);
+                                               put_fl_mem(i, NULL);
 
                                        if (jDir->type == DT_LNK)
-                                               i = get_node_mem(b2->offset);
+                                               i = get_node_mem(b2->offset,
+                                                                NULL);
                                        else
-                                               i = get_fl_mem(b2->offset, sizeof(*i), NULL);
+                                               i = get_fl_mem(b2->offset,
+                                                              sizeof(*i),
+                                                              NULL);
                                }
                                b2 = b2->next;
                        }
 
                        dump_inode(pL, jDir, i);
-                       put_fl_mem(i);
+                       put_fl_mem(i, NULL);
                }
-               put_fl_mem(jDir);
+               put_fl_mem(jDir, pL->readbuf);
        }
        return pino;
 }
@@ -1060,10 +1073,11 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
 
        /* we need to search all and return the inode with the highest version */
        for(b = pL->dir.listHead; b; b = b->next) {
-               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset);
+               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset,
+                                                               pL->readbuf);
                if (ino == jDir->ino) {
                        if (jDir->version < version) {
-                               put_fl_mem(jDir);
+                               put_fl_mem(jDir, pL->readbuf);
                                continue;
                        }
 
@@ -1080,7 +1094,7 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
                        jDirFoundPino = jDir->pino;
                        version = jDir->version;
                }
-               put_fl_mem(jDir);
+               put_fl_mem(jDir, pL->readbuf);
        }
        /* now we found the right entry again. (shoulda returned inode*) */
        if (jDirFoundType != DT_LNK)
@@ -1089,7 +1103,8 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
        /* it's a soft link so we follow it again. */
        b2 = pL->frag.listHead;
        while (b2) {
-               jNode = (struct jffs2_raw_inode *) get_node_mem(b2->offset);
+               jNode = (struct jffs2_raw_inode *) get_node_mem(b2->offset,
+                                                               pL->readbuf);
                if (jNode->ino == jDirFoundIno) {
                        src = (unsigned char *)jNode + sizeof(struct jffs2_raw_inode);
 
@@ -1101,11 +1116,11 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
 #endif
                        strncpy(tmp, (char *)src, jNode->dsize);
                        tmp[jNode->dsize] = '\0';
-                       put_fl_mem(jNode);
+                       put_fl_mem(jNode, pL->readbuf);
                        break;
                }
                b2 = b2->next;
-               put_fl_mem(jNode);
+               put_fl_mem(jNode, pL->readbuf);
        }
        /* ok so the name of the new file to find is in tmp */
        /* if it starts with a slash it is root based else shared dirs */
@@ -1240,7 +1255,8 @@ dump_dirents(struct b_lists *pL)
        putstr("\r\n\r\n******The directory Entries******\r\n");
        b = pL->dir.listHead;
        while (b) {
-               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset);
+               jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset,
+                                                               pL->readbuf);
                putstr("\r\n");
                putnstr(jDir->name, jDir->nsize);
                putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic);
@@ -1256,7 +1272,7 @@ dump_dirents(struct b_lists *pL)
                putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc);
                putLabeledWord("\tbuild_list: offset = ", b->offset);   /* FIXME: ? [RS] */
                b = b->next;
-               put_fl_mem(jDir);
+               put_fl_mem(jDir, pL->readbuf);
        }
 }
 #endif
@@ -1286,6 +1302,7 @@ jffs2_1pass_build_lists(struct part_info * part)
        u32 counter4 = 0;
        u32 counterF = 0;
        u32 counterN = 0;
+       u32 max_totlen = 0;
        u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE;
        char *buf;
 
@@ -1415,6 +1432,8 @@ jffs2_1pass_build_lists(struct part_info * part)
                                if (insert_node(&pL->frag, (u32) part->offset +
                                                ofs) == NULL)
                                        return 0;
+                               if (max_totlen < node->totlen)
+                                       max_totlen = node->totlen;
                                break;
                        case JFFS2_NODETYPE_DIRENT:
                                if (buf_ofs + buf_len < ofs + sizeof(struct
@@ -1440,6 +1459,8 @@ jffs2_1pass_build_lists(struct part_info * part)
                                if (insert_node(&pL->dir, (u32) part->offset +
                                                ofs) == NULL)
                                        return 0;
+                               if (max_totlen < node->totlen)
+                                       max_totlen = node->totlen;
                                counterN++;
                                break;
                        case JFFS2_NODETYPE_CLEANMARKER:
@@ -1468,6 +1489,13 @@ jffs2_1pass_build_lists(struct part_info * part)
 
        free(buf);
        putstr("\b\b done.\r\n");               /* close off the dots */
+
+       /* We don't care if malloc failed - then each read operation will
+        * allocate its own buffer as necessary (NAND) or will read directly
+        * from flash (NOR).
+        */
+       pL->readbuf = malloc(max_totlen);
+
        /* turn the lcd back on. */
        /* splash(); */
 
index 97457627c1573a6d8405655325ad3b44e854cc7d..3633deaaf83cc2b26e8e72c179e7a42dfa3ec192 100644 (file)
@@ -24,7 +24,7 @@ struct b_list {
 struct b_lists {
        struct b_list dir;
        struct b_list frag;
-
+       void *readbuf;
 };
 
 struct b_compr_info {