JFFS2: Add useful fields into lists

The inode list uses version and ino, the dirent list uses version and pino.
This information is collected during scanning, reducing accesses to flash
and significantly speeding up ls and read.

Signed-off-by: Petr Borsodi <petr.borsodi@i.cz>
diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c
index 68db8c3..1115c86 100644
--- a/fs/jffs2/jffs2_1pass.c
+++ b/fs/jffs2/jffs2_1pass.c
@@ -549,7 +549,7 @@
 }
 
 static struct b_node *
-insert_node(struct b_list *list, u32 offset)
+insert_node(struct b_list *list)
 {
 	struct b_node *new;
 
@@ -557,7 +557,6 @@
 		putstr("add_node failed!\r\n");
 		return NULL;
 	}
-	new->offset = offset;
 	new->next = NULL;
 
 	if (list->listTail != NULL)
@@ -575,18 +574,7 @@
  */
 static int compare_inodes(struct b_node *new, struct b_node *old)
 {
-	/*
-	 * 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;
+	return new->version > old->version;
 }
 
 /* Sort directory entries so all entries in the same directory
@@ -683,7 +671,7 @@
 	uchar *src;
 	int i;
 	u32 counter = 0;
-#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
+
 	/* Find file size before loading any data, so fragments that
 	 * start past the end of file can be ignored. A fragment
 	 * that is partially in the file is loaded, so extra data may
@@ -691,35 +679,40 @@
 	 * This shouldn't cause trouble when loading kernel images, so
 	 * we will live with it.
 	 */
+	int latestOffset = -1;
 	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), pL->readbuf);
-		if ((inode == jNode->ino)) {
+		if (inode == b->ino) {
 			/* get actual file length from the newest node */
-			if (jNode->version >= latestVersion) {
-				totalSize = jNode->isize;
-				latestVersion = jNode->version;
+			if (b->version >= latestVersion) {
+				latestVersion = b->version;
+				latestOffset = b->offset;
 			}
 		}
+	}
+
+	if (latestOffset >= 0) {
+		jNode = (struct jffs2_raw_inode *)get_fl_mem(latestOffset,
+			sizeof(struct jffs2_raw_inode), pL->readbuf);
+		totalSize = jNode->isize;
 		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) {
-		/*
-		 * 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 (inode == b->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 0
 			putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen);
 			putLabeledWord("read_inode: inode = ", jNode->ino);
@@ -733,14 +726,6 @@
 			putLabeledWord("read_inode: flags = ", jNode->flags);
 #endif
 
-#ifndef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
-			/* get actual file length from the newest node */
-			if (jNode->version >= latestVersion) {
-				totalSize = jNode->isize;
-				latestVersion = jNode->version;
-			}
-#endif
-
 			if(dest) {
 				/*
 				 * Now that the inode has been checked,
@@ -804,9 +789,9 @@
 #if 0
 			putLabeledWord("read_inode: totalSize = ", totalSize);
 #endif
+			put_fl_mem(jNode, pL->readbuf);
 		}
 		counter++;
-		put_fl_mem(jNode, pL->readbuf);
 	}
 
 #if 0
@@ -953,13 +938,14 @@
 	struct jffs2_raw_dirent *jDir;
 
 	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) {
+		if (pino == b->pino) {
 			u32 i_version = 0;
-			struct jffs2_raw_inode *jNode, *i = NULL;
+			int i_offset = -1;
+			struct jffs2_raw_inode *jNode = NULL;
 			struct b_node *b2;
 
+			jDir = (struct jffs2_raw_dirent *)
+				get_node_mem(b->offset, pL->readbuf);
 #ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
 			/* Check for more recent versions of this file */
 			int match;
@@ -991,30 +977,27 @@
 			}
 
 			for (b2 = pL->frag.listHead; b2; b2 = b2->next) {
-				jNode = (struct jffs2_raw_inode *)
-					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);
-
-					if (jDir->type == DT_LNK)
-						i = get_node_mem(b2->offset,
-								 NULL);
-					else
-						i = get_fl_mem(b2->offset,
-							       sizeof(*i),
-							       NULL);
+				if (b2->ino == jDir->ino &&
+				    b2->version >= i_version) {
+					i_version = b2->version;
+					i_offset = b2->offset;
 				}
-				put_fl_mem(jNode, NULL);
 			}
 
-			dump_inode(pL, jDir, i);
-			put_fl_mem(i, NULL);
+			if (i_version >= 0) {
+				if (jDir->type == DT_LNK)
+					jNode = get_node_mem(i_offset, NULL);
+				else
+					jNode = get_fl_mem(i_offset,
+							   sizeof(*jNode),
+							   NULL);
+			}
+
+			dump_inode(pL, jDir, jNode);
+			put_fl_mem(jNode, NULL);
+
+			put_fl_mem(jDir, pL->readbuf);
 		}
