[U-Boot-Users] [PATCH] JFFS2 bugfixes and code cleanup

kai-uwe.bloem at auerswald.de kai-uwe.bloem at auerswald.de
Wed Mar 12 14:38:14 CET 2003


Here's a rather large patch for the jffs2 code. Besides a lot of general cleanup work, it fixes 3 bugs:

- the memory mangement was broken. It caused havoc on malloc by writing beyond the block boundaries.
- the length calculation for files was wrong, sometimes resulting in short file reads.
- data copying now optionally takes fragment version numbers into account, to avoid copying from older
data.

The last fix is optional, as it involves sorting the fragment list, which takes up a rather long time during the initial file system scan.
With a well prepared readonly root, this is not necessary and can be turned off for a decent speedup. Read the comment in doc/README.JFFS2 for more.

For interested persons there's a comment about the changes in fs/jffs2/jffs2_1pass.c

Regards,
--
Kai-Uwe Bloem
Gesellschaft für Datensysteme
kai-uwe.bloem at auerswald.de


--- /home/kub/tmp/u-boot/doc/README.JFFS2	Sun Nov  3 01:32:21 2002
+++ doc/README.JFFS2	Wed Mar 12 12:00:57 2003
                
 fsinfo  - print information about file systems
 ls      - list files in a directory
 
