jffs2: rewrite jffs2 scanning code based on Linux one
authorIlya Yanok <yanok@emcraft.com>
Thu, 13 Nov 2008 16:49:33 +0000 (19:49 +0300)
committerWolfgang Denk <wd@denx.de>
Tue, 9 Dec 2008 22:39:16 +0000 (23:39 +0100)
Rewrites jffs2_1pass_build_lists() function in style of Linux's
jffs2_scan_medium() and jffs2_scan_eraseblock().
This includes:
 - Caching flash acceses
 - Smart dealing with free space

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

index 35743fc2f5f4958cb1cb59a528cb8d692e260e32..30a6dba6e00f6c0026adcd3c48b9e8f89f0add24 100644 (file)
@@ -389,6 +389,12 @@ static inline void *get_fl_mem_nor(u32 off)
        return (void*)addr;
 }
 
+static inline void *get_fl_mem_nor_copy(u32 off, u32 size, void *ext_buf)
+{
+       memcpy(ext_buf, get_fl_mem_nor(off), size);
+       return ext_buf;
+}
+
 static inline void *get_node_mem_nor(u32 off)
 {
        return (void*)get_fl_mem_nor(off);
@@ -405,8 +411,11 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
        struct mtdids *id = current_part->dev->id;
 
 #if defined(CONFIG_CMD_FLASH)
-       if (id->type == MTD_DEV_TYPE_NOR)
+       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);
+       }
 #endif
 
 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
@@ -478,9 +487,6 @@ static char *compr_names[] = {
 #endif
 };
 
-/* Spinning wheel */
-static char spinner[] = { '|', '/', '-', '\\' };
-
 /* Memory management */
 struct mem_block {
        u32     index;
@@ -651,23 +657,6 @@ static int compare_dirents(struct b_node *new, struct b_node *old)
 }
 #endif
 
-static u32
-jffs2_scan_empty(u32 start_offset, struct part_info *part)
-{
-       char *max = (char *)(part->offset + part->size - sizeof(struct jffs2_raw_inode));
-       char *offset = (char *)(part->offset + start_offset);
-       u32 off;
-
-       while (offset < max &&
-              *(u32*)get_fl_mem((u32)offset, sizeof(u32), &off) == 0xFFFFFFFF) {
-               offset += sizeof(u32);
-               /* return if spinning is due */
-               if (((u32)offset & ((1 << SPIN_BLKSIZE)-1)) == 0) break;
-       }
-
-       return (u32)offset - part->offset;
-}
-
 void
 jffs2_free_cache(struct part_info *part)
 {
@@ -766,6 +755,10 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                                        put_fl_mem(jNode);
                                        continue;
                                }
+                               if (!data_crc(jNode)) {
+                                       put_fl_mem(jNode);
+                                       continue;
+                               }
 
                                lDest = (uchar *) (dest + jNode->offset);
 #if 0
@@ -1268,17 +1261,33 @@ dump_dirents(struct b_lists *pL)
 }
 #endif
 
