[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Sorry, here's the patch for jffs1 async power down problems fix :)



My bad :)

intrep.c patch attached for jffs1 power down problems fix.

Vipin
Index: intrep.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs/intrep.c,v
retrieving revision 1.93
diff -u -r1.93 intrep.c
--- intrep.c	2001/01/29 11:29:37	1.93
+++ intrep.c	2001/03/08 17:14:18
@@ -565,7 +565,26 @@
 	c->building_fs = 1;
 	c->sb = sb;
 	if ((err = jffs_scan_flash(c)) < 0) {
-		goto jffs_build_fs_fail;
+		if(err == -EAGAIN){
+			/* scan_flash() wants us to try once more. A flipping 
+			   bits sector was detect in the middle of the scan flash.
+			   Clean up old allocated memory before going in.
+			*/
+			/* remove this printk later */
+			printk("jffs_build_fs: Cleaning up all control structures, reallocating them and trying mount again.\n");
+			jffs_cleanup_control(c);
+			if (!(c = jffs_create_control(sb->s_dev))) {
+				return -ENOMEM;
+			}
+			c->building_fs = 1;
+			c->sb = sb;
+
+			if ((err = jffs_scan_flash(c)) < 0) {
+				goto jffs_build_fs_fail;
+			}			
+		}else{
+			goto jffs_build_fs_fail;
+		}
 	}
 
 	/* Add a virtual root node if no one exists.  */
@@ -620,6 +639,123 @@
 } /* jffs_build_fs()  */
 
 
