summaryrefslogtreecommitdiff
path: root/fs/jffs2
diff options
context:
space:
mode:
authorIlya Yanok <yanok@emcraft.com>2008-11-13 19:49:33 +0300
committerWolfgang Denk <wd@denx.de>2008-12-09 23:39:16 +0100
commit8a36d31f72411144ac0412ee7e1880e801acd754 (patch)
treefa9b97e79a48ca7cff5bc729230a67f796e25c4b /fs/jffs2
parente0b5532579eda8b4629f1b4f6e49c3cc60f52237 (diff)
jffs2: rewrite jffs2 scanning code based on Linux one
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>
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/jffs2_1pass.c227
1 files changed, 171 insertions, 56 deletions
diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c
index 35743fc2f5f..30a6dba6e00 100644
--- a/fs/jffs2/jffs2_1pass.c
+++ b/fs/jffs2/jffs2_1pass.c
@@ -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(); */