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.
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;
/* 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
*/
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>
#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;
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, "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, "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)
*/
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"
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.
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.
*/
if (erasedOk) {
/* Clean it up... */
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+ bi->sequenceNumber = 0;
dev->nErasedBlocks++;
bi->pagesInUse = 0;
bi->softDeletions = 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);
- }
-
- 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;
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;
}
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;
}
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__);
}
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;
}
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;
* 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:
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;
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. */
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
-
/* Temporary buffer management */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp;
/* 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;
int tagsEccUnfixed;
int nDeletions;
int nUnmarkedDeletions;
+ int refreshCount;
+ int cacheHits;
+
};
typedef struct yaffs_DeviceStruct yaffs_Device;