- 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;
- if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
- threshold = YAFFS_GC_PASSIVE_THRESHOLD;
- if(threshold > maxThreshold)
- 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) &&
- yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
- dev->gcDirtiest = dev->gcBlockFinder;
- dev->gcPagesInUse = pagesUsed;
- }
- }
-
- if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold)
- selected = dev->gcDirtiest;
- }
-
- /*
- * If nothing has been selected for a while, try selecting the oldest dirty
- * because that's gumming up the works.
- */
-
- if(!selected && dev->param.isYaffs2 &&
- dev->gcNotDone >= ( background ? 10 : 20)){
- yaffs2_FindOldestDirtySequence(dev);
- if(dev->oldestDirtyBlock > 0) {
- selected = dev->oldestDirtyBlock;
- dev->gcDirtiest = selected;
- dev->oldestDirtyGCs++;
- 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));
-
- if(background)
- dev->backgroundGCs++;
- 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.
- * Aggressive gc looks further (whole array) and will accept less dirty blocks.
- * Passive gc only inspects smaller areas and will only accept more dirty blocks.
- *
- * 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, int background)
-{
- 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->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 collection does not increase space.
- */
-
- do {
- maxTries++;
-
- checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev);
-
- 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 < minErased)
- aggressive = 1;
- 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 */
-
- if (dev->gcBlock < 1 && !aggressive) {
- dev->gcBlock = yaffs2_FindRefreshBlock(dev);
- dev->gcChunk = 0;
- }
- if (dev->gcBlock < 1) {
- dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
- dev->gcChunk = 0;
- }
-
- if (dev->gcBlock > 0) {
- dev->allGCs++;
- if (!aggressive)
- dev->passiveGCs++;
-
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
- dev->nErasedBlocks, aggressive));
-
- gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive);
- }
-
- 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, dev->gcBlock));
- }
- } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) &&
- (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, unsigned urgency)
-{
- int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
-
- T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
-
- yaffs_CheckGarbageCollection(dev, 1);
- return erasedChunks > dev->nFreeChunks/2;
-}
-
-/*------------------------- TAGS --------------------------------*/
-
-static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
- int chunkInObject)
-{
- return (tags->chunkId == chunkInObject &&
- tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
-
-}
-
-
-/*-------------------- Data file manipulation -----------------*/
-
-static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
- yaffs_ExtendedTags *tags)
-{
- /*Get the Tnode, then get the level 0 offset chunk offset */
- yaffs_Tnode *tn;
- int theChunk = -1;
- yaffs_ExtendedTags localTags;
- int retVal = -1;
-
- yaffs_Device *dev = in->myDev;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &localTags;
- }