JFFS1 scan procedure

Aleksander Sanochkin asanochkin at Lnxw.COM
Fri Nov 30 12:26:07 EST 2001


Hi!

I've been using JFFS1 for some time and faced a problem
that the JFFS1 scan procedure is not robust enough. Namely,
it expects that the flash region it scans is either erased
or is in a state left by JFFS1 itself.  That is, it doesn't
expect that the flash is containing a "garbage", which can
be the case sometimes.

I've improved the scan procedure to work smoothly in all
cases for me.  Attached is a diff against the current CVS.

Best regards.

-------------- next part --------------
diff -ur cvs/fs/jffs/intrep.c scan_flash/fs/jffs/intrep.c
--- cvs/fs/jffs/intrep.c	Mon Sep 24 03:28:36 2001
+++ scan_flash/fs/jffs/intrep.c	Wed Nov 21 19:55:02 2001
@@ -772,6 +772,9 @@
 	__u32 free_chunk_size1;
 	__u32 free_chunk_size2;
 
+	__u32                          largest_hole         = 0;
+	__u32                          hole_end_offset      = 0;
+	__u32                          head_offset;
 	
 #define NUMFREEALLOWED     2        /* 2 chunks of at least erase size space allowed */
 	int num_free_space = 0;       /* Flag err if more than TWO
@@ -884,6 +887,22 @@
 							  (unsigned int) start,
 							  (unsigned int)(test_start - start)));
 
+						D1(printk("Reducing start to 0x%x from 0x%x\n",
+						          test_start, start));
+						if (largest_hole < test_start - start)
+						{
+							D3(printk("was hole = %x end_offset = %x\n",
+							          largest_hole, hole_end_offset));
+							if (fmc->head)
+							{
+								largest_hole    = test_start - start;
+								hole_end_offset = test_start;
+							}
+						}
+
+						D3(printk("now = %x end_offset = %x\n",
+					        	largest_hole, hole_end_offset));
+
 						/* below, space from "start" to "pos" will be marked dirty. */
 						start = test_start; 
 						
@@ -956,6 +975,20 @@
 				           num_free_space++;
 				           D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n",
 						     (unsigned int) start, (unsigned int) (pos - start)));
+
+					   if (largest_hole < pos - start)
+					   {
+						   D3(printk("was hole = %x end_offset = %x\n",
+						          largest_hole, hole_end_offset));
+						   if (fmc->head)
+						   {
+							   largest_hole    = pos - start;
+							   hole_end_offset = pos;
+						   }
+
+						   D3(printk("now = %x end_offset = %x\n",
+						          largest_hole, hole_end_offset));
+					   }
 				 }else{
 				         num_free_spc_not_accp++;
 					 D1(printk("Free space (#%i) found but *Not* accepted: Starting "
@@ -1002,9 +1035,11 @@
 			   to scan for the magic pattern.  */
 			D1(printk("*************** Dirty flash memory or "
 				  "bad inode: "
-				  "hexdump(pos = 0x%lx, len = 128):\n",
-				  (long)pos));
-			D1(jffs_hexdump(fmc->mtd, pos, 128));
+				  "hexdump(pos = 0x%lx, len = %d):\n",
+				  (long)pos,
+				  end - pos > 128 ? 128 : end - pos));
+			D1(jffs_hexdump(fmc->mtd, pos,
+			                end - pos > 128 ? 128 : end - pos));
 
 			for (pos += 4; pos < end; pos += 4) {
 				switch (flash_read_u32(fmc->mtd, pos)) {
@@ -1197,12 +1232,6 @@
 
 				return -ENOMEM;
 			}
-			if ((err = jffs_insert_node(c, 0, &raw_inode,
-						    name, node)) < 0) {
-				printk("JFFS: Failed to handle raw inode. "
-				       "(err = %d)\n", err);
-				break;
-			}
 			if (raw_inode.rename) {
 				struct jffs_delete_list *dl
 				= (struct jffs_delete_list *)
@@ -1226,6 +1255,12 @@
 				c->delete_list = dl;
 				node->data_size = 0;
 			}
+			if ((err = jffs_insert_node(c, 0, &raw_inode,
+						    name, node)) < 0) {
+				printk("JFFS: Failed to handle raw inode. "
+				       "(err = %d)\n", err);
+				break;
+			}
 			D3(jffs_print_node(node));
 			node = 0; /* Don't free the node!  */
 		}
@@ -1242,7 +1277,22 @@
 		jffs_free_node(node);
 		DJM(no_jffs_node--);
 	}
-	jffs_build_end(fmc);
+	if (fmc->head && fmc->tail_extra &&
+	    fmc->head->offset + fmc->flash_size -
+			fmc->tail_extra->offset - fmc->tail_extra->size > largest_hole)
+	{
+		head_offset = fmc->head->offset;
+	}
+	else
+	{
+		head_offset = hole_end_offset;
+	}
+	
+	if (jffs_build_end(fmc, head_offset) < 0)
+	{
+		D(printk("jffs_build_end() failed\n"));
+		return -ENOMEM;
+	}
 
 	/* Free read buffer */
 	kfree (read_buf);