+/*
+  This checks for sectors that were being erased
+  in their previous lifetimes and for some reason
+  or the other (power fail etc.), the erase cycles
+  never completed.
+  As the flash array would have reverted back to 
+  read status, these sectors are detected by the 
+  symptom of the "flipping bits", i.e. bits being
+  read back differently from the same location in
+  flash if read multiple times.
+  The only solution to this is to re-erase the entire
+  sector.
+  Unfortunately detecting "flipping bits" is not a simple
+  exercise as a bit may be read back at 1 or 0 depending
+  on the alignment of the stars in the universe.
+  The level of confidence is in direct proportion to the
+  number of scans done. By power fail testing I (Vipin) have
+  been able to proove that reading twice is not enough.
+  Maybe 4 times? Change NUM_REREADS to a higher number
+  if you want a (even) higher degree of confidence in your
+  mount process. A higher number would of course slow down
+  your mount.
+*/
+int checkPartlyErasedSectors(struct jffs_fmcontrol *fmc){
+
+#define NUM_REREADS             4 /* see note above */
+#define FLIPPING_SECTOR_OK      0
+#define FLIPPING_SECTOR_ERROR  -1
+#define READ_AHEAD_BYTES        4096 /* must be a multiple of 4, 
+					usually set to kernel page size */
+
+	__u8 *read_buf1;
+	__u8 *read_buf2;
+
+	int err = FLIPPING_SECTOR_OK;
+	int retlen;
+	int i;
+	int cnt;
+	__u32 offset;
+	loff_t pos = 0;
+	loff_t end = fmc->flash_size;
+
+
+	/* Allocate read buffers */
+	read_buf1 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL);
+	read_buf2 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL);
+	
+
+ CHECK_NEXT:
+	while(pos < end){
+		
+		D1(printk("checkPartlyErasedSector():checking sector which contains offset 0x%x for flipping bits..\n",
+		       (__u32)pos));
+		
+		retlen = flash_safe_read(fmc->mtd, pos,
+					 &read_buf1[0], READ_AHEAD_BYTES);
+		retlen &= ~3;
+		
+		for(cnt = 0; cnt < NUM_REREADS; cnt++){
+			(void)flash_safe_read(fmc->mtd, pos,
+					      &read_buf2[0], READ_AHEAD_BYTES);
+			
+			for (i=0 ; i < retlen ; i+=4) {
+				/* buffers MUST match, double word for word! */
+				if(*((__u32 *) &read_buf1[i]) !=
+				   *((__u32 *) &read_buf2[i])
+				   ){
+				        /* flipping bits detected, time to erase sector */
+					/* This will help us log some statistics etc. */
+					printk("Flipping bits detected in re-read round:%i of %i\n",
+					       cnt, NUM_REREADS);
+					printk(KERN_WARNING "checkPartlyErasedSectors:flipping bits detected @offset:0x%x(0x%x!=0x%x)\n",
+					       (__u32)pos+i, *((__u32 *) &read_buf1[i]), *((__u32 *) &read_buf2[i]));
+					
+				        /* calculate start of present sector */
+					offset = (((__u32)pos+i)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size;
+					
+					/* make into level D1 later */
+					printk("checkPartlyErasedSector():erasing sector starting 0x%x.\n",
+						  offset);
+					
+					if (flash_erase_region(fmc->mtd,
+							       offset, fmc->sector_size) < 0) {
+						printk(KERN_ERR "JFFS: Erase of flash failed. "
+						       "offset = %u, erase_size = %d\n",
+						       offset , fmc->sector_size);
+						
+						err = FLIPPING_SECTOR_ERROR;
+						goto returnBack;
+
+					}else{
+						printk("JFFS: Erase of flash sector @xxxxxxx.\n",
+						       offset);
+						/* skip ahead to the next sector */
+						pos = (((__u32)pos+i)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size;
+						pos += fmc->sector_size;
+						goto CHECK_NEXT;
+					}
+				}
+			}
+		}
+		pos += READ_AHEAD_BYTES;
+	}
+
+ returnBack:
+	kfree(read_buf1);
+	kfree(read_buf2);
+
+	/* Change this to level "D1" later*/
+	printk("checkPartlyErasedSector():Done checking all sectors till offset 0x%x for flipping bits.\n",
+		  (__u32)pos);
+
+	return err;
+
+}/* end checkPartlyErasedSectors() */
+
+
 /* Scan the whole flash memory in order to find all nodes in the
    file systems.  */
 static int
@@ -638,12 +774,34 @@
 	loff_t end = fmc->flash_size;
 	__u8 *read_buf;
 	int i, len, retlen;
+	__u32 offset;
+	
+#define NUMFREEALLOWED     2        /* 2 chunks of at least erase size space allowed */
+	int numFreeSpace = 0;       /* Flag err if more than TWO
+				       free blocks found. This is NOT allowed
+				       by the current jffs design.
+				    */
+	int numFreeSpaceNotAccp = 0; /* For debugging purposed keep count 
+					of how much free space was rejected and
+					marked dirty
+				     */
 
 	D1(printk("jffs_scan_flash(): start pos = 0x%lx, end = 0x%lx\n",
 		  (long)pos, (long)end));
 
 	flash_safe_acquire(fmc->mtd);
 
+	/*
+	  check and make sure that any sector does not suffer
+	  from the "partly erased, bit flipping syndrome" (TM Vipin :)
+	  If so, offending sectors will be erased.
+	*/
+	if(checkPartlyErasedSectors(fmc) < 0){
+
+		flash_safe_release(fmc->mtd);
+		return -1; /* what should we return here ? */
+	}
+
 	/* Allocate read buffer */
 	read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
 
@@ -656,32 +814,40 @@
 
 		switch (flash_read_u32(fmc->mtd, pos)) {
 		case JFFS_EMPTY_BITMASK:
-			/* We have found 0xff at this position.  We have to
+			/* We have found 0xffffffff at this position.  We have to
 			   scan the rest of the flash till the end or till
-			   something else than 0xff is found.  */
-			D1(printk("jffs_scan_flash(): 0xff at pos 0x%lx.\n",
+			   something else than 0xffffffff is found.
+		           Keep going till we do not find JFFS_EMPTY_BITMASK 
+			   anymore */
+
+			D1(printk("jffs_scan_flash(): 0xffffffff at pos 0x%lx.\n",
 				  (long)pos));
 
-			len = end - pos < 4096 ? end - pos : 4096;
+		        while(pos < end){
 
-			retlen = flash_safe_read(fmc->mtd, pos,
+			      len = end - pos < 4096 ? end - pos : 4096;
+			      
+			      retlen = flash_safe_read(fmc->mtd, pos,
 						 &read_buf[0], len);
 
-			retlen &= ~3;
-
-			for (i=0 ; i < retlen ; i+=4, pos += 4) {
-				if(*((__u32 *) &read_buf[i]) !=
-						JFFS_EMPTY_BITMASK)
+			      retlen &= ~3;
+			      
+			      for (i=0 ; i < retlen ; i+=4, pos += 4) {
+				      if(*((__u32 *) &read_buf[i]) !=
+					 JFFS_EMPTY_BITMASK)
 					break;
+			      }
+			      if (i == retlen)
+				    continue;
+			      else
+				    break;
 			}
-			if (i == retlen)
-				continue;
-
-			D1(printk("jffs_scan_flash(): 0xff ended at "
-				  "pos 0x%lx.\n", (long)pos));
 
+			D1(printk("jffs_scan_flash(): 0xff ended at pos 0x%lx (read: 0x%lx).\n",
+				  (long)pos, (long)*((__u32 *) &read_buf[i])));
+			
 			/* If some free space ends in the middle of a sector,
-				treat it as dirty rather than clean.
+			   treat it as dirty rather than clean.
 			   This is to handle the case where one thread 
 			   allocated space for a node, but didn't get to
 			   actually _write_ it before power was lost, leaving
@@ -694,13 +860,97 @@
 				   only from the beginning of this sector
 				   (or from start) 
 				*/
-				if (start < (pos & ~(fmc->sector_size-1))) {
-					D1(printk("Reducing start to 0x%x from 0x%x\n", (unsigned int) (pos & ~(fmc->sector_size-1)), (unsigned int) start));
-					start = pos & ~(fmc->sector_size-1);
+				if ((start < (pos & ~(fmc->sector_size-1)))) {
+				        if(numFreeSpace < NUMFREEALLOWED){
+					        D1(printk("Reducing start to 0x%x from 0x%x\n",
+							  (unsigned int) (pos & ~(fmc->sector_size-1)), (unsigned int) start));
+
+						/* change this to level D1 later */
+						printk("Free space accepted: Starting 0x%x for 0x%x bytes\n",
+							  (unsigned int) start,
+							  (unsigned int) ((unsigned int)start - (unsigned int)(pos & ~(fmc->sector_size-1))));
+						start = pos & ~(fmc->sector_size-1);
+						
+						/* Being in here means that we have found
+						   at least an entire erase sector size of free space.
+						   Count it in.
+						*/
+						numFreeSpace++;
+					}else{
+						/* change this to a D1 level later. */
+					        printk("Free space (#%i) found but *Not* accepted: Starting 0x%x for 0x%x bytes\n",
+							  ++numFreeSpaceNotAccp, 
+							  (unsigned int) start, 
+							  (unsigned int) ((unsigned int) start - (unsigned int) (pos & ~(fmc->sector_size-1))));
+					        
+					}
+					
 				}
-				D1(printk("Dirty space: 0x%x for 0x%x bytes\n", (unsigned int) start, (unsigned int) (pos - start)));
-				jffs_fmalloced(fmc, (__u32) start,
-					       (__u32) (pos - start), 0);
+				if((((__u32)(pos - start)) != 0)){
+
+				        D1(printk("Dirty space: Starting 0x%x for 0x%x bytes\n",
+						  (unsigned int) start, (unsigned int) (pos - start)));
+					jffs_fmalloced(fmc, (__u32) start,
+						       (__u32) (pos - start), 0);
+				}else{
+					/* "Flipping bits" detected. This means that our scan for them
+					   did not catch this offset. See checkPartlyErasedSectors() for
+					   more info.
+					*/
+					/* make into level D1  later */
+					printk("jffs_scan_flash(): wants to allocate dirty flash space for 0 bytes.\n");
+					/* make into level D1  later */
+					printk("jffs_scan_flash(): Flipping bits! We will free all allocated memory, erase this sector and remount\n");
+					/* calculate start of present sector */
+					offset = (((__u32)pos)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size;
+					
+					/* make into level D1 later */
+					printk("jffs_scan_flash():erasing sector starting 0x%x.\n",
+						  offset);
+					
+					if (flash_erase_region(fmc->mtd,
+							       offset, fmc->sector_size) < 0) {
+						printk(KERN_ERR "JFFS: Erase of flash failed. "
+						       "offset = %u, erase_size = %d\n",
+						       offset , fmc->sector_size);
+
+						flash_safe_release(fmc->mtd);
+						kfree (read_buf);
+						return -1; /* what should we return here on erase error ? */
+
+					}
+					flash_safe_release(fmc->mtd);
+					kfree (read_buf);
+
+					return -EAGAIN; /* erased offending sector. Try mount one more time please. */
+				}
+			}else{
+			        /* Being in here means that we have found
+				   at least an entire erase sector size of free space.
+				   Count it in if we have not found any free space yet.
+				 */
+			         if(numFreeSpace < NUMFREEALLOWED){
+				           numFreeSpace++;
+				           D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n",
+						     (unsigned int) start, (unsigned int) (pos - start)));
+				 }else{
+					 /* change this to a D1 level later */
+					 printk("Free space (#%i) found but *Not* accepted: Starting 0x%x for 0x%x bytes\n",
+						++numFreeSpaceNotAccp, 
+						(unsigned int) start, 
+						(unsigned int) (pos - start));
+					 
+					 /* Mark this space as dirty. We already have our free space. */
+					 D1(printk("Dirty space: Starting 0x%x for 0x%x bytes\n",
+						   (unsigned int) start, (unsigned int) (pos - start)));
+					 jffs_fmalloced(fmc, (__u32) start,
+							(__u32) (pos - start), 0);				           
+				 }
+				 
+			}
+			if(numFreeSpace > NUMFREEALLOWED){
+			         printk(KERN_WARNING "jffs_scan_flash: Found free space "
+					"number %i. Only 1 free space is allowed.\n", numFreeSpace);			      
 			}
 			continue;
 
@@ -731,61 +981,28 @@
 				  "hexdump(pos = 0x%lx, len = 128):\n",
 				  (long)pos));
 			D1(jffs_hexdump(fmc->mtd, pos, 128));
-		cont_dirty:
+
 			for (pos += 4; pos < end; pos += 4) {
 				switch (flash_read_u32(fmc->mtd, pos)) {
 				case JFFS_MAGIC_BITMASK:
-					jffs_fmalloced(fmc, (__u32) start,
-						       (__u32) (pos - start),
-						       0);
-					goto cont_scan;
 				case JFFS_EMPTY_BITMASK:
-					/* First, mark as dirty the region
-					   which really does contain crap. */
-					jffs_fmalloced(fmc, (__u32) start,
-						       (__u32) (pos - start),
-						       0);
+					/* handle these in the main switch() loop */
+					goto cont_scan;
 
-					/* Then, scan the region which looks free.
-					   Depending on how large it is, we may
-					   mark it dirty too.
-					*/
-					start = pos;
-					for (; pos < end ; pos += 4) {
-						switch (flash_read_u32(fmc->mtd, pos)) {
-						case JFFS_MAGIC_BITMASK:
-							if (pos - start < fmc->max_chunk_size) {
-								/* Not much free space. Mark it dirty. */
-								jffs_fmalloced(fmc, (__u32)start,
-									       (__u32)pos-start, 0);
-							}
-							goto cont_scan;
-
-						case JFFS_EMPTY_BITMASK:
-							/* More empty space */
-							continue;
-				
-						default: 
-							/* i.e. more dirt */
-							if (pos - start < fmc->max_chunk_size) {
-								/* There wasn't much before the dirt
-								   started again. Just mark it all dirty
-								*/
-								goto cont_dirty;
-							}
-							/* There was quite a lot of free space. Leave it
-							   free.
-							*/
-							goto cont_scan;
-						}
-					}
 				default:
 					break;
 				}
 			}
+
 			cont_scan:
+			/* First, mark as dirty the region
+			   which really does contain crap. */
+			jffs_fmalloced(fmc, (__u32) start,
+				       (__u32) (pos - start),
+				       0);
+			
 			continue;
-		}
+		}/* switch */
 
 		/* We have found the beginning of an inode.  Create a
 		   node for it unless there already is one available.  */
@@ -1000,9 +1217,14 @@
 	/* Free read buffer */
 	kfree (read_buf);
 
+	if(!numFreeSpace){
+	        printk(KERN_WARNING "jffs_scan_flash(): Did not find even a single chunk of free space.\n");
+	}
+
 	/* Return happy */
 	D3(printk("jffs_scan_flash(): Leaving...\n"));
 	flash_safe_release(fmc->mtd);
+
 	return 0;
 } /* jffs_scan_flash()  */