Add block refreshing feature
authorcharles <charles>
Thu, 25 Feb 2010 22:41:46 +0000 (22:41 +0000)
committercharles <charles>
Thu, 25 Feb 2010 22:41:46 +0000 (22:41 +0000)
Kconfig
direct/yaffscfg2k.c
moduleconfig.h
yaffs_fs.c
yaffs_guts.c
yaffs_guts.h

diff --git a/Kconfig b/Kconfig
index 4a8b0c8f6eb507c1288348eaa303a0d9a00bc5ac..073f54170062d81f0d88a092fa644edec2c6c70a 100644 (file)
--- 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.
index 7731ade5bfdbabdcfbed1c087a1d6e2451c4e874..3c0341c5cd35bad700cceb4853367292f0399ef1 100644 (file)
@@ -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;
index 64689076902c57b34081966c66398b8f0a7e5102..f58b8e25b4558d367e5cf4d72c5869db85443ca2 100644 (file)
 /* 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
index 0d219f64160fb1e30db673675ac0715ec29c9182..8b11f4034c4896c54d6099d8256027c77b521f86 100644 (file)
@@ -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_internal_read_super(int yaffsVersion,
 #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, yaffs_Device * dev)
        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, yaffs_Device * dev)
        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, yaffs_Device * dev)
        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)
index c5d20b17a9e72ae2100d30c707bd423d7e19a168..dc9742ba84be4baeb92b830fc6ea20d95a52680b 100644 (file)
@@ -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_Object *obj)
 
        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_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
        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_Device *dev, int blockNo)
        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(yaffs_Device *dev, int block,
                                                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(yaffs_Device *dev, int block,
 
        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(yaffs_Device *dev)
                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 (dev->gcBlock <= 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 < 1) {
                        dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
                        dev->gcChunk = 0;
                }
@@ -6472,35 +6540,26 @@ static int yaffs_ScanBackwards(yaffs_Device *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_Device *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_Device *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_Device *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:
index 53ab280aa67173d3dec74dba29b42805b34c77ca..7d2ab53011e909346de68de72bda99a8203400cf 100644 (file)
@@ -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;