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 4a8b0c8..073f541 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.
 
          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 7731ade..3c0341c 100644 (file)
@@ -182,6 +182,7 @@ int yaffs_StartUp(void)
        flashDev.param.isYaffs2 = 1;
        flashDev.param.useNANDECC=1;
        flashDev.param.wideTnodesDisabled=0;
        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;
        flashDev.param.nShortOpCaches = 10; // Use caches
        flashDev.context = (void *) 2;  // Used to identify the device in fstat.
        flashDev.param.writeChunkWithTagsToNAND = yflash2_WriteChunkWithTagsToNAND;
index 6468907..f58b8e2 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. */
 /* 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: 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
 
 /*
 Older-style on-NAND data format has a "pageStatus" byte to record
index 0d219f6..8b11f40 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 const char *yaffs_fs_c_version =
  */
 
 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>
 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_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;
 
        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, "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);
        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, "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);
        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, "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;
 }
 
        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)
 static int yaffs_proc_read(char *page,
                           char **start,
                           off_t offset, int count, int *eof, void *data)
index c5d20b1..dc9742b 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 const char *yaffs_guts_c_version =
  */
 
 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"
 
 #include "yportenv.h"
 #include "yaffs_trace.h"
@@ -682,12 +682,6 @@ static void yaffs_VerifyFile(yaffs_Object *obj)
 
        actualTallness = obj->variant.fileVariant.topLevel;
 
 
        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.
        /* 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);
 }
 
        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.
  */
 
  * 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;
        if (erasedOk) {
                /* Clean it up... */
                bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+               bi->sequenceNumber = 0;
                dev->nErasedBlocks++;
                bi->pagesInUse = 0;
                bi->softDeletions = 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;
                                                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);
                                                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;
 
                                        if (newChunk < 0) {
                                                retVal = YAFFS_FAIL;
@@ -3289,16 +3352,17 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
 
        yaffs_VerifyCollectedBlock(dev, bi, 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) {
 
        /* 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;
        }
                dev->gcBlock = -1;
                dev->gcChunk = 0;
        }
@@ -3342,15 +3406,19 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
                if (checkpointBlockAdjust < 0)
                        checkpointBlockAdjust = 0;
 
                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;
                        aggressive = 1;
-               } else {
-                       /* We're in no hurry */
+               else
                        aggressive = 0;
                        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;
                }
                        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
 
                                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 */
                                        /* 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.
                                         */
                                                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 */
 
                                        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) {
                                        }
 
                                } 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__);
 
                                }
                                        yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
 
                                }
@@ -6517,9 +6576,9 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                in = NULL;
 
                                if (tags.extraHeaderInfoAvailable) {
                                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;
                                }
                                        if (!in)
                                                alloc_failed = 1;
                                }
@@ -6601,13 +6660,8 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                                        isShrink = 1;
                                                }
 
                                                        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;
 
                                                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;
                                                         * 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;
                                                        in->variant.fileVariant.shrinkSize = fileSize;
-                                               }
+                               
 
                                                break;
                                        case YAFFS_OBJECT_TYPE_HARDLINK:
 
                                                break;
                                        case YAFFS_OBJECT_TYPE_HARDLINK:
index 53ab280..7d2ab53 100644 (file)
@@ -557,6 +557,8 @@ struct yaffs_DeviceParamStruct {
 
        int emptyLostAndFound;  /* Auto-empty lost+found directory on mount */
 
 
        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;
        /* 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;
 
        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. */
        /* 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. */
 
        int nUnlinkedFiles;             /* Count of unlinked files. */
        int nBackgroundDeletions;       /* Count of background deletions. */
 
-
        /* Temporary buffer management */
        yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
        int maxTemp;
        /* 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;
        /* 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;
 
        /* Statistcs */
        int nPageWrites;
@@ -762,6 +763,9 @@ struct yaffs_DeviceStruct {
        int tagsEccUnfixed;
        int nDeletions;
        int nUnmarkedDeletions;
        int tagsEccUnfixed;
        int nDeletions;
        int nUnmarkedDeletions;
+       int refreshCount;
+       int cacheHits;
+
 };
 
 typedef struct yaffs_DeviceStruct yaffs_Device;
 };
 
 typedef struct yaffs_DeviceStruct yaffs_Device;