[U-Boot] [PATCH 3/6] jffs2: rewrite jffs2 scanning code based on Linux one

Ilya Yanok yanok at emcraft.com
Thu Nov 13 17:49:33 CET 2008


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 at emcraft.com>
Signed-off-by: Ilya Yanok <yanok at emcraft.com>
---
 fs/jffs2/jffs2_1pass.c |  227 ++++++++++++++++++++++++++++++++++++------------
 1 files changed, 171 insertions(+), 56 deletions(-)

diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c
index 35743fc..30a6dba 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(); */
-- 
1.5.6.1



More information about the U-Boot mailing list