-		put_fl_mem(jDir, pL->readbuf);
 	}
 	return pino;
 }
@@ -1266,7 +1249,7 @@
 {
 	void *sp;
 	int i, pass;
-	void *ret;
+	struct b_node *b;
 
 	for (pass = 0; pass < 2; pass++) {
 		sp = summary->sum;
@@ -1281,13 +1264,17 @@
 					if (pass) {
 						spi = sp;
 
-						ret = insert_node(&pL->frag,
-							(u32)part->offset +
+						b = insert_node(&pL->frag);
+						if (!b)
+							return -1;
+						b->offset = (u32)part->offset +
 							offset +
 							sum_get_unaligned32(
-								&spi->offset));
-						if (ret == NULL)
-							return -1;
+								&spi->offset);
+						b->version = sum_get_unaligned32(
+							&spi->version);
+						b->ino = sum_get_unaligned32(
+							&spi->inode);
 					}
 
 					sp += JFFS2_SUMMARY_INODE_SIZE;
@@ -1298,13 +1285,17 @@
 					struct jffs2_sum_dirent_flash *spd;
 					spd = sp;
 					if (pass) {
-						ret = insert_node(&pL->dir,
-							(u32) part->offset +
+						b = insert_node(&pL->dir);
+						if (!b)
+							return -1;
+						b->offset = (u32)part->offset +
 							offset +
 							sum_get_unaligned32(
-								&spd->offset));
-						if (ret == NULL)
-							return -1;
+								&spd->offset);
+						b->version = sum_get_unaligned32(
+							&spd->version);
+						b->pino = sum_get_unaligned32(
+							&spd->pino);
 					}
 
 					sp += JFFS2_SUMMARY_DIRENT_SIZE(
@@ -1508,6 +1499,7 @@
 		/* Indicates a sector with a CLEANMARKER was found */
 		int clean_sector = 0;
 		struct jffs2_unknown_node crcnode;
+		struct b_node *b;
 
 		/* Set buf_size to maximum length */
 		buf_size = DEFAULT_EMPTY_SCAN_SIZE;
@@ -1715,12 +1707,15 @@
 				if (!inode_crc((struct jffs2_raw_inode *)node))
 					break;
 
-				if (insert_node(&pL->frag, (u32) part->offset +
-						ofs) == NULL) {
+				b = insert_node(&pL->frag);
+				if (!b) {
 					free(buf);
 					jffs2_free_cache(part);
 					return 0;
 				}
+				b->offset = (u32)part->offset + ofs;
+				b->version = node->i.version;
+				b->ino = node->i.ino;
 				if (max_totlen < node->u.totlen)
 					max_totlen = node->u.totlen;
 				break;
@@ -1750,12 +1745,15 @@
 					break;
 				if (! (counterN%100))
 					puts ("\b\b.  ");
-				if (insert_node(&pL->dir, (u32) part->offset +
-						ofs) == NULL) {
+				b = insert_node(&pL->dir);
+				if (!b) {
 					free(buf);
 					jffs2_free_cache(part);
 					return 0;
 				}
+				b->offset = (u32)part->offset + ofs;
+				b->version = node->d.version;
+				b->pino = node->d.pino;
 				if (max_totlen < node->u.totlen)
 					max_totlen = node->u.totlen;
 				counterN++;
diff --git a/fs/jffs2/jffs2_private.h b/fs/jffs2/jffs2_private.h
index 06b6ca2..65d19a7 100644
--- a/fs/jffs2/jffs2_private.h
+++ b/fs/jffs2/jffs2_private.h
@@ -8,6 +8,11 @@
 	u32 offset;
 	struct b_node *next;
 	enum { CRC_UNKNOWN = 0, CRC_OK, CRC_BAD } datacrc;
+	u32 version;
+	union {
+		u32 ino; /* for inodes */
+		u32 pino; /* for dirents */
+	};
 };
 
 struct b_list {