- 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;
- dev->nCleanups=0;
- }
- if (dev->gcBlock < 1) {
- dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
- dev->gcChunk = 0;
- dev->nCleanups=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;
- }
-
- tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
-
- if (tn) {
- theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
-
- retVal =
- yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
- chunkInInode);
- }
- return retVal;
-}
-
-static int yaffs_FindAndDeleteChunkInFile(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;
-
- yaffs_Device *dev = in->myDev;
- int retVal = -1;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &localTags;
- }
-
- tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
-
- if (tn) {
-
- theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
-
- retVal =
- yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
- chunkInInode);
-
- /* Delete the entry in the filestructure (if found) */
- if (retVal != -1)
- yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
- }
-
- return retVal;
-}
-
-
-int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
- int chunkInNAND, int inScan)
-{
- /* NB inScan is zero unless scanning.
- * For forward scanning, inScan is > 0;
- * for backward scanning inScan is < 0
- *
- * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
- */
-
- yaffs_Tnode *tn;
- yaffs_Device *dev = in->myDev;
- int existingChunk;
- yaffs_ExtendedTags existingTags;
- yaffs_ExtendedTags newTags;
- unsigned existingSerial, newSerial;
-
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
- /* Just ignore an attempt at putting a chunk into a non-file during scanning
- * If it is not during Scanning then something went wrong!
- */
- if (!inScan) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy:attempt to put data chunk into a non-file"
- TENDSTR)));
- YBUG();
- }
-
- yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
- return YAFFS_OK;
- }
-
- tn = yaffs_AddOrFindLevel0Tnode(dev,
- &in->variant.fileVariant,
- chunkInInode,
- NULL);
- if (!tn)
- return YAFFS_FAIL;
-
- if(!chunkInNAND)
- /* Dummy insert, bail now */
- return YAFFS_OK;
-
- existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
-
- if (inScan != 0) {
- /* If we're scanning then we need to test for duplicates
- * NB This does not need to be efficient since it should only ever
- * happen when the power fails during a write, then only one
- * chunk should ever be affected.
- *
- * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
- * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
- */
-
- if (existingChunk > 0) {
- /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1
- * thus we have to do a FindChunkInFile to get the real chunk id.
- *
- * We have a duplicate now we need to decide which one to use:
- *
- * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
- * Forward scanning YAFFS2: The new one is what we use, dump the old one.
- * YAFFS1: Get both sets of tags and compare serial numbers.
- */
-
- if (inScan > 0) {
- /* Only do this for forward scanning */
- yaffs_ReadChunkWithTagsFromNAND(dev,
- chunkInNAND,
- NULL, &newTags);