+If you boot from a partition which is mounted writable, and you
+update your boot environment by replacing single files on that
+partition, you should also define CFG_JFFS2_SORT_FRAGMENTS. Scanning
+the JFFS2 filesystem takes *much* longer with this feature, though.
+Sorting is done while inserting into the fragment list, which is
+more or less a bubble sort. That algorithm is known to be O(n^2),
+thus you should really consider if you can avoid it!
+
 
 There is two ways for JFFS2 to find the disk. The default way uses
 the flash_info structure to find the start of a JFFS2 disk (called
--- /home/kub/tmp/u-boot/fs/jffs2/jffs2_1pass.c	Sun Nov  3 01:53:59 2002
+++ fs/jffs2/jffs2_1pass.c	Wed Mar 12 12:19:04 2003
               
+/* vi: set sw=4 ts=4: */
 /*
 -------------------------------------------------------------------------
  * Filename:      jffs2.c
                  
  *
  */
 
+/*
+ * Bugfixing by Kai-Uwe Bloem <kai-uwe.bloem at auerswald.de>, (C) Mar/2003
+ *
+ * - overhaul of the memory management. Removed much of the "paper-bagging"
+ *   in that part of the code, fixed several bugs, now frees memory when
+ *   partition is changed.
+ *   It's still ugly :-(
+ * - fixed a bug in jffs2_1pass_read_inode where the file length calculation
+ *   was incorrect. Removed a bit of the paper-bagging as well.
+ * - removed double crc calculation for fragment headers in jffs2_private.h
+ *   for speedup.
+ * - scan_empty rewritten in a more "standard" manner (non-paperbag, that is).
+ * - spinning wheel now spins depending on how much memory has been scanned
+ * - lots of small changes all over the place to "improve" readability.
+ * - implemented fragment sorting to ensure that the newest data is copied
+ *   if there are multiple copies of fragments for a certain file offset.
+ *
+ * The fragment sorting feature must be enabled by CFG_JFFS2_SORT_FRAGMENTS.
+ * Sorting is done while adding fragments to the lists, which is more or less a
+ * bubble sort. This takes a lot of time, and is most probably not an issue if
+ * the boot filesystem is always mounted readonly.
+ *
+ * You should define it if the boot filesystem is mounted writable, and updates
+ * to the boot files are done by copying files to that filesystem.
+ *
+ *
+ * There's a big issue left: endianess is completely ignored in this code. Duh!
+ *
+ *
+ * You still should have paper bags at hand :-(. The code lacks more or less
+ * any comment, and is still arcane and difficult to read in places. As this
+ * is incompatible with any new code from the jffs2 maintainers anyway, it
+ * should probably be dumped and replaced by something like jffs2reader!
+ */
+
+
 #include <common.h>
 #include <config.h>
 #include <malloc.h>
                      
 
 #include "jffs2_private.h"
 
-/* Compression names */
-static char *compr_names[] = {
-        "NONE",
-        "ZERO",
-        "RTIME",
-        "RUBINMIPS",
-        "COPY",
-        "DYNRUBIN",
-        "ZLIB" };
 
-static char spinner[] = { '|', '\\', '-', '/' };
+#define	NODE_CHUNK  	1024	/* size of memory allocation chunk in b_nodes */
+#define	SPIN_BLKSIZE	18  	/* spin after having scanned 1<<BLKSIZE bytes */
+
+/* Debugging switches */
+#undef	DEBUG_DIRENTS		/* print directory entry list after scan */
+#undef	DEBUG_FRAGMENTS		/* print fragment list after scan */
+#undef	DEBUG   			/* enable debugging messages */
+
 
-#define DEBUG
 #ifdef  DEBUG
 # define DEBUGF(fmt,args...)	printf(fmt ,##args)
 #else
 # define DEBUGF(fmt,args...)
 #endif
 
-#define MALLOC_CHUNK (10*1024)
 
+/* Compression names */
+static char *compr_names[] = {
+	"NONE",
+	"ZERO",
+	"RTIME",
+	"RUBINMIPS",
+	"COPY",
+	"DYNRUBIN",
+	"ZLIB"
+};
+
+/* Spinning wheel */
+static char spinner[] = { '|', '/', '-', '\\' };
+
+/* Memory management */
+struct mem_block {
+	u32	index;
+	struct mem_block *next;
+	struct b_node nodes[NODE_CHUNK];
+};
+
+
+static void
+free_nodes(struct b_list *list)
+{
+	while (list->listMemBase != NULL) {
+		struct mem_block *next = list->listMemBase->next;
+		free( list->listMemBase );
+		list->listMemBase = next;
+	}
+}
 
 static struct b_node *
-add_node(struct b_node *tail, u32 * count, u32 * memBase)
+add_node(struct b_list *list)
 {
-	u32 index;
-	u32 memLimit;
+	u32 index = 0;
+	struct mem_block *memBase;
 	struct b_node *b;
 
-	index = (*count) * sizeof(struct b_node) % MALLOC_CHUNK;
-	memLimit = MALLOC_CHUNK;
-
+	memBase = list->listMemBase;
+	if (memBase != NULL)
+		index = memBase->index;
 #if 0
 	putLabeledWord("add_node: index = ", index);
-	putLabeledWord("add_node: memLimit = ", memLimit);
-	putLabeledWord("add_node: memBase = ", *memBase);
+	putLabeledWord("add_node: memBase = ", list->listMemBase);
 #endif
 
-	/* we need not keep a list of bases since we'll never free the */
-	/* memory, just jump the the kernel */
-	if ((index == 0) || (index > memLimit)) {	/* we need mode space before we continue */
-		if ((*memBase = (u32) mmalloc(MALLOC_CHUNK)) == (u32) NULL) {
+	if (memBase == NULL || index >= NODE_CHUNK) {
+		/* we need more space before we continue */
+		memBase = mmalloc(sizeof(struct mem_block));
+		if (memBase == NULL) {
 			putstr("add_node: malloc failed\n");
 			return NULL;
 		}
+		memBase->next = list->listMemBase;
+		index = 0;
 #if 0
 		putLabeledWord("add_node: alloced a new membase at ", *memBase);
 #endif
 
 	}
 	/* now we have room to add it. */
-	b = (struct b_node *) (*memBase + index);
+	b = &memBase->nodes[index];
+	index ++;
 
-	/* null on first call */
-	if (tail)
-		tail->next = b;
-
-#if 0
-	putLabeledWord("add_node: tail = ", (u32) tail);
-	if (tail)
-		putLabeledWord("add_node: tail->next = ", (u32) tail->next);
+	memBase->index = index;
+	list->listMemBase = memBase;
+	list->listCount++;
+	return b;
+}
 
+static struct b_node *
+insert_node(struct b_list *list, u32 offset)
+{
+	struct b_node *new;
+#ifdef CFG_JFFS2_SORT_FRAGMENTS
+	struct b_node *b, *prev;
 #endif
 
-#if 0
-	putLabeledWord("add_node: mb+i = ", (u32) (*memBase + index));
-	putLabeledWord("add_node: b = ", (u32) b);
+	if (!(new = add_node(list))) {
+		putstr("add_node failed!\r\n");
+		return NULL;
+	}
+	new->offset = offset;
+
+#ifdef CFG_JFFS2_SORT_FRAGMENTS
+	if (list->listTail != NULL && list->listCompare(new, list->listTail))
+		prev = list->listTail;
+	else if (list->listLast != NULL && list->listCompare(new, list->listLast))
+		prev = list->listLast;
+	else
+		prev = NULL;
+
+	for (b = (prev ? prev->next : list->listHead);
+	     b != NULL && list->listCompare(new, b);
+	     prev = b, b = b->next) {
+		list->listLoops++;
+	}
+	if (b != NULL)
+		list->listLast = prev;
+
+	if (b != NULL) {
+		new->next = b;
+		if (prev != NULL)
+			prev->next = new;
+		else
+			list->listHead = new;
+	} else
 #endif
-	(*count)++;
-	b->next = (struct b_node *) NULL;
-	return b;
+	{
+		new->next = (struct b_node *) NULL;
+		if (list->listTail != NULL) {
+			list->listTail->next = new;
+			list->listTail = new;
+		} else {
+			list->listTail = list->listHead = new;
+		}
+	}
 
+	return new;
 }
 
-/* we know we have empties at the start offset so we will hop */
-/* t points that would be non F if there were a node here to speed this up. */
-struct jffs2_empty_node {
-	u32 first;
-	u32 second;
-};
+#ifdef CFG_JFFS2_SORT_FRAGMENTS
+static int compare_inodes(struct b_node *new, struct b_node *old)
+{
+	struct jffs2_raw_inode *jNew = (struct jffs2_raw_inode *)new->offset;
+	struct jffs2_raw_inode *jOld = (struct jffs2_raw_inode *)old->offset;
+
+	return jNew->version < jOld->version;
+}
+
+static int compare_dirents(struct b_node *new, struct b_node *old)
+{
+	struct jffs2_raw_dirent *jNew = (struct jffs2_raw_dirent *)new->offset;
+	struct jffs2_raw_dirent *jOld = (struct jffs2_raw_dirent *)old->offset;
+
+	return jNew->version > jOld->version;
+}
+#endif
 
 static u32
 jffs2_scan_empty(u32 start_offset, struct part_info *part)
 {
-	u32 max = part->size - sizeof(struct jffs2_raw_inode);
-
-	/* this would be either dir node_crc or frag isize */
-	u32 offset = start_offset + 32;
-	struct jffs2_empty_node *node;
+	char *max = part->offset + part->size - sizeof(struct jffs2_raw_inode);
+	char *offset = part->offset + start_offset;
 
-	start_offset += 4;
-	while (offset < max) {
-		node = (struct jffs2_empty_node *) (part->offset + offset);
-		if ((node->first == 0xFFFFFFFF) && (node->second == 0xFFFFFFFF)) {
-			/* we presume that there were no nodes in between and advance in a hop */
-			/* putLabeledWord("\t\tjffs2_scan_empty: empty at offset=",offset); */
-			start_offset = offset + 4;
-			offset = start_offset + 32;	/* orig 32 + 4 bytes for the second==0xfffff */
-		} else {
-			return start_offset;
-		}
+	while (offset < max && *(u32 *)offset == 0xFFFFFFFF) {
+		offset += sizeof(u32);
+		/* return if spinning is due */
+		if (((u32)offset & ((1 << SPIN_BLKSIZE)-1)) == 0) break;
 	}
-	return start_offset;
+
+	return offset - part->offset;
 }
 
 static u32
 jffs_init_1pass_list(struct part_info *part)
 {
-	if ( 0 != ( part->jffs2_priv=malloc(sizeof(struct b_lists)))){
-		struct b_lists *pL =(struct b_lists *)part->jffs2_priv;
+	struct b_lists *pL;
 
-		pL->dirListHead = pL->dirListTail = NULL;
-		pL->fragListHead = pL->fragListTail = NULL;
-		pL->dirListCount = 0;
-		pL->dirListMemBase = 0;
-		pL->fragListCount = 0;
-		pL->fragListMemBase = 0;
-		pL->partOffset = 0x0;
+	if (part->jffs2_priv != NULL) {
+		pL = (struct b_lists *)part->jffs2_priv;
+		free_nodes(&pL->frag);
+		free_nodes(&pL->dir);
+		free(pL);
+	}
+	if (NULL != (part->jffs2_priv = malloc(sizeof(struct b_lists)))) {
+		pL = (struct b_lists *)part->jffs2_priv;
+
+		memset(pL, 0, sizeof(*pL));
+#ifdef CFG_JFFS2_SORT_FRAGMENTS
+		pL->dir.listCompare = compare_dirents;
+		pL->frag.listCompare = compare_inodes;
+#endif
 	}
 	return 0;
 }
                     
 {
 	struct b_node *b;
 	struct jffs2_raw_inode *jNode;
-	u32 totalSize = 1;
-	u32 oldTotalSize = 0;
-	u32 size = 0;
-	char *lDest = (char *) dest;
+	u32 totalSize = 0;
+	u16 latestVersion = 0;
+	char *lDest;
 	char *src;
 	long ret;
 	int i;
 	u32 counter = 0;
-	char totalSizeSet = 0;
 
-#if 0
-	b = pL->fragListHead;
-	while (b) {
+	for (b = pL->frag.listHead; b != NULL; b = b->next) {
 		jNode = (struct jffs2_raw_inode *) (b->offset);
 		if ((inode == jNode->ino)) {
+#if 0
 			putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen);
 			putLabeledWord("read_inode: inode = ", jNode->ino);
 			putLabeledWord("read_inode: version = ", jNode->version);
                     
 			putLabeledWord("read_inode: compr = ", jNode->compr);
 			putLabeledWord("read_inode: usercompr = ", jNode->usercompr);
 			putLabeledWord("read_inode: flags = ", jNode->flags);
-		}
-
-		b = b->next;
-	}
-
 #endif
-
-#if 1
-	b = pL->fragListHead;
-	while (b && (size < totalSize)) {
-		jNode = (struct jffs2_raw_inode *) (b->offset);
-		if ((inode == jNode->ino)) {
-			if ((jNode->isize == oldTotalSize) && (jNode->isize > totalSize)) {
-				/* 2 consecutive isizes indicate file length */
+			/* get actual file length from the newest node */
+			if (jNode->version >= latestVersion) {
 				totalSize = jNode->isize;
-				totalSizeSet = 1;
-			} else if (!totalSizeSet) {
-				totalSize = size + jNode->dsize + 1;
+				latestVersion = jNode->version;
 			}
-			oldTotalSize = jNode->isize;
 
 			if(dest) {
 				src = ((char *) jNode) + sizeof(struct jffs2_raw_inode);
-				/* lDest = (char *) (dest + (jNode->offset & ~3)); */
+				/* ignore data behind latest known EOF */
+				if (jNode->offset > totalSize)
+					continue;
+
 				lDest = (char *) (dest + jNode->offset);
 #if 0
-				putLabeledWord("\r\n\r\nread_inode: src = ", src);
+				putLabeledWord("read_inode: src = ", src);
 				putLabeledWord("read_inode: dest = ", lDest);
-				putLabeledWord("read_inode: dsize = ", jNode->dsize);
-				putLabeledWord("read_inode: csize = ", jNode->csize);
-				putLabeledWord("read_inode: version = ", jNode->version);
-				putLabeledWord("read_inode: isize = ", jNode->isize);
-				putLabeledWord("read_inode: offset = ", jNode->offset);
-				putLabeledWord("read_inode: compr = ", jNode->compr);
-				putLabeledWord("read_inode: flags = ", jNode->flags);
 #endif
 				switch (jNode->compr) {
 				case JFFS2_COMPR_NONE:
-#if 0
-					{
-						int i;
-
-						if ((dest > 0xc0092ff0) && (dest < 0xc0093000))
-							for (i = 0; i < first->length; i++) {
-								putLabeledWord("\tCOMPR_NONE: src =", src + i);
-								putLabeledWord("\tCOMPR_NONE: length =", first->length);
-								putLabeledWord("\tCOMPR_NONE: dest =", dest + i);
-								putLabeledWord("\tCOMPR_NONE: data =", (unsigned char) *(src + i));
-							}
-					}
-#endif
-
 					ret = (unsigned long) ldr_memcpy(lDest, src, jNode->dsize);
 					break;
 				case JFFS2_COMPR_ZERO:
                     
 				}
 			}
 
-			size += jNode->dsize;
 #if 0
-			putLabeledWord("read_inode: size = ", size);
 			putLabeledWord("read_inode: totalSize = ", totalSize);
 			putLabeledWord("read_inode: compr ret = ", ret);
 #endif
 		}
-		b = b->next;
 		counter++;
 	}
-#endif
 
 #if 0
-	putLabeledWord("read_inode: returning = ", size);
+	putLabeledWord("read_inode: returning = ", totalSize);
 #endif
-	return size;
+	return totalSize;
 }
 
 /* find the inode from the slashless name given a parent */
                     
 
 	counter = 0;
 	/* we need to search all and return the inode with the highest version */
-	for(b = pL->dirListHead;b;b=b->next,counter++) {
+	for(b = pL->dir.listHead; b; b = b->next, counter++) {
 		jDir = (struct jffs2_raw_dirent *) (b->offset);
-		if ((pino == jDir->pino) && (len == jDir->nsize) && (jDir->ino) &&	/* 0 for unlink */
+		if ((pino == jDir->pino) && (len == jDir->nsize) &&
+		    (jDir->ino) &&	/* 0 for unlink */
 		    (!strncmp(jDir->name, name, len))) {	/* a match */
 			if (jDir->version < version) continue;
 
-		        if(jDir->version==0) {
+		        if(jDir->version == 0) {
 			    	/* Is this legal? */
 				putstr(" ** WARNING ** ");
 				putnstr(jDir->name, jDir->nsize);
 				putstr(" is version 0 (in find, ignoring)\r\n");
-			} else if(jDir->version==version) {
+			} else if(jDir->version == version) {
 			    	/* Im pretty sure this isn't ... */
 				putstr(" ** ERROR ** ");
 				putnstr(jDir->name, jDir->nsize);
                     
 
 static char *mkmodestr(unsigned long mode, char *str)
 {
-    static const char *l="xwr";
-    int mask=1, i;
-    char c;
-
-    switch (mode & S_IFMT) {
-        case S_IFDIR:    str[0]='d'; break;
-        case S_IFBLK:    str[0]='b'; break;
-        case S_IFCHR:    str[0]='c'; break;
-        case S_IFIFO:    str[0]='f'; break;
-        case S_IFLNK:    str[0]='l'; break;
-        case S_IFSOCK:   str[0]='s'; break;
-        case S_IFREG:    str[0]='-'; break;
-        default:        str[0]='?';
-    }
-
-    for(i=0;i<9;i++) {
-        c=l[i%3];
-        str[9-i]=(mode & mask)?c:'-';
-        mask=mask<<1;
-    }
-
-    if(mode & S_ISUID) str[3]=(mode & S_IXUSR)?'s':'S';
-    if(mode & S_ISGID) str[6]=(mode & S_IXGRP)?'s':'S';
-    if(mode & S_ISVTX) str[9]=(mode & S_IXOTH)?'t':'T';
-    str[10]='\0';
-    return str;
+	static const char *l = "xwr";
+	int mask = 1, i;
+	char c;
+
+	switch (mode & S_IFMT) {
+		case S_IFDIR:    str[0] = 'd'; break;
+		case S_IFBLK:    str[0] = 'b'; break;
+		case S_IFCHR:    str[0] = 'c'; break;
+		case S_IFIFO:    str[0] = 'f'; break;
+		case S_IFLNK:    str[0] = 'l'; break;
+		case S_IFSOCK:   str[0] = 's'; break;
+		case S_IFREG:    str[0] = '-'; break;
+		default:         str[0] = '?';
+	}
+
+	for(i = 0; i < 9; i++) {
+		c = l[i%3];
+		str[9-i] = (mode & mask)?c:'-';
+		mask = mask<<1;
+	}
+
+	if(mode & S_ISUID) str[3] = (mode & S_IXUSR)?'s':'S';
+	if(mode & S_ISGID) str[6] = (mode & S_IXGRP)?'s':'S';
+	if(mode & S_ISVTX) str[9] = (mode & S_IXOTH)?'t':'T';
+	str[10] = '\0';
+	return str;
 }
 
 static inline void dump_stat(struct stat *st, const char *name)
 {
-    char str[20];
-    char s[64], *p;
+	char str[20];
+	char s[64], *p;
 
-    if (st->st_mtime == (time_t)(-1))	/* some ctimes really hate -1 */
-        st->st_mtime = 1;
+	if (st->st_mtime == (time_t)(-1)) /* some ctimes really hate -1 */
+		st->st_mtime = 1;
 
-    ctime_r(&st->st_mtime, s/*, 64*/);   /* newlib ctime doesn't have buflen */
+	ctime_r(&st->st_mtime, s/*,64*/); /* newlib ctime doesn't have buflen */
 
-    if((p=strchr(s,'\n'))!=NULL) *p='\0';
-    if((p=strchr(s,'\r'))!=NULL) *p='\0';
+	if ((p = strchr(s,'\n')) != NULL) *p = '\0';
+	if ((p = strchr(s,'\r')) != NULL) *p = '\0';
 
 /*
-    printf("%6lo %s %8ld %s %s\n", st->st_mode, mkmodestr(st->st_mode, str),
-        st->st_size, s, name);
+	printf("%6lo %s %8ld %s %s\n", st->st_mode, mkmodestr(st->st_mode, str),
+		st->st_size, s, name);
 */
 
-    printf(" %s %8ld %s %s", mkmodestr(st->st_mode,str), st->st_size, s, name);
+	printf(" %s %8ld %s %s", mkmodestr(st->st_mode,str), st->st_size, s, name);
 }
 
 static inline u32 dump_inode(struct b_lists * pL, struct jffs2_raw_dirent *d, struct jffs2_raw_inode *i)
                     
 	if(!d || !i) return -1;
 
 	strncpy(fname, d->name, d->nsize);
-	fname[d->nsize]='\0';
+	fname[d->nsize] = '\0';
 
 	memset(&st,0,sizeof(st));
 
-	st.st_mtime=i->mtime;
-	st.st_mode=i->mode;
-	st.st_ino=i->ino;
+	st.st_mtime = i->mtime;
+	st.st_mode = i->mode;
+	st.st_ino = i->ino;
 
 	/* neither dsize nor isize help us.. do it the long way */
-	st.st_size=jffs2_1pass_read_inode(pL, i->ino, NULL);
+	st.st_size = jffs2_1pass_read_inode(pL, i->ino, NULL);
 
 	dump_stat(&st, fname);
 
                     
 	struct b_node *b;
 	struct jffs2_raw_dirent *jDir;
 
-	for(b = pL->dirListHead;b;b=b->next) {
+	for (b = pL->dir.listHead; b; b = b->next) {
 		jDir = (struct jffs2_raw_dirent *) (b->offset);
-		if ((pino == jDir->pino) && (jDir->ino)) {	/* 0 inode for unlink */
-			u32 i_version=0;
-			struct jffs2_raw_inode *jNode, *i=NULL;
-			struct b_node *b2 = pL->fragListHead;
+		if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */
+			u32 i_version = 0;
+			struct jffs2_raw_inode *jNode, *i = NULL;
+			struct b_node *b2 = pL->frag.listHead;
 
 			while (b2) {
 				jNode = (struct jffs2_raw_inode *) (b2->offset);
 				if (jNode->ino == jDir->ino
-				    && jNode->version>=i_version)
-					i=jNode;
+				    && jNode->version >= i_version)
+					i = jNode;
 				b2 = b2->next;
 			}
 
                   
 	unsigned char *src;
 
 	/* we need to search all and return the inode with the highest version */
-	for(b = pL->dirListHead; b; b=b->next) {
+	for(b = pL->dir.listHead; b; b = b->next) {
 		jDir = (struct jffs2_raw_dirent *) (b->offset);
 		if (ino == jDir->ino) {
 		    	if(jDir->version < version) continue;
                   
 	/* now we found the right entry again. (shoulda returned inode*) */
 	if (jDirFound->type != DT_LNK)
 		return jDirFound->ino;
-	/* so its a soft link so we follow it again. */
-	b2 = pL->fragListHead;
+
+	/* it's a soft link so we follow it again. */
+	b2 = pL->frag.listHead;
 	while (b2) {
 		jNode = (struct jffs2_raw_inode *) (b2->offset);
 		if (jNode->ino == jDirFound->ino) {
                   
 			tmp[i] = c[i + 1];
 		tmp[i] = '\0';
 		/* only a failure if we arent looking at top level */
-		if (!(pino = jffs2_1pass_find_inode(pL, working_tmp, pino)) && (working_tmp[0])) {
+		if (!(pino = jffs2_1pass_find_inode(pL, working_tmp, pino)) &&
+		    (working_tmp[0])) {
 			putstr("find_inode failed for name=");
 			putstr(working_tmp);
 			putstr("\r\n");
                     
 {
 	struct b_node *b;
 	struct jffs2_unknown_node *node;
-	struct b_lists *pL=(struct b_lists *)part->jffs2_priv;
+	struct b_lists *pL = (struct b_lists *)part->jffs2_priv;
 
 	if (part->jffs2_priv == 0){
 		DEBUGF ("rescan: First time in use\n");
 		return 1;
 	}
 	/* if we have no list, we need to rescan */
-	if (pL->fragListCount == 0) {
+	if (pL->frag.listCount == 0) {
 		DEBUGF ("rescan: fraglist zero\n");
 		return 1;
 	}
 
-	/* or if we are scanninga new partition */
+	/* or if we are scanning a new partition */
 	if (pL->partOffset != part->offset) {
 		DEBUGF ("rescan: different partition\n");
 		return 1;
 	}
-	/* but suppose someone reflashed the root partition at the same offset... */
-	b = pL->dirListHead;
+	/* but suppose someone reflashed a partition at the same offset... */
+	b = pL->dir.listHead;
 	while (b) {
 		node = (struct jffs2_unknown_node *) (b->offset);
 		if (node->nodetype != JFFS2_NODETYPE_DIRENT) {
-			DEBUGF ("rescan: fs changed beneath me? (%lx)\n", (unsigned long) b->offset);
+			DEBUGF ("rescan: fs changed beneath me? (%lx)\n",
+					(unsigned long) b->offset);
 			return 1;
 		}
 		b = b->next;
                     
 	return 0;
 }
 
+#ifdef DEBUG_FRAGMENTS
+static void
+dump_fragments(struct b_lists *pL)
+{
+	struct b_node *b;
+	struct jffs2_raw_inode *jNode;
+
+	putstr("\r\n\r\n******The fragment Entries******\r\n");
+	b = pL->frag.listHead;
+	while (b) {
+		jNode = (struct jffs2_raw_inode *) (b->offset);
+		putLabeledWord("\r\n\tbuild_list: FLASH_OFFSET = ", b->offset);
+		putLabeledWord("\tbuild_list: totlen = ", jNode->totlen);
+		putLabeledWord("\tbuild_list: inode = ", jNode->ino);
+		putLabeledWord("\tbuild_list: version = ", jNode->version);
+		putLabeledWord("\tbuild_list: isize = ", jNode->isize);
+		putLabeledWord("\tbuild_list: atime = ", jNode->atime);
+		putLabeledWord("\tbuild_list: offset = ", jNode->offset);
+		putLabeledWord("\tbuild_list: csize = ", jNode->csize);
+		putLabeledWord("\tbuild_list: dsize = ", jNode->dsize);
+		putLabeledWord("\tbuild_list: compr = ", jNode->compr);
+		putLabeledWord("\tbuild_list: usercompr = ", jNode->usercompr);
+		putLabeledWord("\tbuild_list: flags = ", jNode->flags);
+		putLabeledWord("\tbuild_list: offset = ", b->offset);	// FIXME: ? [RS]
+		b = b->next;
+	}
+}
+#endif
+
+#ifdef DEBUG_DIRENTS
+static void
+dump_dirents(struct b_lists *pL)
+{
+	struct b_node *b;
+	struct jffs2_raw_dirent *jDir;
+
+	putstr("\r\n\r\n******The directory Entries******\r\n");
+	b = pL->dir.listHead;
+	while (b) {
+		jDir = (struct jffs2_raw_dirent *) (b->offset);
+		putstr("\r\n");
+		putnstr(jDir->name, jDir->nsize);
+		putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic);
+		putLabeledWord("\tbuild_list: nodetype = ", jDir->nodetype);
+		putLabeledWord("\tbuild_list: hdr_crc = ", jDir->hdr_crc);
+		putLabeledWord("\tbuild_list: pino = ", jDir->pino);
+		putLabeledWord("\tbuild_list: version = ", jDir->version);
+		putLabeledWord("\tbuild_list: ino = ", jDir->ino);
+		putLabeledWord("\tbuild_list: mctime = ", jDir->mctime);
+		putLabeledWord("\tbuild_list: nsize = ", jDir->nsize);
+		putLabeledWord("\tbuild_list: type = ", jDir->type);
+		putLabeledWord("\tbuild_list: node_crc = ", jDir->node_crc);
+		putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc);
+		putLabeledWord("\tbuild_list: offset = ", b->offset); 	// FIXME: ? [RS]
+		b = b->next;
+	}
+}
+#endif
+
 static u32
 jffs2_1pass_build_lists(struct part_info * part)
 {
 	struct b_lists *pL;
 	struct jffs2_unknown_node *node;
-	u32 offset;
+	u32 offset, oldoffset = 0;
 	u32 max = part->size - sizeof(struct jffs2_raw_inode);
 	u32 counter = 0;
 	u32 counter4 = 0;
                     
 	/* lcd_off(); */
 
 	/* if we are building a list we need to refresh the cache. */
-	/* note that since we don't free our memory, eventually this will be bad. */
-	/* but we're a bootldr so what the hell. */
 	jffs_init_1pass_list(part);
-	pL=(struct b_lists *)part->jffs2_priv;
+	pL = (struct b_lists *)part->jffs2_priv;
 	pL->partOffset = part->offset;
 	offset = 0;
 	printf("Scanning JFFS2 FS:   ");
 
 	/* start at the beginning of the partition */
 	while (offset < max) {
-	    	if (! (++counter%10000))
-			printf("\b\b%c ", spinner[(counter / 10000) % 4]);
+	    	if ((oldoffset >> SPIN_BLKSIZE) != (offset >> SPIN_BLKSIZE)) {
+			printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]);
+			oldoffset = offset;
+		}
 
 		node = (struct jffs2_unknown_node *) (part->offset + offset);
 		if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) {
 			/* if its a fragment add it */
-			if (node->nodetype == JFFS2_NODETYPE_INODE && inode_crc((struct jffs2_raw_inode *) node)) {
-				if (!(pL->fragListTail = add_node(pL->fragListTail, &(pL->fragListCount),
-								  &(pL->fragListMemBase)))) {
-					putstr("add_node failed!\r\n");
+			if (node->nodetype == JFFS2_NODETYPE_INODE &&
+				    inode_crc((struct jffs2_raw_inode *) node)) {
+				if (insert_node(&pL->frag, (u32) part->offset +
+								offset) == NULL)
 					return 0;
-				}
-				pL->fragListTail->offset = (u32) (part->offset + offset);
-				if (!pL->fragListHead)
-					pL->fragListHead = pL->fragListTail;
 			} else if (node->nodetype == JFFS2_NODETYPE_DIRENT &&
 				   dirent_crc((struct jffs2_raw_dirent *) node)  &&
 				   dirent_name_crc((struct jffs2_raw_dirent *) node)) {
 				if (! (counterN%100))
 					printf("\b\b.  ");
-#if 0
-				printf("Found DIRENT @ 0x%lx\n", offset);
-				putstr("\r\nbuild_lists:p&l ->");
-				putnstr(((struct jffs2_raw_dirent *) node)->name, ((struct jffs2_raw_dirent *) node)->nsize);
-				putstr("\r\n");
-				putLabeledWord("\tpino = ", ((struct jffs2_raw_dirent *) node)->pino);
-				putLabeledWord("\tnsize = ", ((struct jffs2_raw_dirent *) node)->nsize);
-#endif
-
-				if (!(pL->dirListTail = add_node(pL->dirListTail, &(pL->dirListCount), &(pL->dirListMemBase)))) {
-					putstr("add_node failed!\r\n");
+				if (insert_node(&pL->dir, (u32) part->offset +
+								offset) == NULL)
 					return 0;
-				}
-				pL->dirListTail->offset = (u32) (part->offset + offset);
-#if 0
-				putLabeledWord("\ttail = ", (u32) pL->dirListTail);
-				putstr("\ttailName ->");
-				putnstr(((struct jffs2_raw_dirent *) (pL->dirListTail->offset))->name,
-					((struct jffs2_raw_dirent *) (pL->dirListTail->offset))->nsize);
-				putstr("\r\n");
-#endif
-				if (!pL->dirListHead)
-					pL->dirListHead = pL->dirListTail;
 				counterN++;
 			} else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) {
 				if (node->totlen != sizeof(struct jffs2_unknown_node))
-					printf("OOPS Cleanmarker has bad size %d != %d\n", node->totlen, sizeof(struct jffs2_unknown_node));
+					printf("OOPS Cleanmarker has bad size "
+						"%d != %d\n", node->totlen,
+						sizeof(struct jffs2_unknown_node));
 			} else {
-				printf("Unknown node type: %x len %d offset 0x%x\n", node->nodetype, node->totlen, offset);
+				printf("Unknown node type: %x len %d "
+					"offset 0x%x\n", node->nodetype,
+					node->totlen, offset);
 			}
 			offset += ((node->totlen + 3) & ~3);
 			counterF++;
-		} else if (node->magic == JFFS2_EMPTY_BITMASK && node->nodetype == JFFS2_EMPTY_BITMASK) {
+		} else if (node->magic == JFFS2_EMPTY_BITMASK &&
+			   node->nodetype == JFFS2_EMPTY_BITMASK) {
 			offset = jffs2_scan_empty(offset, part);
-		} else {	/* if we know nothing of the filesystem, we just step and look. */
+		} else {	/* if we know nothing, we just step and look. */
 			offset += 4;
 			counter4++;
 		}
                     
 	/* splash(); */
 
 #if 0
-	putLabeledWord("dir entries = ", pL->dirListCount);
-	putLabeledWord("frag entries = ", pL->fragListCount);
+	putLabeledWord("dir entries = ", pL->dir.listCount);
+	putLabeledWord("frag entries = ", pL->frag.listCount);
 	putLabeledWord("+4 increments = ", counter4);
 	putLabeledWord("+file_offset increments = ", counterF);
 
 #endif
 
-#undef SHOW_ALL
-#undef SHOW_ALL_FRAGMENTS
+#ifdef DEBUG_DIRENTS
+	dump_dirents(pL);
+#endif
 
-#ifdef SHOW_ALL
-	{
-		struct b_node *b;
-		struct b_node *b2;
-		struct jffs2_raw_dirent *jDir;
-		struct jffs2_raw_inode *jNode;
-
-		putstr("\r\n\r\n******The directory Entries******\r\n");
-		b = pL->dirListHead;
-		while (b) {
-			jDir = (struct jffs2_raw_dirent *) (b->offset);
-			putstr("\r\n");
-			putnstr(jDir->name, jDir->nsize);
-			putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic);
-			putLabeledWord("\tbuild_list: nodetype = ", jDir->nodetype);
-			putLabeledWord("\tbuild_list: hdr_crc = ", jDir->hdr_crc);
-			putLabeledWord("\tbuild_list: pino = ", jDir->pino);
-			putLabeledWord("\tbuild_list: version = ", jDir->version);
-			putLabeledWord("\tbuild_list: ino = ", jDir->ino);
-			putLabeledWord("\tbuild_list: mctime = ", jDir->mctime);
-			putLabeledWord("\tbuild_list: nsize = ", jDir->nsize);
-			putLabeledWord("\tbuild_list: type = ", jDir->type);
-			putLabeledWord("\tbuild_list: node_crc = ", jDir->node_crc);
-			putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc);
-			b = b->next;
-		}
-
-#ifdef SHOW_ALL_FRAGMENTS
-		putstr("\r\n\r\n******The fragment Entries******\r\n");
-		b = pL->fragListHead;
-		while (b) {
-			jNode = (struct jffs2_raw_inode *) (b->offset);
-			putLabeledWord("\r\n\tbuild_list: FLASH_OFFSET = ", b->offset);
-			putLabeledWord("\tbuild_list: totlen = ", jNode->totlen);
-			putLabeledWord("\tbuild_list: inode = ", jNode->ino);
-			putLabeledWord("\tbuild_list: version = ", jNode->version);
-			putLabeledWord("\tbuild_list: isize = ", jNode->isize);
-			putLabeledWord("\tbuild_list: atime = ", jNode->atime);
-			putLabeledWord("\tbuild_list: offset = ", jNode->offset);
-			putLabeledWord("\tbuild_list: csize = ", jNode->csize);
-			putLabeledWord("\tbuild_list: dsize = ", jNode->dsize);
-			putLabeledWord("\tbuild_list: compr = ", jNode->compr);
-			putLabeledWord("\tbuild_list: usercompr = ", jNode->usercompr);
-			putLabeledWord("\tbuild_list: flags = ", jNode->flags);
-			b = b->next;
-		}
-#endif /* SHOW_ALL_FRAGMENTS */
-	}
+#ifdef DEBUG_FRAGMENTS
+	dump_fragments(pL);
+#endif
 
-#endif	/* SHOW_ALL */
 	/* give visual feedback that we are done scanning the flash */
 	led_blink(0x0, 0x0, 0x1, 0x1);	/* off, forever, on 100ms, off 100ms */
 	return 1;
                     
 	struct jffs2_raw_inode *jNode;
 	int i;
 
-	b = pL->fragListHead;
 	for (i = 0; i < JFFS2_NUM_COMPR; i++) {
 		piL->compr_info[i].num_frags = 0;
 		piL->compr_info[i].compr_sum = 0;
 		piL->compr_info[i].decompr_sum = 0;
 	}
 
+	b = pL->frag.listHead;
 	while (b) {
 		jNode = (struct jffs2_raw_inode *) (b->offset);
 		if (jNode->compr < JFFS2_NUM_COMPR) {
                   
 	long ret = 0;
 	u32 inode;
 
-	if (! (pl  = jffs2_get_list(part, "ls")))
+	if (! (pl = jffs2_get_list(part, "ls")))
 		return 0;
 
 	if (! (inode = jffs2_1pass_search_list_inodes(pl, fname, 1))) {
                    
 		return 0;
 
 	jffs2_1pass_fill_info(pl, &info);
-	for (i=0; i < JFFS2_NUM_COMPR; i++) {
+	for (i = 0; i < JFFS2_NUM_COMPR; i++) {
 		printf("Compression: %s\n", compr_names[i]);
 		printf("\tfrag count: %d\n", info.compr_info[i].num_frags);
 		printf("\tcompressed sum: %d\n", info.compr_info[i].compr_sum);
--- /home/kub/tmp/u-boot/fs/jffs2/jffs2_private.h	Mon Feb 18 00:36:36 2002
+++ fs/jffs2/jffs2_private.h	Wed Mar 12 11:43:19 2003
                 
 
 #include <jffs2/jffs2.h>
 
+
 struct b_node {
 	u32 offset;
 	struct b_node *next;
 };
 
+struct b_list {
+	struct b_node *listTail;
+	struct b_node *listHead;
+#ifdef CFG_JFFS2_SORT_FRAGMENTS
+	struct b_node *listLast;
+	int (*listCompare)(struct b_node *new, struct b_node *node);
+	u32 listLoops;
+#endif
+	u32 listCount;
+	struct mem_block *listMemBase;
+};
+
 struct b_lists {
 	char *partOffset;
-	struct b_node *dirListTail;
-	struct b_node *dirListHead;
-	u32 dirListCount;
-	u32 dirListMemBase;
-	struct b_node *fragListTail;
-	struct b_node *fragListHead;
-	u32 fragListCount;
-	u32 fragListMemBase;
+	struct b_list dir;
+	struct b_list frag;
 
 };
+
 struct b_compr_info {
 	u32 num_frags;
 	u32 compr_sum;
                   
 static inline int
 hdr_crc(struct jffs2_unknown_node *node)
 {
+#if 1
         u32 crc = crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4);
-        u32 crc_blah = crc32_no_comp(~0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4);
-
-        crc_blah ^= ~0;
+#else
+	/* what's the semantics of this? why is this here? */
+        u32 crc = crc32_no_comp(~0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4);
 
+        crc ^= ~0;
+#endif
         if (node->hdr_crc != crc) {
                 return 0;
         } else {





More information about the U-Boot mailing list