Merge branch 'master' of ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2
[yaffs2.git] / yaffs_guts.c
index 99d6e97ab7b4990b94c6661a486289ba48a87acf..feade2aff1044b208adf2647a924f374d79b52b4 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 const char *yaffs_guts_c_version =
-    "$Id: yaffs_guts.c,v 1.118 2010-03-12 01:22:48 charles Exp $";
+    "$Id: yaffs_guts.c,v 1.120 2010-03-15 23:10:34 charles Exp $";
 
 #include "yportenv.h"
 #include "yaffs_trace.h"
@@ -1062,19 +1062,20 @@ static int yaffs_CalcOldestDirtySequence(yaffs_Device *dev)
 {
        int i;
        __u32 seq;
-       yaffs_BlockInfo *b = 0;
+       yaffs_BlockInfo *b;
 
        if(!dev->param.isYaffs2)
                return 0;
 
        /* Find the oldest dirty sequence number. */
        seq = dev->sequenceNumber;
+       b = dev->blockInfo;
        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;
+               b++;
        }
        return seq;
 }
@@ -2800,12 +2801,9 @@ static __u32 yaffs_FindRefreshBlock(yaffs_Device *dev)
         */
        dev->refreshSkip = dev->param.refreshPeriod;
        dev->refreshCount++;
-
+       bi = dev->blockInfo;
        for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
 
-               bi = yaffs_GetBlockInfo(dev, b);
-               
-
                if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
 
                        if(oldest < 1 ||
@@ -2814,6 +2812,7 @@ static __u32 yaffs_FindRefreshBlock(yaffs_Device *dev)
                                 oldestSequence = bi->sequenceNumber;
                         }
                }
+               bi++;
        }
 
        if (oldest > 0) {
@@ -2845,11 +2844,9 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
 
        /* 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++) {
 
-                       bi = yaffs_GetBlockInfo(dev, i);
-                       /* yaffs_VerifyBlock(dev,bi,i); */
-
                        if (bi->gcPrioritise) {
                                pendingPrioritisedExist = 1;
                                if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
@@ -2860,6 +2857,7 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
                                        aggressive = 1; /* Fool the non-aggressive skip logiv below */
                                }
                        }
+                       bi++;
                }
 
                if (!pendingPrioritisedExist) /* None found, so we can clear this */
@@ -2945,6 +2943,10 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
 
        bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
 
+       /* If this is the block being garbage collected then stop gc'ing this block */
+       if(blockNo == dev->gcBlock)
+               dev->gcBlock = -1;
+
        if (!bi->needsRetiring) {
                yaffs_InvalidateCheckpoint(dev);
                erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
@@ -3217,12 +3219,6 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
        
        bi->hasShrinkHeader = 0;        /* clear the flag so that the block can erase */
 
-       /* Take off the number of soft deleted entries because
-        * they're going to get really deleted during GC.
-        */
-       if(dev->gcChunk == 0) /* first time through for this block */
-               dev->nFreeChunks -= bi->softDeletions;
-
        dev->isDoingGC = 1;
 
        if (isCheckpointBlock ||
@@ -3302,6 +3298,13 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                                         * No need to copy this, just forget about it and
                                         * fix up the object.
                                         */
+                                        
+                                       /* Free chunks already includes softdeleted chunks.
+                                        * How ever this chunk is going to soon be really deleted
+                                        * which will increment free chunks.
+                                        * We have to decrement free chunks so this works out properly.
+                                        */
+                                       dev->nFreeChunks--;
 
                                        object->nDataChunks--;
 
@@ -3422,8 +3425,14 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
 
 
 
-       /* If the gc completed then clear the current gcBlock so that we find another. */
-       if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
+       if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
+               /*
+                * The gc did not complete. Set block state back to FULL
+                * because checkpointing does not restore gc.
+                */
+               bi->blockState = YAFFS_BLOCK_STATE_FULL;
+       } else {
+               /* The gc completed. */
                chunksAfter = yaffs_GetErasedChunks(dev);
                if (chunksBefore >= chunksAfter) {
                        T(YAFFS_TRACE_GC,
@@ -3458,6 +3467,10 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
 
        int checkpointBlockAdjust;
 
+       if(dev->param.gcControl &&
+               (dev->param.gcControl(dev) & 1) == 0)
+               return YAFFS_OK;
+
        if (dev->isDoingGC) {
                /* Bail out so we don't get recursive gc */
                return YAFFS_OK;
@@ -5476,6 +5489,7 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
 
        int retVal;
        int immediateDeletion = 0;
+       yaffs_Device *dev = in->myDev;
 
        if (!in->myInode)
                immediateDeletion = 1;
@@ -5489,7 +5503,7 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
                   in->objectId));
                in->deleted = 1;
                in->myDev->nDeletedFiles++;
-               if (1 || in->myDev->param.isYaffs2)
+               if (dev->param.disableSoftDelete || dev->param.isYaffs2)
                        yaffs_ResizeFile(in, 0);
                yaffs_SoftDeleteFile(in);
        } else {
@@ -5506,8 +5520,10 @@ int yaffs_DeleteFile(yaffs_Object *in)
 {
        int retVal = YAFFS_OK;
        int deleted = in->deleted;
+       yaffs_Device *dev = in->myDev;
 
-       yaffs_ResizeFile(in, 0);
+       if (dev->param.disableSoftDelete || dev->param.isYaffs2)
+               yaffs_ResizeFile(in, 0);
 
        if (in->nDataChunks > 0) {
                /* Use soft deletion if there is data in the file.
@@ -5970,8 +5986,8 @@ static int yaffs_Scan(yaffs_Device *dev)
        dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
 
        /* Scan all the blocks to determine their state */
+       bi = dev->blockInfo;
        for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
-               bi = yaffs_GetBlockInfo(dev, blk);
                yaffs_ClearChunkBits(dev, blk);
                bi->pagesInUse = 0;
                bi->softDeletions = 0;
@@ -5997,6 +6013,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                        dev->nErasedBlocks++;
                        dev->nFreeChunks += dev->param.nChunksPerBlock;
                }
+               bi++;
        }
 
        startIterator = dev->internalStartBlock;
@@ -6494,8 +6511,8 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        chunkData = yaffs_GetTempBuffer(dev, __LINE__);
 
        /* Scan all the blocks to determine their state */
+       bi = dev->blockInfo;
        for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
-               bi = yaffs_GetBlockInfo(dev, blk);
                yaffs_ClearChunkBits(dev, blk);
                bi->pagesInUse = 0;
                bi->softDeletions = 0;
@@ -6548,6 +6565,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
 
                        }
                }
+               bi++;
        }
 
        T(YAFFS_TRACE_SCAN,
@@ -7994,15 +8012,13 @@ void yaffs_Deinitialise(yaffs_Device *dev)
 
 static int yaffs_CountFreeChunks(yaffs_Device *dev)
 {
-       int nFree;
+       int nFree=0;
        int b;
 
        yaffs_BlockInfo *blk;
 
-       for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
-                       b++) {
-               blk = yaffs_GetBlockInfo(dev, b);
-
+       blk = dev->blockInfo;
+       for (b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) {
                switch (blk->blockState) {
                case YAFFS_BLOCK_STATE_EMPTY:
                case YAFFS_BLOCK_STATE_ALLOCATING:
@@ -8015,6 +8031,7 @@ static int yaffs_CountFreeChunks(yaffs_Device *dev)
                default:
                        break;
                }
+               blk++;
        }
 
        return nFree;