changeset 365:db12031081bc

Add block refreshing feature
author charles <charles>
date Thu, 25 Feb 2010 22:41:46 +0000
parents 578449a365d7
children 2a0c6f4e34ec
files Kconfig direct/yaffscfg2k.c moduleconfig.h yaffs_fs.c yaffs_guts.c yaffs_guts.h
diffstat 6 files changed, 159 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/Kconfig
+++ b/Kconfig
@@ -175,3 +175,12 @@ config YAFFS_EMPTY_LOST_AND_FOUND
 	  If this is enabled then the contents of lost and found is
 	  automatically dumped at mount.
 
+config YAFFS_DISABLE_BLOCK_REFRESHING
+	boot "Disable yaffs2 block refreshing"
+	depends on YAFFS_FS
+	default n
+	help
+	 If this is set, then block refreshing is disabled.
+	 Block refreshing infrequently refreshes the oldest block in
+	 a yaffs2 file system. This mechanism helps to refresh flash to
+	 mitigate against data loss. This is particularly useful for MLC.
--- a/direct/yaffscfg2k.c
+++ b/direct/yaffscfg2k.c
@@ -182,6 +182,7 @@ int yaffs_StartUp(void)
 	flashDev.param.isYaffs2 = 1;
 	flashDev.param.useNANDECC=1;
 	flashDev.param.wideTnodesDisabled=0;
+	flashDev.param.refreshPeriod = 10000;
 	flashDev.param.nShortOpCaches = 10; // Use caches
 	flashDev.context = (void *) 2;	// Used to identify the device in fstat.
 	flashDev.param.writeChunkWithTagsToNAND = yflash2_WriteChunkWithTagsToNAND;
--- a/moduleconfig.h
+++ b/moduleconfig.h
@@ -46,15 +46,17 @@
 /* Meaning: At mount automatically empty all files from lost and found. */
 /* This is done to fix an old problem where rmdir was not checking for an */
 /* empty directory. This can also be achieved with a mount option. */
-/* #define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND */
+#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
 
 /* Default: Selected */
 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
 
-/* Default: 10 */
-/* Meaning: set the count of blocks to reserve for checkpointing */
-#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
+/* Default: Unselected */
+/* Meaning: Select to disable block refreshing. */
+/* Block Refreshing periodically rewrites the oldest block. */
+/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
+
 
 /*
 Older-style on-NAND data format has a "pageStatus" byte to record
--- a/yaffs_fs.c
+++ b/yaffs_fs.c
@@ -32,7 +32,7 @@
  */
 
 const char *yaffs_fs_c_version =
-    "$Id: yaffs_fs.c,v 1.95 2010-02-19 01:19:12 charles Exp $";
+    "$Id: yaffs_fs.c,v 1.96 2010-02-25 22:41:46 charles Exp $";
 extern const char *yaffs_guts_c_version;
 
 #include <linux/version.h>
@@ -2301,6 +2301,13 @@ static struct super_block *yaffs_interna
 #ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
 	param->emptyLostAndFound = 1;
 #endif
+
+#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
+	param->refreshPeriod = 0;
+#else
+	param->refreshPeriod = 10000;
+#endif
+
 	if(options.empty_lost_and_found_overridden)
 		param->emptyLostAndFound = options.empty_lost_and_found;
 
