Add some more tracing
[yaffs2.git] / yaffs_guts.c
index 306b9b4bb08b4c688c5df0ff455c8836fd0bd06c..b90313e5fe408fea035902c9aebcf3a4a60b2041 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.44 2006-11-11 23:27:44 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__);