normalise licence headers
[yaffs2.git] / yaffs_guts.c
index 306b9b4bb08b4c688c5df0ff455c8836fd0bd06c..f88851eea5c89e971120c6267b6a7e012f1bebe9 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 const char *yaffs_guts_c_version =
-    "$Id: yaffs_guts.c,v 1.39 2006-10-03 10:13:03 charles Exp $";
+    "$Id: yaffs_guts.c,v 1.45 2006-11-14 03:07:17 charles Exp $";
 
 #include "yportenv.h"
 
@@ -484,13 +484,15 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
  
 static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND)
 {
+       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
 
        yaffs_InvalidateCheckpoint(dev);
        
        yaffs_MarkBlockBad(dev, blockInNAND);
 
-       yaffs_GetBlockInfo(dev, blockInNAND)->blockState =
-           YAFFS_BLOCK_STATE_DEAD;
+       bi->blockState = YAFFS_BLOCK_STATE_DEAD;
+       bi->gcPrioritise = 0;
+       bi->needsRetiring = 0;
 
        dev->nRetiredBlocks++;
 }
@@ -511,19 +513,53 @@ static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
 {
 }
 
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
+{
+       if(!bi->gcPrioritise){
+               bi->gcPrioritise = 1;
+               dev->hasPendingPrioritisedGCs = 1;
+               bi->chunkErrorStrikes ++;
+               
+               if(bi->chunkErrorStrikes > 3){
+                       bi->needsRetiring = 1; /* Too many stikes, so retire this */
+                       T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
+
+               }
+               
+       }
+}
+
+static void yaffs_ReportOddballBlocks(yaffs_Device *dev)
+{
+       int i;
+               
+       for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){
+               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
+               if(bi->needsRetiring || bi->gcPrioritise)
+                       T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR),
+                               i,
+                               bi->needsRetiring ? " needs retiring" : "",
+                               bi->gcPrioritise ?  " gc prioritised" : ""));
+               
+       }
+}
+
 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk)
 {
 
        int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
        yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
+
+       yaffs_HandleChunkError(dev,bi);
                
-       bi->gcPrioritise = 1;
-       dev->hasPendingPrioritisedGCs = 1;
        
-       if(erasedOk) {
+       if(erasedOk ) {
                /* Was an actual write failure, so mark the block for retirement  */
-
                bi->needsRetiring = 1;
+               T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+                 (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
+
+               
        }
        
        /* Delete the chunk */
@@ -1921,7 +1957,7 @@ static int yaffs_InitialiseBlocks(yaffs_Device * dev)
                dev->blockInfoAlt = 0;
        
        /* Set up dynamic blockinfo stuff. */
-       dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; // round up bytes
+       dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
        dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
        if(!dev->chunkBits){
                dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
@@ -1994,8 +2030,6 @@ static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev,
         */
        return (bi->sequenceNumber <= dev->oldestDirtySequence);
 
-       return 1;
-
 }
 
 /* FindDiretiestBlock is used to select the dirtiest block (or close enough)
@@ -2015,22 +2049,26 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
        int prioritised=0;
        yaffs_BlockInfo *bi;
        static int nonAggressiveSkip = 0;
+       int pendingPrioritisedExist = 0;
        
        /* First let's see if we need to grab a prioritised block */
        if(dev->hasPendingPrioritisedGCs){
                for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){
 
                        bi = yaffs_GetBlockInfo(dev, i);
-                       if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
-                          bi->gcPrioritise &&
-                          yaffs_BlockNotDisqualifiedFromGC(dev, bi)){
-                               pagesInUse = (bi->pagesInUse - bi->softDeletions);
-                               dirtiest = b;
-                               prioritised = 1;
-                               aggressive = 1; /* Fool the non-aggressive skip logiv below */
+                       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 */
+                               }
                        }
                }
-               if(dirtiest < 0) /* None found, so we can clear this */
+               
+               if(!pendingPrioritisedExist) /* None found, so we can clear this */
                        dev->hasPendingPrioritisedGCs = 0;
        }
 
@@ -2118,6 +2156,11 @@ static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo)
        /* If the block is still healthy erase it and mark as clean.
         * If the block has had a data failure, then retire it.
         */
+        
+       T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+               (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
+               blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
+               
        bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
 
        if (!bi->needsRetiring) {
@@ -3408,7 +3451,7 @@ static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head)
        yaffs_CheckpointValidity cp;
        cp.structType = sizeof(cp);
        cp.magic = YAFFS_MAGIC;
-       cp.version = 1;
+       cp.version = YAFFS_CHECKPOINT_VERSION;
        cp.head = (head) ? 1 : 0;
        
        return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))?
@@ -3425,7 +3468,7 @@ static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
        if(ok)
                ok = (cp.structType == sizeof(cp)) &&
                     (cp.magic == YAFFS_MAGIC) &&