+#define min_t(type, x, y) ({                    \
+       type __min1 = (x);                      \
+       type __min2 = (y);                      \
+       __min1 < __min2 ? __min1: __min2; })
+
+#define DEFAULT_EMPTY_SCAN_SIZE        4096
+
+static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size)
+{
+       if (sector_size < DEFAULT_EMPTY_SCAN_SIZE)
+               return sector_size;
+       else
+               return DEFAULT_EMPTY_SCAN_SIZE;
+}
+
 static u32
 jffs2_1pass_build_lists(struct part_info * part)
 {
        struct b_lists *pL;
        struct jffs2_unknown_node *node;
-       u32 offset, oldoffset = 0;
-       u32 max = part->size - sizeof(struct jffs2_raw_inode);
-       u32 counter = 0;
+       u32 nr_sectors = part->size/part->sector_size;
+       u32 i;
        u32 counter4 = 0;
        u32 counterF = 0;
        u32 counterN = 0;
+       u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE;
+       char *buf;
 
        /* turn off the lcd.  Refreshing the lcd adds 50% overhead to the */
        /* jffs2 list building enterprise nope.  in newer versions the overhead is */
@@ -1288,70 +1297,176 @@ jffs2_1pass_build_lists(struct part_info * part)
        /* if we are building a list we need to refresh the cache. */
        jffs_init_1pass_list(part);
        pL = (struct b_lists *)part->jffs2_priv;
-       offset = 0;
+       buf = malloc(buf_size);
        puts ("Scanning JFFS2 FS:   ");
 
        /* start at the beginning of the partition */
-       while (offset < max) {
-               if ((oldoffset >> SPIN_BLKSIZE) != (offset >> SPIN_BLKSIZE)) {
-                       printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]);
-                       oldoffset = offset;
-               }
+       for (i = 0; i < nr_sectors; i++) {
+               uint32_t sector_ofs = i * part->sector_size;
+               uint32_t buf_ofs = sector_ofs;
+               uint32_t buf_len = EMPTY_SCAN_SIZE(part->sector_size);
+               uint32_t ofs, prevofs;
 
                WATCHDOG_RESET();
+               get_fl_mem((u32)part->offset + buf_ofs, buf_len, buf);
 
-               node = (struct jffs2_unknown_node *) get_node_mem((u32)part->offset + offset);
-               if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) {
+               /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+               ofs = 0;
+
+               /* Scan only 4KiB of 0xFF before declaring it's empty */
+               while (ofs < EMPTY_SCAN_SIZE(part->sector_size) &&
+                               *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
+                       ofs += 4;
+
+               if (ofs == EMPTY_SCAN_SIZE(part->sector_size))
+                       continue;
+
+               ofs += sector_ofs;
+               prevofs = ofs - 1;
+
+       scan_more:
+               while (ofs < sector_ofs + part->sector_size) {
+                       if (ofs == prevofs) {
+                               printf("offset %08x already seen, skip\n", ofs);
+                               ofs += 4;
+                               counter4++;
+                               continue;
+                       }
+                       prevofs = ofs;
+                       if (sector_ofs + part->sector_size <
+                                       ofs + sizeof(*node))
+                               break;
+                       if (buf_ofs + buf_len < ofs + sizeof(*node)) {
+                               buf_len = min_t(uint32_t, buf_size, sector_ofs
+                                               + part->sector_size - ofs);
+                               get_fl_mem((u32)part->offset + ofs, buf_len,
+                                          buf);
+                               buf_ofs = ofs;
+                       }
+
+                       node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
+
+                       if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
+                               uint32_t inbuf_ofs;
+                               uint32_t empty_start, scan_end;
+
+                               empty_start = ofs;
+                               ofs += 4;
+                               scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(
+                                                       part->sector_size)/8,
+                                                       buf_len);
+                       more_empty:
+                               inbuf_ofs = ofs - buf_ofs;
+                               while (inbuf_ofs < scan_end) {
+                                       if (*(uint32_t *)(&buf[inbuf_ofs]) !=
+                                                       0xffffffff)
+                                               goto scan_more;
+
+                                       inbuf_ofs += 4;
+                                       ofs += 4;
+                               }
+                               /* Ran off end. */
+
+                               /* See how much more there is to read in this
+                                * eraseblock...
+                                */
+                               buf_len = min_t(uint32_t, buf_size,
+                                               sector_ofs +
+                                               part->sector_size - ofs);
+                               if (!buf_len) {
+                                       /* No more to read. Break out of main
+                                        * loop without marking this range of
+                                        * empty space as dirty (because it's
+                                        * not)
+                                        */
+                                       break;
+                               }
+                               scan_end = buf_len;
+                               get_fl_mem((u32)part->offset + ofs, buf_len,
+                                          buf);
+                               buf_ofs = ofs;
+                               goto more_empty;
+                       }
+                       if (node->magic != JFFS2_MAGIC_BITMASK ||
+                                       !hdr_crc(node)) {
+                               ofs += 4;
+                               counter4++;
+                               continue;
+                       }
+                       if (ofs + node->totlen >
+                                       sector_ofs + part->sector_size) {
+                               ofs += 4;
+                               counter4++;
+                               continue;
+                       }
                        /* if its a fragment add it */
-                       if (node->nodetype == JFFS2_NODETYPE_INODE &&
-                                   inode_crc((struct jffs2_raw_inode *) node) &&
-                                   data_crc((struct jffs2_raw_inode *) node)) {
+                       switch (node->nodetype) {
+                       case JFFS2_NODETYPE_INODE:
+                               if (buf_ofs + buf_len < ofs + sizeof(struct
+                                                       jffs2_raw_inode)) {
+                                       get_fl_mem((u32)part->offset + ofs,
+                                                  buf_len, buf);
+                                       buf_ofs = ofs;
+                                       node = (void *)buf;
+                               }
+                               if (!inode_crc((struct jffs2_raw_inode *) node))
+                                      break;
+
                                if (insert_node(&pL->frag, (u32) part->offset +
-                                               offset) == NULL) {
-                                       put_fl_mem(node);
+                                               ofs) == NULL)
                                        return 0;
+                               break;
+                       case JFFS2_NODETYPE_DIRENT:
+                               if (buf_ofs + buf_len < ofs + sizeof(struct
+                                                       jffs2_raw_dirent) +
+                                                       ((struct
+                                                        jffs2_raw_dirent *)
+                                                       node)->nsize) {
+                                       get_fl_mem((u32)part->offset + ofs,
+                                                  buf_len, buf);
+                                       buf_ofs = ofs;
+                                       node = (void *)buf;
                                }
-                       } else if (node->nodetype == JFFS2_NODETYPE_DIRENT &&
-                                  dirent_crc((struct jffs2_raw_dirent *) node)  &&
-                                  dirent_name_crc((struct jffs2_raw_dirent *) node)) {
+
+                               if (!dirent_crc((struct jffs2_raw_dirent *)
+                                                       node) ||
+                                               !dirent_name_crc(
+                                                       (struct
+                                                        jffs2_raw_dirent *)
+                                                       node))
+                                       break;
                                if (! (counterN%100))
                                        puts ("\b\b.  ");
                                if (insert_node(&pL->dir, (u32) part->offset +
-                                               offset) == NULL) {
-                                       put_fl_mem(node);
+                                               ofs) == NULL)
                                        return 0;
-                               }
                                counterN++;