@@ -2514,6 +2521,22 @@ static char *yaffs_dump_dev_part0(char *
 	buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
 	buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
 	buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
+	buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
+	buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
+	buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
+	buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
+	buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
+	buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
+	buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
+
+	buf += sprintf(buf, "\n");
+
+	return buf;
+}
+
+
+static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
+{
 	buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
 	buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
 	buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
@@ -2530,8 +2553,7 @@ static char *yaffs_dump_dev_part0(char *
 	buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
 	buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
 	buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
-	buf += sprintf(buf, "passiveGCs......... %d\n",
-		    dev->passiveGarbageCollections);
+	buf += sprintf(buf, "passiveGCs......... %d\n", dev->passiveGarbageCollections);
 	buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
 	buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
 	buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
@@ -2542,25 +2564,13 @@ static char *yaffs_dump_dev_part0(char *
 	buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
 	buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
 	buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
+	buf += sprintf(buf, "refreshCount....... %d\n", dev->refreshCount);
 	buf +=
 	    sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
 
 	return buf;
 }
 
-
-static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
-{
-	buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
-	buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
-	buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
-	buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
-	buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
-	buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
-
-	return buf;
-}
-
 static int yaffs_proc_read(char *page,
 			   char **start,
 			   off_t offset, int count, int *eof, void *data)
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -12,7 +12,7 @@
  */
 
 const char *yaffs_guts_c_version =
-    "$Id: yaffs_guts.c,v 1.109 2010-02-24 21:06:39 charles Exp $";
+    "$Id: yaffs_guts.c,v 1.110 2010-02-25 22:41:46 charles Exp $";
 
 #include "yportenv.h"
 #include "yaffs_trace.h"
@@ -682,12 +682,6 @@ static void yaffs_VerifyFile(yaffs_Objec
 
 	actualTallness = obj->variant.fileVariant.topLevel;
 
-	if (requiredTallness > actualTallness)
-		T(YAFFS_TRACE_VERIFY,
-		(TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
-		 obj->objectId, actualTallness, requiredTallness));
-
-
 	/* Check that the chunks in the tnode tree are all correct.
 	 * We do this by scanning through the tnode tree and
 	 * checking the tags for every chunk match.
@@ -2705,7 +2699,72 @@ static int yaffs_BlockNotDisqualifiedFro
 	return (bi->sequenceNumber <= dev->oldestDirtySequence);
 }
 
-/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
+/*
+ * yaffs_FindRefreshBlock()
+ * periodically finds the oldest full block by sequence number for refreshing.
+ * Only for yaffs2.
+ */
+static __u32 yaffs_FindRefreshBlock(yaffs_Device *dev)
+{
+	__u32 b ;
+
+	__u32 oldest = 0;
+	__u32 oldestSequence = 0;
+
+	yaffs_BlockInfo *bi;
+
+	/*
+	 * If refresh period < 10 then refreshing is disabled.
+	 */
+	if(dev->param.refreshPeriod < 10 ||
+		!dev->param.isYaffs2)
+	        return oldest;
+
+        /*
+         * Fix broken values.
+         */
+        if(dev->refreshSkip > dev->param.refreshPeriod)
+                dev->refreshSkip = dev->param.refreshPeriod;
+
+	if(dev->refreshSkip > 0){
+	        dev->refreshSkip--;
+	        return oldest;
+	}
+
+	/*
+	 * Refresh skip is now zero.
+	 * We'll do a refresh this time around....
+	 * Update the refresh skip and find the oldest block.
+	 */
+	dev->refreshSkip = dev->param.refreshPeriod;
+	dev->refreshCount++;
+
+	for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
+
+		bi = yaffs_GetBlockInfo(dev, b);
+		
+
+		if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
+
+			if(oldest < 1 ||
+                                bi->sequenceNumber < oldestSequence){
+                                oldest = b;
+                                oldestSequence = bi->sequenceNumber;
+                        }
+		}
+	}
+
+	if (oldest > 0) {
+		T(YAFFS_TRACE_GC,
+		  (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
+		   dev->refreshCount, oldest, oldestSequence));
+	}
+
+	return oldest;
+}
+
+/*
+ * FindDiretiestBlock is used to select the dirtiest block (or close enough)
  * for garbage collection.
  */
 
@@ -2851,6 +2910,7 @@ static void yaffs_BlockBecameDirty(yaffs
 	if (erasedOk) {
 		/* Clean it up... */
 		bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+		bi->sequenceNumber = 0;
 		dev->nErasedBlocks++;
 		bi->pagesInUse = 0;
 		bi->softDeletions = 0;
@@ -3226,13 +3286,16 @@ static int yaffs_GarbageCollectBlock(yaf
 						tags.extraIsShrinkHeader = 0;
 						oh->shadowsObject = 0;
 						oh->inbandShadowsObject = 0;
+						if(object->variantType == YAFFS_OBJECT_TYPE_FILE)
+							oh->fileSize = object->variant.fileVariant.fileSize;
 						tags.extraShadows = 0;
 
 						yaffs_VerifyObjectHeader(object, oh, &tags, 1);
-					}
-
-					newChunk =
-					    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
+						newChunk =
+						    yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1);
+					} else
+						newChunk =
+						    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
 
 					if (newChunk < 0) {
 						retVal = YAFFS_FAIL;
@@ -3289,16 +3352,17 @@ static int yaffs_GarbageCollectBlock(yaf
 
 	yaffs_VerifyCollectedBlock(dev, bi, block);
 
-	chunksAfter = yaffs_GetErasedChunks(dev);
-	if (chunksBefore >= chunksAfter) {
-		T(YAFFS_TRACE_GC,
-		  (TSTR
-		   ("gc did not increase free chunks before %d after %d"
-		    TENDSTR), chunksBefore, chunksAfter));
-	}
+
 
 	/* If the gc completed then clear the current gcBlock so that we find another. */
 	if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
+		chunksAfter = yaffs_GetErasedChunks(dev);
+		if (chunksBefore >= chunksAfter) {
+			T(YAFFS_TRACE_GC,
+			  (TSTR
+			   ("gc did not increase free chunks before %d after %d"
+			    TENDSTR), chunksBefore, chunksAfter));
+		}
 		dev->gcBlock = -1;
 		dev->gcChunk = 0;
 	}
@@ -3342,15 +3406,19 @@ static int yaffs_CheckGarbageCollection(
 		if (checkpointBlockAdjust < 0)
 			checkpointBlockAdjust = 0;
 
-		if (dev->nErasedBlocks < (dev->param.nReservedBlocks + checkpointBlockAdjust + 2)) {
-			/* We need a block soon...*/
+		/* If we need a block soon then do aggressive gc.*/
+		if (dev->nErasedBlocks < (dev->param.nReservedBlocks + checkpointBlockAdjust + 2))
 			aggressive = 1;
-		} else {
-			/* We're in no hurry */
+		else
 			aggressive = 0;
+
+                /* If we don't already have a block being gc'd then see if we should start another */
+
+		if (dev->gcBlock < 1 && !aggressive) {
+			dev->gcBlock = yaffs_FindRefreshBlock(dev);
+			dev->gcChunk = 0;
 		}
-
-		if (dev->gcBlock <= 0) {
+		if (dev->gcBlock < 1) {
 			dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
 			dev->gcChunk = 0;
 		}
@@ -6472,35 +6540,26 @@ static int yaffs_ScanBackwards(yaffs_Dev
 
 				if (in &&
 				    in->variantType == YAFFS_OBJECT_TYPE_FILE
-				    && chunkBase <
-				    in->variant.fileVariant.shrinkSize) {
+				    && chunkBase < in->variant.fileVariant.shrinkSize) {
 					/* This has not been invalidated by a resize */
-					if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
-							       chunk, -1)) {
+					if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
 						alloc_failed = 1;
 					}
 
 					/* File size is calculated by looking at the data chunks if we have not
 					 * seen an object header yet. Stop this practice once we find an object header.
 					 */
-					endpos =
-					    (tags.chunkId -
-					     1) * dev->nDataBytesPerChunk +
-					    tags.byteCount;
+					endpos = chunkBase + tags.byteCount;
 
 					if (!in->valid &&	/* have not got an object header yet */
-					    in->variant.fileVariant.
-					    scannedFileSize < endpos) {
-						in->variant.fileVariant.
-						    scannedFileSize = endpos;
-						in->variant.fileVariant.
-						    fileSize =
-						    in->variant.fileVariant.
-						    scannedFileSize;
+					    in->variant.fileVariant.scannedFileSize < endpos) {
+						in->variant.fileVariant.scannedFileSize = endpos;
+						in->variant.fileVariant.fileSize = endpos;
 					}
 
 				} else if (in) {
-					/* This chunk has been invalidated by a resize, so delete */
+					/* This chunk has been invalidated by a resize, or a past file deletion
+					 * so delete the chunk*/
 					yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
 
 				}
@@ -6517,9 +6576,9 @@ static int yaffs_ScanBackwards(yaffs_Dev
 				in = NULL;
 
 				if (tags.extraHeaderInfoAvailable) {
-					in = yaffs_FindOrCreateObjectByNumber
-					    (dev, tags.objectId,
-					     tags.extraObjectType);
+					in = yaffs_FindOrCreateObjectByNumber(dev,
+						tags.objectId,
+						tags.extraObjectType);
 					if (!in)
 						alloc_failed = 1;
 				}
@@ -6601,13 +6660,8 @@ static int yaffs_ScanBackwards(yaffs_Dev
 							isShrink = 1;
 						}
 
-						if (isShrink &&
-						    in->variant.fileVariant.
-						    shrinkSize > thisSize) {
-							in->variant.fileVariant.
-							    shrinkSize =
-							    thisSize;
-						}
+						if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
+							in->variant.fileVariant.shrinkSize = thisSize;
 
 						if (isShrink)
 							bi->hasShrinkHeader = 1;
@@ -6780,14 +6834,12 @@ static int yaffs_ScanBackwards(yaffs_Dev
 							 * than its current data extents.
 							 */
 							in->variant.fileVariant.fileSize = fileSize;
-							in->variant.fileVariant.scannedFileSize =
-							    in->variant.fileVariant.fileSize;
+							in->variant.fileVariant.scannedFileSize = fileSize;
 						}
 
-						if (isShrink &&
-						    in->variant.fileVariant.shrinkSize > fileSize) {
+						if (in->variant.fileVariant.shrinkSize > fileSize)
 							in->variant.fileVariant.shrinkSize = fileSize;
-						}
+				
 
 						break;
 					case YAFFS_OBJECT_TYPE_HARDLINK:
--- a/yaffs_guts.h
+++ b/yaffs_guts.h
@@ -557,6 +557,8 @@ struct yaffs_DeviceParamStruct {
 
 	int emptyLostAndFound;  /* Auto-empty lost+found directory on mount */
 
+	int refreshPeriod;	/* How often we should check to do a block refresh */
+
 	/* Checkpoint control. Can be set before or after initialisation */
 	__u8 skipCheckpointRead;
 	__u8 skipCheckpointWrite;
@@ -723,8 +725,6 @@ struct yaffs_DeviceStruct {
 	yaffs_ChunkCache *srCache;
 	int srLastUse;
 
-	int cacheHits;
-
 	/* Stuff for background deletion and unlinked files.*/
 	yaffs_Object *unlinkedDir;	/* Directory where unlinked and deleted files live. */
 	yaffs_Object *deletedDir;	/* Directory where deleted objects are sent to disappear. */
@@ -733,7 +733,6 @@ struct yaffs_DeviceStruct {
 	int nUnlinkedFiles;		/* Count of unlinked files. */
 	int nBackgroundDeletions;	/* Count of background deletions. */
 
-
 	/* Temporary buffer management */
 	yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
 	int maxTemp;
@@ -744,7 +743,9 @@ struct yaffs_DeviceStruct {
 	/* yaffs2 runtime stuff */
 	unsigned sequenceNumber;	/* Sequence number of currently allocating block */
 	unsigned oldestDirtySequence;
-	
+
+	/* Block refreshing */
+	int refreshSkip;	/* A skip down counter. Refresh happens when this gets to zero. */
 
 	/* Statistcs */
 	int nPageWrites;
@@ -762,6 +763,9 @@ struct yaffs_DeviceStruct {
 	int tagsEccUnfixed;
 	int nDeletions;
 	int nUnmarkedDeletions;
+	int refreshCount;
+	int cacheHits;
+
 };
 
 typedef struct yaffs_DeviceStruct yaffs_Device;