diff -ur cvs/fs/jffs/jffs_fm.c scan_flash/fs/jffs/jffs_fm.c
--- cvs/fs/jffs/jffs_fm.c	Thu Sep 20 16:29:47 2001
+++ scan_flash/fs/jffs/jffs_fm.c	Wed Nov 21 19:02:25 2001
@@ -89,8 +89,8 @@
 
 /* When the flash memory scan has completed, this function should be called
    before use of the control structure.  */
-void
-jffs_build_end(struct jffs_fmcontrol *fmc)
+int
+jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset)
 {
 	D3(printk("jffs_build_end()\n"));
 
@@ -99,13 +99,112 @@
 		fmc->tail = fmc->tail_extra;
 	}
 	else if (fmc->head_extra) {
-		fmc->tail_extra->next = fmc->head;
-		fmc->head->prev = fmc->tail_extra;
-		fmc->head = fmc->head_extra;
+		struct jffs_fm *fm, *cur;
+
+		if (head_offset == fmc->head->offset)
+		{
+			fmc->tail->next = fmc->head_extra;
+			fmc->head_extra->prev = fmc->tail;
+			fmc->tail = fmc->tail_extra;
+		}
+		else
+		{
+			fmc->tail_extra->next = fmc->head;
+			fmc->head->prev = fmc->tail_extra;
+			fmc->head = fmc->head_extra;
+			while (fmc->head->offset != head_offset)
+			{
+				fmc->tail->next = fmc->head;
+				fmc->head = fmc->head->next;
+				fmc->head->prev = 0;
+				fmc->tail->next->prev = fmc->tail;
+				fmc->tail = fmc->tail->next;
+				fmc->tail->next = 0;
+			}
+		}
+				/* Make sure the only free space we have is between tail and head.
+				 */
+		for (cur = fmc->head; cur && cur != fmc->tail;)
+		{
+			if (cur->offset + cur->size < cur->next->offset)
+			{
+				if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL)))
+				{
+					D(printk("jffs_buid_end(): kmalloc failed!\n"));
+					return -ENOMEM;
+				}
+				DJM(no_jffs_fm++);
+				fm->size = cur->next->offset - cur->offset - cur->size;
+				fm->offset = cur->offset + cur->size;
+				fm->nodes = 0;
+				fm->next = cur->next;
+				fm->prev = cur;
+				cur->next->prev = fm;
+				cur->next = fm;
+				cur = fm->next;
+				fmc->free_size -= fm->size;
+				fmc->dirty_size += fm->size;
+			}
+			else if (cur->offset > cur->next->offset)
+			{
+				if (cur->offset + cur->size < fmc->flash_size)
+				{
+					if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL)))
+					{
+						D(printk("jffs_buid_end(): kmalloc failed!\n"));
+						return -ENOMEM;
+					}
+					DJM(no_jffs_fm++);
+					fm->size = fmc->flash_size -
+					           cur->offset - cur->size;
+					fm->nodes = 0;
+					fm->offset = cur->offset + cur->size;
+					fm->next = cur->next;
+					fm->prev = cur;
+					cur->next->prev = fm;
+					cur->next = fm;
+					cur = fm->next;
+					fmc->free_size -= fm->size;
+					fmc->dirty_size += fm->size;
+				}
+				else
+				{
+					cur = cur->next;
+				}
+				if (cur->offset > 0)
+				{
+					if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL)))
+					{
+						D(printk("jffs_buid_end(): kmalloc failed!\n"));
+						return -ENOMEM;
+					}
+					DJM(no_jffs_fm++);
+					fm->size = cur->offset;
+					fm->nodes = 0;
+					fm->offset = 0;
+					fm->next = cur;
+					fm->prev = cur->prev;
+					cur->prev->next = fm;
+					cur->prev = fm;
+					fmc->free_size -= fm->size;
+					fmc->dirty_size += fm->size;
+				}
+			}
+			else if (cur->offset + cur->size != cur->next->offset)
+			{
+				printk("jffs_build_end(): Internal error.\n");
+				return -EINVAL;
+			}
+			else
+			{
+				cur = cur->next;
+			}
+		}
 	}
 	fmc->head_extra = 0; /* These two instructions should be omitted.  */
 	fmc->tail_extra = 0;
 	D3(jffs_print_fmcontrol(fmc));
+	return 0;
 }
 
 
diff -ur cvs/fs/jffs/jffs_fm.h scan_flash/fs/jffs/jffs_fm.h
--- cvs/fs/jffs/jffs_fm.h	Thu Jan 11 15:03:25 2001
+++ scan_flash/fs/jffs/jffs_fm.h	Wed Nov 21 19:03:30 2001
@@ -123,7 +123,7 @@
 
 
 struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, kdev_t dev);
-void jffs_build_end(struct jffs_fmcontrol *fmc);
+int jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset);
 void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc);
 
 int jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size,


More information about the linux-mtd mailing list