-                       } else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) {
+                               break;
+                       case JFFS2_NODETYPE_CLEANMARKER:
                                if (node->totlen != sizeof(struct jffs2_unknown_node))
                                        printf("OOPS Cleanmarker has bad size "
                                                "%d != %zu\n",
                                                node->totlen,
                                                sizeof(struct jffs2_unknown_node));
-                       } else if (node->nodetype == JFFS2_NODETYPE_PADDING) {
+                               break;
+                       case JFFS2_NODETYPE_PADDING:
                                if (node->totlen < sizeof(struct jffs2_unknown_node))
                                        printf("OOPS Padding has bad size "
                                                "%d < %zu\n",
                                                node->totlen,
                                                sizeof(struct jffs2_unknown_node));
-                       } else {
+                               break;
+                       default:
                                printf("Unknown node type: %x len %d offset 0x%x\n",
                                        node->nodetype,
-                                       node->totlen, offset);
+                                       node->totlen, ofs);
                        }
-                       offset += ((node->totlen + 3) & ~3);
+                       ofs += ((node->totlen + 3) & ~3);
                        counterF++;
-               } else if (node->magic == JFFS2_EMPTY_BITMASK &&
-                          node->nodetype == JFFS2_EMPTY_BITMASK) {
-                       offset = jffs2_scan_empty(offset, part);
-               } else {        /* if we know nothing, we just step and look. */
-                       offset += 4;
-                       counter4++;
                }
-/*             printf("unknown node magic %4.4x %4.4x @ %lx\n", node->magic, node->nodetype, (unsigned long)node); */
-               put_fl_mem(node);
        }
 
+       free(buf);
        putstr("\b\b done.\r\n");               /* close off the dots */
        /* turn the lcd back on. */
        /* splash(); */