From c565b5da13774bc9d5f661d93a127ba86a8769e7 Mon Sep 17 00:00:00 2001 From: Charles Manning Date: Fri, 16 Apr 2010 12:13:27 +1200 Subject: [PATCH] work in progress --- linux-tests/gather_data.sh | 2 +- linux-tests/mkfiles | 6 +- yaffs_fs.c | 73 ++++++- yaffs_guts.c | 394 ++++++++++++++++++++++--------------- yaffs_guts.h | 21 +- 5 files changed, 322 insertions(+), 174 deletions(-) diff --git a/linux-tests/gather_data.sh b/linux-tests/gather_data.sh index 4a463fd..8c99653 100755 --- a/linux-tests/gather_data.sh +++ b/linux-tests/gather_data.sh @@ -10,5 +10,5 @@ str=$(cat /proc/yaffs_debug) echo "$i, $str" echo "$i, $str" >> $the_file let i=$i+1 -sleep 1 +sleep 0.5 done diff --git a/linux-tests/mkfiles b/linux-tests/mkfiles index acac482..4488337 100755 --- a/linux-tests/mkfiles +++ b/linux-tests/mkfiles @@ -2,12 +2,12 @@ TREE_BASE=/mnt/dirtree -for (( f=0; f<50; f++ )) +for (( f=0; f<500; f++ )) do - for (( d=0; d<50; d++ )) + for (( d=0; d<10; d++ )) do mkdir -p $TREE_BASE/dir$d - dd bs=1024 count=20 if=/dev/zero of=$TREE_BASE/dir$d/file$f + dd bs=1024 count=5 if=/dev/zero of=$TREE_BASE/dir$d/file$f done done diff --git a/yaffs_fs.c b/yaffs_fs.c index 0ee40e7..5c0157a 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -69,6 +69,7 @@ extern const char *yaffs_guts_c_version; #ifdef YAFFS_COMPILE_BACKGROUND #include #include +#include #endif @@ -1976,26 +1977,84 @@ static int yaffs_do_sync_fs(struct super_block *sb, int do_checkpoint) */ #ifdef YAFFS_COMPILE_BACKGROUND + +void yaffs_background_waker(unsigned long data) +{ + wake_up_process((struct task_struct *)data); +} + static int yaffs_BackgroundThread(void *data) { yaffs_Device *dev = (yaffs_Device *)data; struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev); + unsigned long now = jiffies; + unsigned long next_dir_update = now; + unsigned long next_gc = now; + unsigned long expires; + + int gcResult; + unsigned int erasedChunks; + struct timer_list timer; T(YAFFS_TRACE_BACKGROUND, ("yaffs_background starting for dev %p\n", (void *)dev)); - + + set_freezable(); + while(context->bgRunning){ T(YAFFS_TRACE_BACKGROUND, ("yaffs_background\n")); if(kthread_should_stop()) break; + + if(try_to_freeze()) + continue; + yaffs_GrossLock(dev); - yaffs_UpdateDirtyDirectories(dev); + + now = jiffies; + + if(time_after(now, next_dir_update) && + !dev->isCheckpointed){ + yaffs_UpdateDirtyDirectories(dev); + next_dir_update = now + HZ; + } + + if(time_after(now,next_gc) && + ! dev->isCheckpointed){ + gcResult = yaffs_BackgroundGarbageCollect(dev); + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; + if(erasedChunks < dev->nFreeChunks/4) + next_gc = now + HZ/50+1; + else if(erasedChunks < dev->nFreeChunks/2) + next_gc = now + HZ/20+1; + else + next_gc = now + HZ * 2; + } yaffs_GrossUnlock(dev); - msleep(500); +#if 1 + expires = next_dir_update; + if (time_before(next_gc,expires)) + expires = next_gc; + if(time_before(expires,now)) + expires = now + HZ; + + init_timer(&timer); + timer.expires = expires+1; + timer.data = (unsigned long) current; + timer.function = yaffs_background_waker; + + set_current_state(TASK_INTERRUPTIBLE); + add_timer(&timer); + schedule(); + del_timer_sync(&timer); +#else + msleep(10); +#endif } + return 0; } @@ -2173,6 +2232,10 @@ static void yaffs_put_super(struct super_block *sb) T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ("Shutting down yaffs background thread\n")); + yaffs_BackgroundStop(dev); + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ("yaffs background thread shut down\n")); + yaffs_GrossLock(dev); yaffs_FlushSuperBlock(sb,1); @@ -2180,7 +2243,6 @@ static void yaffs_put_super(struct super_block *sb) if (yaffs_DeviceToContext(dev)->putSuperFunc) yaffs_DeviceToContext(dev)->putSuperFunc(sb); - yaffs_BackgroundStop(dev); yaffs_Deinitialise(dev); @@ -2545,7 +2607,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, #ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING param->refreshPeriod = 0; #else - param->refreshPeriod = 10000; + param->refreshPeriod = 100; #endif if(options.empty_lost_and_found_overridden) @@ -3133,6 +3195,7 @@ static void __exit exit_yaffs_fs(void) " removing. \n")); remove_proc_entry("yaffs", YPROC_ROOT); + remove_proc_entry("yaffs_debug", YPROC_ROOT); fsinst = fs_to_install; diff --git a/yaffs_guts.c b/yaffs_guts.c index feade2a..65e33a6 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -34,7 +34,9 @@ const char *yaffs_guts_c_version = #include "yaffs_packedtags2.h" -#define YAFFS_PASSIVE_GC_CHUNKS 2 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ +#define YAFFS_GC_GOOD_ENOUGH 2 +#define YAFFS_GC_PASSIVE_THRESHOLD 4 #define YAFFS_SMALL_HOLE_THRESHOLD 3 #include "yaffs_ecc.h" @@ -1058,41 +1060,41 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, * yaffs_FindOldestDirtySequence() * Calculate the oldest dirty sequence number if we don't know it. */ -static int yaffs_CalcOldestDirtySequence(yaffs_Device *dev) +static void yaffs_CalcOldestDirtySequence(yaffs_Device *dev) { int i; - __u32 seq; + unsigned seq; + unsigned blockNo = 0; yaffs_BlockInfo *b; if(!dev->param.isYaffs2) - return 0; + return; /* Find the oldest dirty sequence number. */ - seq = dev->sequenceNumber; + seq = dev->sequenceNumber + 1; b = dev->blockInfo; for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { if (b->blockState == YAFFS_BLOCK_STATE_FULL && - (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock && - b->sequenceNumber < seq) - seq = b->sequenceNumber; + (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock && + b->sequenceNumber < seq) { + seq = b->sequenceNumber; + blockNo = i; + } b++; } - return seq; + + if(blockNo){ + dev->oldestDirtySequence = seq; + dev->oldestDirtyBlock = blockNo; + } + } 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_CalcOldestDirtySequence(dev); } /* @@ -1107,8 +1109,10 @@ static void yaffs_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *b if(!dev->param.isYaffs2) return; - if(!bi || bi->sequenceNumber == dev->oldestDirtySequence) + if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){ dev->oldestDirtySequence = 0; + dev->oldestDirtyBlock = 0; + } } /* @@ -1116,11 +1120,13 @@ static void yaffs_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *b * 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) +static void yaffs_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi) { if(dev->param.isYaffs2 && dev->oldestDirtySequence){ - if(dev->oldestDirtySequence > bi->sequenceNumber) + if(dev->oldestDirtySequence > bi->sequenceNumber){ dev->oldestDirtySequence = bi->sequenceNumber; + dev->oldestDirtyBlock = blockNo; + } } } @@ -1799,14 +1805,16 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) { yaffs_BlockInfo *theBlock; + unsigned blockNo; T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->param.nChunksPerBlock); + blockNo = chunk / dev->param.nChunksPerBlock; + theBlock = yaffs_GetBlockInfo(dev, blockNo); if (theBlock) { theBlock->softDeletions++; dev->nFreeChunks++; - yaffs_UpdateOldestDirtySequence(dev,theBlock); + yaffs_UpdateOldestDirtySequence(dev, blockNo, theBlock); } } @@ -2667,12 +2675,12 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, * Note we must disable gc otherwise it can mess up the shadowing. * */ - dev->isDoingGC=1; + dev->gcDisable=1; yaffs_ChangeObjectName(obj, newDir, newName, force, existingTarget->objectId); existingTarget->isShadowed = 1; yaffs_UnlinkObject(existingTarget); - dev->isDoingGC=0; + dev->gcDisable=0; } result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); @@ -2789,10 +2797,8 @@ static __u32 yaffs_FindRefreshBlock(yaffs_Device *dev) if(dev->refreshSkip > dev->param.refreshPeriod) dev->refreshSkip = dev->param.refreshPeriod; - if(dev->refreshSkip > 0){ - dev->refreshSkip--; + if(dev->refreshSkip > 0) return oldest; - } /* * Refresh skip is now zero. @@ -2824,106 +2830,6 @@ static __u32 yaffs_FindRefreshBlock(yaffs_Device *dev) return oldest; } -/* - * FindDiretiestBlock is used to select the dirtiest block (or close enough) - * for garbage collection. - */ - -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, - int aggressive) -{ - int b = dev->currentDirtyChecker; - - int i; - int iterations; - int dirtiest = -1; - int pagesInUse = 0; - int prioritised = 0; - yaffs_BlockInfo *bi; - int pendingPrioritisedExist = 0; - - /* First let's see if we need to grab a prioritised block */ - if (dev->hasPendingPrioritisedGCs) { - bi = dev->blockInfo; - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) { - - if (bi->gcPrioritise) { - pendingPrioritisedExist = 1; - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { - pagesInUse = (bi->pagesInUse - bi->softDeletions); - dirtiest = i; - prioritised = 1; - aggressive = 1; /* Fool the non-aggressive skip logiv below */ - } - } - bi++; - } - - if (!pendingPrioritisedExist) /* None found, so we can clear this */ - dev->hasPendingPrioritisedGCs = 0; - } - - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and - * search harder. - * else (we're doing a leasurely gc), then we only bother to do this if the - * block has only a few pages in use. - */ - - dev->nonAggressiveSkip--; - - if (!aggressive && (dev->nonAggressiveSkip > 0)) - return -1; - - if (!prioritised) - pagesInUse = - (aggressive) ? dev->param.nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; - - if (aggressive) - iterations = - dev->internalEndBlock - dev->internalStartBlock + 1; - else { - iterations = - dev->internalEndBlock - dev->internalStartBlock + 1; - iterations = iterations / 16; - if (iterations > 200) - iterations = 200; - } - - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { - b++; - if (b < dev->internalStartBlock || b > dev->internalEndBlock) - b = dev->internalStartBlock; - - if (b < dev->internalStartBlock || b > dev->internalEndBlock) { - T(YAFFS_TRACE_ERROR, - (TSTR("**>> Block %d is not valid" TENDSTR), b)); - YBUG(); - } - - bi = yaffs_GetBlockInfo(dev, b); - - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && - (bi->pagesInUse - bi->softDeletions) < pagesInUse && - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { - dirtiest = b; - pagesInUse = (bi->pagesInUse - bi->softDeletions); - } - } - - dev->currentDirtyChecker = b; - - if (dirtiest > 0) { - T(YAFFS_TRACE_GC, - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, - dev->param.nChunksPerBlock - pagesInUse, prioritised)); - } - - if (dirtiest > 0) - dev->nonAggressiveSkip = 4; - - return dirtiest; -} static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) { @@ -2945,7 +2851,13 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) /* If this is the block being garbage collected then stop gc'ing this block */ if(blockNo == dev->gcBlock) - dev->gcBlock = -1; + dev->gcBlock = 0; + + /* If this block is currently the best candidate for gc then drop as a candidate */ + if(blockNo == dev->gcDirtiest){ + dev->gcDirtiest = 0; + dev->gcPagesInUse = 0; + } if (!bi->needsRetiring) { yaffs_InvalidateCheckpoint(dev); @@ -3219,7 +3131,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ - dev->isDoingGC = 1; + dev->gcDisable = 1; if (isCheckpointBlock || !yaffs_StillSomeChunkBits(dev, block)) { @@ -3234,7 +3146,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_VerifyBlock(dev, bi, block); - maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 10; + maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5; oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk; for (/* init already done */; @@ -3440,15 +3352,154 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, ("gc did not increase free chunks before %d after %d" TENDSTR), chunksBefore, chunksAfter)); } - dev->gcBlock = -1; + dev->gcBlock = 0; dev->gcChunk = 0; } - dev->isDoingGC = 0; + dev->gcDisable = 0; return retVal; } +/* + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough) + * for garbage collection. + */ + +static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, + int aggressive, + int background) +{ + int i; + int iterations; + unsigned selected = 0; + int prioritised = 0; + int prioritisedExists = 0; + yaffs_BlockInfo *bi; + int threshold; + + /* First let's see if we need to grab a prioritised block */ + if (dev->hasPendingPrioritisedGCs && !aggressive) { + dev->gcDirtiest = 0; + bi = dev->blockInfo; + for (i = dev->internalStartBlock; + i <= dev->internalEndBlock && !selected; + i++) { + + if (bi->gcPrioritise) { + prioritisedExists = 1; + if (bi->blockState == YAFFS_BLOCK_STATE_FULL && + yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { + selected = i; + prioritised = 1; + } + } + bi++; + } + + /* + * If there is a prioritised block and none was selected then + * this happened because there is at least one old dirty block gumming + * up the works. Let's gc the oldest dirty block. + */ + + if(prioritisedExists && + !selected && + dev->oldestDirtyBlock > 0) + selected = dev->oldestDirtyBlock; + + if (!prioritisedExists) /* None found, so we can clear this */ + dev->hasPendingPrioritisedGCs = 0; + } + + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and + * search harder. + * else (we're doing a leasurely gc), then we only bother to do this if the + * block has only a few pages in use. + */ + + if (!selected){ + int pagesUsed; + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; + if (aggressive){ + threshold = dev->param.nChunksPerBlock; + iterations = nBlocks; + } else { + int maxThreshold = dev->param.nChunksPerBlock/2; + threshold = background ? + (dev->gcNotDone + 2) * 2 : 0; + threshold = max(threshold, YAFFS_GC_PASSIVE_THRESHOLD); + threshold = min(threshold, maxThreshold); + + iterations = nBlocks / 16 + 1; + if (iterations > 100) + iterations = 100; + } + + for (i = 0; + i < iterations && + (dev->gcDirtiest < 1 || + dev->gcPagesInUse > YAFFS_GC_GOOD_ENOUGH); + i++) { + dev->gcBlockFinder++; + if (dev->gcBlockFinder < dev->internalStartBlock || + dev->gcBlockFinder > dev->internalEndBlock) + dev->gcBlockFinder = dev->internalStartBlock; + + bi = yaffs_GetBlockInfo(dev, dev->gcBlockFinder); + + pagesUsed = bi->pagesInUse - bi->softDeletions; + + if (bi->blockState == YAFFS_BLOCK_STATE_FULL && + pagesUsed < dev->param.nChunksPerBlock && + (dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) && + yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { + dev->gcDirtiest = dev->gcBlockFinder; + dev->gcPagesInUse = pagesUsed; + } + } + + if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold) + selected = dev->gcDirtiest; + } + + if(!selected && dev->param.isYaffs2 && dev->gcNotDone >= ( background ? 10 : 20)){ + yaffs_FindOldestDirtySequence(dev); + if(dev->oldestDirtyBlock > 0) { + selected = dev->oldestDirtyBlock; + dev->gcDirtiest = selected; + bi = yaffs_GetBlockInfo(dev, selected); + dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions; + } else + dev->gcNotDone = 0; + } + + if(selected){ + T(YAFFS_TRACE_GC, + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), + selected, + dev->param.nChunksPerBlock - dev->gcPagesInUse, + prioritised)); + + dev->gcDirtiest = 0; + dev->gcPagesInUse = 0; + dev->gcNotDone = 0; + if(dev->refreshSkip > 0) + dev->refreshSkip--; + } else{ + dev->gcNotDone++; + T(YAFFS_TRACE_GC, + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR), + dev->gcBlockFinder, dev->gcNotDone, + threshold, + dev->gcDirtiest, dev->gcPagesInUse, + dev->oldestDirtyBlock, + background ? " bg" : "")); + } + + return selected; +} + /* New garbage collector * If we're very low on erased blocks then we do aggressive garbage collection * otherwise we do "leasurely" garbage collection. @@ -3458,26 +3509,28 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, * The idea is to help clear out space in a more spread-out manner. * Dunno if it really does anything useful. */ -static int yaffs_CheckGarbageCollection(yaffs_Device *dev) +static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) { - int block; - int aggressive; + int aggressive = 0; int gcOk = YAFFS_OK; int maxTries = 0; + int minErased; + int erasedChunks; + int checkpointBlockAdjust; if(dev->param.gcControl && (dev->param.gcControl(dev) & 1) == 0) return YAFFS_OK; - if (dev->isDoingGC) { + if (dev->gcDisable) { /* Bail out so we don't get recursive gc */ return YAFFS_OK; } /* This loop should pass the first time. - * We'll only see looping here if the erase of the collected block fails. + * We'll only see looping here if the collection does not increase space. */ do { @@ -3487,11 +3540,26 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev) if (checkpointBlockAdjust < 0) checkpointBlockAdjust = 0; + minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1; + erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; + /* If we need a block soon then do aggressive gc.*/ - if (dev->nErasedBlocks < (dev->param.nReservedBlocks + checkpointBlockAdjust + 2)) + if (dev->nErasedBlocks < minErased) aggressive = 1; - else - aggressive = 0; + else { + if(dev->gcSkip > 20) + dev->gcSkip = 20; + if(erasedChunks < dev->nFreeChunks/2 || + dev->gcSkip < 1 || + background) + aggressive = 0; + else { + dev->gcSkip--; + break; + } + } + + dev->gcSkip = 5; /* If we don't already have a block being gc'd then see if we should start another */ @@ -3500,13 +3568,11 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev) dev->gcChunk = 0; } if (dev->gcBlock < 1) { - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background); dev->gcChunk = 0; } - block = dev->gcBlock; - - if (block > 0) { + if (dev->gcBlock > 0) { dev->garbageCollections++; if (!aggressive) dev->passiveGarbageCollections++; @@ -3516,22 +3582,37 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev) ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), dev->nErasedBlocks, aggressive)); - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive); + gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive); } - if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && block > 0) { + if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) { T(YAFFS_TRACE_GC, (TSTR ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" - TENDSTR), dev->nErasedBlocks, maxTries, block)); + TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock)); } } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) && - (block > 0) && + (dev->gcBlock > 0) && (maxTries < 2)); return aggressive ? gcOk : YAFFS_OK; } +/* + * yaffs_BackgroundGarbageCollect() + * Garbage collects. Intended to be called from a background thread. + * Returns non-zero if at least half the free chunks are erased. + */ +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev) +{ + int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; + + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc" TENDSTR))); + + yaffs_CheckGarbageCollection(dev, 1); + return erasedChunks > dev->nFreeChunks/2; +} + /*------------------------- TAGS --------------------------------*/ static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, @@ -3835,7 +3916,7 @@ void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) bi = yaffs_GetBlockInfo(dev, block); - yaffs_UpdateOldestDirtySequence(dev,bi); + yaffs_UpdateOldestDirtySequence(dev, block, bi); T(YAFFS_TRACE_DELETION, (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); @@ -3894,7 +3975,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, yaffs_Device *dev = in->myDev; - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev,0); /* Get the previous chunk at this location in the file if it exists. * If it does not exist then put a zero into the tree. This creates @@ -3969,7 +4050,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, in == dev->rootDir || /* The rootDir should also be saved */ force) { - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev,0); yaffs_CheckObjectDetailsLoaded(in); buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); @@ -5379,7 +5460,7 @@ int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) yaffs_FlushFilesChunkCache(in); yaffs_InvalidateWholeChunkCache(in); - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev,0); if (in->variantType != YAFFS_OBJECT_TYPE_FILE) return YAFFS_FAIL; @@ -7695,7 +7776,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->chunkOffset = 0; dev->nFreeChunks = 0; - dev->gcBlock = -1; + dev->gcBlock = 0; if (dev->param.startBlock == 0) { dev->internalStartBlock = dev->param.startBlock + 1; @@ -7826,7 +7907,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev) /* More device initialisation */ dev->garbageCollections = 0; dev->passiveGarbageCollections = 0; - dev->currentDirtyChecker = 0; + dev->gcBlockFinder = 0; dev->bufferedBlock = -1; dev->doingBufferedBlockRewrite = 0; dev->nDeletedFiles = 0; @@ -7838,10 +7919,11 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->tagsEccUnfixed = 0; dev->nErasureFailures = 0; dev->nErasedBlocks = 0; - dev->isDoingGC = 0; + dev->gcDisable= 0; dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ YINIT_LIST_HEAD(&dev->dirtyDirectories); dev->oldestDirtySequence = 0; + dev->oldestDirtyBlock = 0; /* Initialise temporary buffers and caches. */ if (!yaffs_InitialiseTempBuffers(dev)) diff --git a/yaffs_guts.h b/yaffs_guts.h index cf19391..8c0b782 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -689,10 +689,6 @@ struct yaffs_DeviceStruct { int nFreeTnodes; yaffs_TnodeList *allocatedTnodeList; - int isDoingGC; - int gcBlock; - int gcChunk; - int nObjectsCreated; yaffs_Object *freeObjects; int nFreeObjects; @@ -706,12 +702,18 @@ struct yaffs_DeviceStruct { int nFreeChunks; - int currentDirtyChecker; /* Used to find current dirtiest block */ - + /* Garbage collection control */ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ - int nonAggressiveSkip; /* GC state/mode */ - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ + unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ + unsigned gcDisable; + unsigned gcBlockFinder; + unsigned gcDirtiest; + unsigned gcPagesInUse; + unsigned gcNotDone; + unsigned gcBlock; + unsigned gcChunk; + unsigned gcSkip; /* Special directories */ yaffs_Object *rootDir; @@ -746,6 +748,7 @@ struct yaffs_DeviceStruct { /* yaffs2 runtime stuff */ unsigned sequenceNumber; /* Sequence number of currently allocating block */ unsigned oldestDirtySequence; + unsigned oldestDirtyBlock; /* Block refreshing */ int refreshSkip; /* A skip down counter. Refresh happens when this gets to zero. */ @@ -892,9 +895,9 @@ void yfsd_WinFileTimeNow(__u32 target[2]); void yaffs_HandleDeferedFree(yaffs_Object *obj); - void yaffs_UpdateDirtyDirectories(yaffs_Device *dev); +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev); /* Debug dump */ int yaffs_DumpObject(yaffs_Object *obj); -- 2.30.2