X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=1ad630b8a9f4e3c26cc3527717cea0fc9c109bdb;hp=c5d20b17a9e72ae2100d30c707bd423d7e19a168;hb=adf8ff155a242969024595f8750f191be6b8acaf;hpb=b9cc161107778024e07cfb2f1d92dcf8d3248bd6 diff --git a/yaffs_guts.c b/yaffs_guts.c index c5d20b1..1ad630b 100644 --- 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.116 2010-03-09 04:12:00 charles Exp $"; #include "yportenv.h" #include "yaffs_trace.h" @@ -404,16 +404,19 @@ static int yaffs_CountChunkBits(yaffs_Device *dev, int blk) static int yaffs_SkipVerification(yaffs_Device *dev) { + dev=dev; return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); } static int yaffs_SkipFullVerification(yaffs_Device *dev) { + dev=dev; return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); } static int yaffs_SkipNANDVerification(yaffs_Device *dev) { + dev=dev; return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); } @@ -682,12 +685,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. @@ -1050,6 +1047,80 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, return chunk; } + +/* + * Oldest Dirty Sequence Number handling. + */ + +/* yaffs_CalcOldestDirtySequence() + * yaffs_FindOldestDirtySequence() + * Calculate the oldest dirty sequence number if we don't know it. + */ +static int yaffs_CalcOldestDirtySequence(yaffs_Device *dev) +{ + int i; + __u32 seq; + yaffs_BlockInfo *b = 0; + + if(!dev->param.isYaffs2) + return 0; + + /* Find the oldest dirty sequence number. */ + seq = dev->sequenceNumber; + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { + b = yaffs_GetBlockInfo(dev, i); + if (b->blockState == YAFFS_BLOCK_STATE_FULL && + (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock && + b->sequenceNumber < seq) + seq = b->sequenceNumber; + } + return seq; +} + + +static void yaffs_FindOldestDirtySequence(yaffs_Device *dev) +{ + if(dev->param.isYaffs2 && !dev->oldestDirtySequence) + dev->oldestDirtySequence = + yaffs_CalcOldestDirtySequence(dev); + +#if 0 + if(!yaffs_SkipVerification(dev) && + dev->oldestDirtySequence != yaffs_CalcOldestDirtySequence(dev)) + YBUG(); + +#endif +} + +/* + * yaffs_ClearOldestDirtySequence() + * Called when a block is erased or marked bad. (ie. when its sequenceNumber + * becomes invalid). If the value matches the oldest then we clear + * dev->oldestDirtySequence to force its recomputation. + */ +static void yaffs_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi) +{ + + if(!dev->param.isYaffs2) + return; + + if(!bi || bi->sequenceNumber == dev->oldestDirtySequence) + dev->oldestDirtySequence = 0; +} + +/* + * yaffs_UpdateOldestDirtySequence() + * Update the oldest dirty sequence number whenever we dirty a block. + * Only do this if the oldestDirtySequence is actually being tracked. + */ +static void yaffs_UpdateOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi) +{ + if(dev->param.isYaffs2 && dev->oldestDirtySequence){ + if(dev->oldestDirtySequence > bi->sequenceNumber) + dev->oldestDirtySequence = bi->sequenceNumber; + } +} + /* * Block retiring for handling a broken block. */ @@ -1059,6 +1130,8 @@ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); yaffs_InvalidateCheckpoint(dev); + + yaffs_ClearOldestDirtySequence(dev,bi); if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { @@ -1100,11 +1173,18 @@ static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *tags) { + dev=dev; + chunkInNAND=chunkInNAND; + data=data; + tags=tags; } static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, const yaffs_ExtendedTags *tags) { + dev=dev; + chunkInNAND=chunkInNAND; + tags=tags; } void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) @@ -1452,6 +1532,8 @@ static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, int requiredTallness; int level = fStruct->topLevel; + dev=dev; + /* Check sane level and chunk Id */ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) return NULL; @@ -1721,6 +1803,7 @@ static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) if (theBlock) { theBlock->softDeletions++; dev->nFreeChunks++; + yaffs_UpdateOldestDirtySequence(dev,theBlock); } } @@ -2135,33 +2218,21 @@ static void yaffs_InitialiseObjects(yaffs_Device *dev) static int yaffs_FindNiceObjectBucket(yaffs_Device *dev) { - static int x; int i; int l = 999; int lowest = 999999; - /* First let's see if we can find one that's empty. */ - - for (i = 0; i < 10 && lowest > 0; i++) { - x++; - x %= YAFFS_NOBJECT_BUCKETS; - if (dev->objectBucket[x].count < lowest) { - lowest = dev->objectBucket[x].count; - l = x; - } - - } - /* If we didn't find an empty list, then try - * looking a bit further for a short one + /* Search for the shortest list or one that + * isn't too long. */ - for (i = 0; i < 10 && lowest > 3; i++) { - x++; - x %= YAFFS_NOBJECT_BUCKETS; - if (dev->objectBucket[x].count < lowest) { - lowest = dev->objectBucket[x].count; - l = x; + for (i = 0; i < 10 && lowest > 4; i++) { + dev->bucketFinder++; + dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS; + if (dev->objectBucket[dev->bucketFinder].count < lowest) { + lowest = dev->objectBucket[dev->bucketFinder].count; + l = dev->bucketFinder; } } @@ -2287,6 +2358,8 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, case YAFFS_OBJECT_TYPE_DIRECTORY: YINIT_LIST_HEAD(&theObject->variant.directoryVariant. children); + YINIT_LIST_HEAD(&theObject->variant.directoryVariant. + dirty); break; case YAFFS_OBJECT_TYPE_SYMLINK: case YAFFS_OBJECT_TYPE_HARDLINK: @@ -2671,9 +2744,6 @@ static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi) { - int i; - __u32 seq; - yaffs_BlockInfo *b; if (!dev->param.isYaffs2) return 1; /* disqualification only applies to yaffs2. */ @@ -2681,23 +2751,7 @@ static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, if (!bi->hasShrinkHeader) return 1; /* can gc */ - /* Find the oldest dirty sequence number if we don't know it and save it - * so we don't have to keep recomputing it. - */ - if (!dev->oldestDirtySequence) { - seq = dev->sequenceNumber; - - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; - i++) { - b = yaffs_GetBlockInfo(dev, i); - if (b->blockState == YAFFS_BLOCK_STATE_FULL && - (b->pagesInUse - b->softDeletions) < - dev->param.nChunksPerBlock && b->sequenceNumber < seq) { - seq = b->sequenceNumber; - } - } - dev->oldestDirtySequence = seq; - } + yaffs_FindOldestDirtySequence(dev); /* Can't do gc of this block if there are any blocks older than this one that have * discarded pages. @@ -2705,7 +2759,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. */ @@ -2800,8 +2919,6 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, dev->param.nChunksPerBlock - pagesInUse, prioritised)); } - dev->oldestDirtySequence = 0; - if (dirtiest > 0) dev->nonAggressiveSkip = 4; @@ -2822,6 +2939,8 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); + yaffs_ClearOldestDirtySequence(dev,bi); + bi->blockState = YAFFS_BLOCK_STATE_DIRTY; if (!bi->needsRetiring) { @@ -2851,6 +2970,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 +3346,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 +3412,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 +3466,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; } @@ -3685,6 +3813,8 @@ void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) chunkId)); bi = yaffs_GetBlockInfo(dev, block); + + yaffs_UpdateOldestDirtySequence(dev,bi); T(YAFFS_TRACE_DELETION, (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); @@ -3750,9 +3880,9 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, * the tnode now, rather than later when it is harder to clean up. */ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); - if(prevChunkId <= 0 && - !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0)){ - } + if(prevChunkId < 1 && + !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0)) + return 0; /* Set up new tags */ yaffs_InitialiseTags(&newTags); @@ -3769,13 +3899,6 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, YBUG(); } - /* - * If there isn't already a chunk there then do a dummy - * insert to make sue we have the desired tnode structure. - */ - if(prevChunkId < 1 && - yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0) != YAFFS_OK) - return -1; newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, @@ -4266,7 +4389,6 @@ static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, cp->nUnlinkedFiles = dev->nUnlinkedFiles; cp->nBackgroundDeletions = dev->nBackgroundDeletions; cp->sequenceNumber = dev->sequenceNumber; - cp->oldestDirtySequence = dev->oldestDirtySequence; } @@ -4282,7 +4404,6 @@ static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, dev->nUnlinkedFiles = cp->nUnlinkedFiles; dev->nBackgroundDeletions = cp->nBackgroundDeletions; dev->sequenceNumber = cp->sequenceNumber; - dev->oldestDirtySequence = cp->oldestDirtySequence; } @@ -4737,9 +4858,9 @@ static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) dev->blocksInCheckpoint > 0) { dev->isCheckpointed = 0; yaffs_CheckpointInvalidateStream(dev); - if (dev->param.markSuperBlockDirty) - dev->param.markSuperBlockDirty(dev); } + if (dev->param.markSuperBlockDirty) + dev->param.markSuperBlockDirty(dev); } @@ -5158,7 +5279,6 @@ int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) in->variant.fileVariant.fileSize = newSize; } - /* Write a new object header to reflect the resize. * show we've shrunk the file, if need be * Do this only if the file is not in the deleted directories @@ -5351,6 +5471,10 @@ int retVal = -1; retVal = yaffs_DeleteFile(obj); break; case YAFFS_OBJECT_TYPE_DIRECTORY: + if(!ylist_empty(&obj->variant.directoryVariant.dirty)){ + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->objectId)); + ylist_del_init(&obj->variant.directoryVariant.dirty); + } return yaffs_DeleteDirectory(obj); break; case YAFFS_OBJECT_TYPE_SYMLINK: @@ -5425,6 +5549,7 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) return yaffs_DeleteFile(obj); break; case YAFFS_OBJECT_TYPE_DIRECTORY: + ylist_del_init(&obj->variant.directoryVariant.dirty); return yaffs_DeleteDirectory(obj); break; case YAFFS_OBJECT_TYPE_SYMLINK: @@ -6472,35 +6597,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 +6633,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 +6717,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 +6891,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: @@ -6949,17 +7058,57 @@ static void yaffs_VerifyDirectory(yaffs_Object *directory) * create dir/a : update dir's mtime/ctime * rm dir/a: update dir's mtime/ctime * modify dir/a: don't update dir's mtimme/ctime + * + * This can be handled immediately or defered. Defering helps reduce the number + * of updates when many files in a directory are changed within a brief period. + * + * If the directory updating is defered then yaffs_UpdateDirtyDirecories must be + * called periodically. */ static void yaffs_UpdateParent(yaffs_Object *obj) { + yaffs_Device *dev; if(!obj) return; + dev = obj->myDev; obj->dirty = 1; obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME; + if(dev->param.deferDirectoryUpdate){ + struct ylist_head *link = &obj->variant.directoryVariant.dirty; + + if(ylist_empty(link)){ + ylist_add(link,&dev->dirtyDirectories); + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->objectId)); + } - yaffs_UpdateObjectHeader(obj,NULL,0,0,0); + } else + yaffs_UpdateObjectHeader(obj,NULL,0,0,0); +} + +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev) +{ + struct ylist_head *link; + yaffs_Object *obj; + yaffs_DirectoryStructure *dS; + yaffs_ObjectVariant *oV; + + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR))); + + while(!ylist_empty(&dev->dirtyDirectories)){ + link = dev->dirtyDirectories.next; + ylist_del_init(link); + + dS=ylist_entry(link,yaffs_DirectoryStructure,dirty); + oV = ylist_entry(dS,yaffs_ObjectVariant,directoryVariant); + obj = ylist_entry(oV,yaffs_Object,variant); + + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId)); + + if(obj->dirty) + yaffs_UpdateObjectHeader(obj,NULL,0,0,0); + } } static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) @@ -7570,6 +7719,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->nErasedBlocks = 0; dev->isDoingGC = 0; dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ + YINIT_LIST_HEAD(&dev->dirtyDirectories); + dev->oldestDirtySequence = 0; /* Initialise temporary buffers and caches. */ if (!yaffs_InitialiseTempBuffers(dev)) @@ -7652,7 +7803,6 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->nDeletedFiles = 0; dev->nUnlinkedFiles = 0; dev->nBackgroundDeletions = 0; - dev->oldestDirtySequence = 0; if (!init_failed && !yaffs_InitialiseBlocks(dev)) init_failed = 1;