-                    (cp.version == 1) &&
+                    (cp.version == YAFFS_CHECKPOINT_VERSION) &&
                     (cp.head == ((head) ? 1 : 0));
        return ok ? 1 : 0;
 }
@@ -3692,7 +3735,11 @@ static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
                                if (!obj->deferedFree) {
                                        yaffs_ObjectToCheckpointObject(&cp,obj);
                                        cp.structType = sizeof(cp);
-                                       /* printf("Write out object %d type %d\n",obj->objectId,obj->variantType); */
+
+                                       T(YAFFS_TRACE_CHECKPOINT,(
+                                               TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
+                                               cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj));
+                                               
                                        ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
                                        
                                        if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){
@@ -3731,9 +3778,9 @@ static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
                if(ok && cp.objectId == ~0)
                        done = 1;
                else if(ok){
-                       T(YAFFS_TRACE_CHECKPOINT,(TSTR("Read object %d parent %d type %d" TENDSTR),
-                               cp.objectId,cp.parentId,cp.variantType));
                        obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
+                       T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
+                               cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj));
                        if(obj) {
                                yaffs_CheckpointObjectToObject(obj,&cp);
                                if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
@@ -3825,6 +3872,7 @@ static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
 
 int yaffs_CheckpointSave(yaffs_Device *dev)
 {
+       yaffs_ReportOddballBlocks(dev);
        T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
 
        if(!dev->isCheckpointed)
@@ -3844,6 +3892,8 @@ int yaffs_CheckpointRestore(yaffs_Device *dev)
 
        T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
        
+       yaffs_ReportOddballBlocks(dev);
+       
        return retval;
 }
 
@@ -5121,6 +5171,12 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
        yaffs_ExtendedTags tags;
        int result;
        
+#if 0
+       T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR),
+               in->objectId,
+               in->lazyLoaded ? "not yet" : "already"));
+#endif
+               
        if(in->lazyLoaded){
                in->lazyLoaded = 0;
                chunkData = yaffs_GetTempBuffer(dev, __LINE__);
@@ -5364,39 +5420,41 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
                                        state = YAFFS_BLOCK_STATE_EMPTY;
                                        dev->nErasedBlocks++;
                                } else {
-                                       /* this is the block being allocated from */
-                                       if (state ==
-                                           YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
-                                               T(YAFFS_TRACE_SCAN,
-                                                 (TSTR
-                                                  (" Allocating from %d %d"
-                                                   TENDSTR), blk, c));
+                                       if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+                                           state == YAFFS_BLOCK_STATE_ALLOCATING) {
+                                               if(dev->sequenceNumber == bi->sequenceNumber) {
+                                                       /* this is the block being allocated from */
+                                               
+                                                       T(YAFFS_TRACE_SCAN,
+                                                         (TSTR
+                                                          (" Allocating from %d %d"
+                                                           TENDSTR), blk, c));
+
+                                                       state = YAFFS_BLOCK_STATE_ALLOCATING;
+                                                       dev->allocationBlock = blk;
+                                                       dev->allocationPage = c;
+                                                       dev->allocationBlockFinder = blk;       
+                                               }
+                                               else {
+                                                       /* This is a partially written block that is not
+                                                        * the current allocation block. This block must have
+                                                        * had a write failure, so set up for retirement.
+                                                        */
+                                                 
+                                                        bi->needsRetiring = 1;
+                                                        bi->gcPrioritise = 1;
+                                                                                                        
+                                                        T(YAFFS_TRACE_ALWAYS,
+                                                        (TSTR("Partially written block %d being set for retirement" TENDSTR),
+                                                        blk));
+                                               }
+
                                        }
-                                       state = YAFFS_BLOCK_STATE_ALLOCATING;
-                                       dev->allocationBlock = blk;
-                                       dev->allocationPage = c;
-                                       dev->allocationBlockFinder = blk;       
-                                       /* Set it to here to encourage the allocator to 
-                                        *  go forth from here.
-                                        */
                                         
-                                       /* Yaffs2 sanity check:
-                                        * This should be the one with the highest sequence number
-                                        */
-                                       if (dev->isYaffs2
-                                           && (dev->sequenceNumber !=
-                                               bi->sequenceNumber)) {
-                                               T(YAFFS_TRACE_ALWAYS,
-                                                 (TSTR
-                                                  ("yaffs: Allocation block %d was not highest sequence "
-                                                   "id: block seq = %d, dev seq = %d"
-                                                   TENDSTR), blk,
-                                                  bi->sequenceNumber,
-                                                  dev->sequenceNumber));
-                                       }
                                }
 
                                dev->nFreeChunks++;
+                               
                        } else if (tags.chunkId > 0) {
                                /* chunkId > 0 so it is a data chunk... */
                                unsigned int endpos;