*** empty log message ***
[yaffs/.git] / yaffs_guts.c
index caf9289d0e6f99671d965211e1b87700965be058..fa1c9d59d1645a4c7953827ea7105750da19a155 100644 (file)
@@ -29,7 +29,7 @@ int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
 // countBits is a quick way of counting the number of bits in a byte.\r
 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.\r
 \r
-static const char yaffs_countBits[256] =\r
+static const char yaffs_countBitsTable[256] =\r
 {\r
 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,\r
 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,\r
@@ -49,6 +49,13 @@ static const char yaffs_countBits[256] =
 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8\r
 };\r
 \r
+static int yaffs_CountBits(__u8 x)\r
+{\r
+       int retVal;\r
+       retVal = yaffs_countBitsTable[x];\r
+       return retVal;\r
+}\r
+\r
 \r
 \r
 // Device info\r
@@ -66,11 +73,27 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
 \r
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);\r
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);\r
-static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name);\r
+static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force);\r
 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);\r
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);\r
 static int yaffs_CheckStructures(void);\r
 \r
+// Robustification\r
+static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);\r
+static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);\r
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);\r
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);\r
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare);\r
+\r
+static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);\r
+\r
+static int yaffs_UnlinkWorker(yaffs_Object *obj);\r
+\r
+\r
+static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1);\r
+\r
+\r
+\r
 loff_t yaffs_GetFileSize(yaffs_Object *obj);\r
 \r
 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);\r
@@ -108,7 +131,8 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND
        return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);\r
 }\r
 \r
-int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)\r
+\r
+int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare,int doErrorCorrection)\r
 {\r
        int retVal;\r
        __u8 calcEcc[3];\r
@@ -125,7 +149,7 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8
        }\r
        \r
        retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);\r
-       if(data)\r
+       if(data && doErrorCorrection)\r
        {\r
                // Do ECC correction\r
                //Todo handle any errors\r
@@ -151,22 +175,25 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8
                 {\r
                        T((TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));\r
                 }\r
+                \r
+                if(eccResult1 || eccResult2)\r
+                {\r
+                       // Hoosterman, we had a data problem on this page\r
+                       yaffs_HandleReadDataError(dev,chunkInNAND);\r
+                }\r
        }\r
        return retVal;\r
 }\r
 \r
-#ifdef YAFFS_PARANOID\r
 \r
 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)\r
 {\r
+\r
        static int init = 0;\r
        static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];\r
        static __u8 data[YAFFS_BYTES_PER_CHUNK];\r
        static __u8 spare[16];\r
        \r
-       int retVal;\r
-       \r
-       retVal  = YAFFS_OK;\r
        \r
        dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);\r
        \r
@@ -178,14 +205,14 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND
                init = 1;\r
        }\r
        \r
-       if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) retVal = YAFFS_FAIL;\r
-       if(memcmp(cmpbuf,spare,16)) retVal = YAFFS_FAIL;\r
+       if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return  YAFFS_FAIL;\r
+       if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL;\r
+\r
        \r
-       return retVal;\r
+       return YAFFS_OK;\r
        \r
 }\r
 \r
-#endif\r
 \r
 \r
 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)\r
@@ -203,7 +230,7 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
 {\r
        int chunk;\r
        \r
-       int writeOk = 0;\r
+       int writeOk = 1;\r
        int attempts = 0;\r
        \r
        unsigned char rbData[YAFFS_BYTES_PER_CHUNK];\r
@@ -214,7 +241,19 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
        \r
                if(chunk >= 0)\r
                {\r
-                       writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);\r
+\r
+                       // First check this chunk is erased...\r
+#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK\r
+                       writeOk = yaffs_CheckChunkErased(dev,chunk);\r
+#endif         \r
+                       if(!writeOk)\r
+                       {\r
+                               T((TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));\r
+                       }\r
+                       else\r
+                       {\r
+                               writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);\r
+                       }\r
                        attempts++;\r
                        if(writeOk)\r
                        {\r
@@ -222,33 +261,33 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
                                // If verify fails, then delete this chunk and try again\r
                                // To verify we compare everything except the block and \r
                                // page status bytes.\r
-                               yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);\r
+                               // NB We check a raw read without ECC correction applied\r
+                               yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0);\r
                                \r
-                               if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||\r
-                                       spare->tagByte0 != rbSpare.tagByte0 ||\r
-                                       spare->tagByte1 != rbSpare.tagByte1 ||\r
-                                       spare->tagByte2 != rbSpare.tagByte2 ||\r
-                                       spare->tagByte3 != rbSpare.tagByte3 ||\r
-                                       spare->tagByte4 != rbSpare.tagByte4 ||\r
-                                       spare->tagByte5 != rbSpare.tagByte5 ||\r
-                                       spare->tagByte6 != rbSpare.tagByte6 ||\r
-                                       spare->tagByte7 != rbSpare.tagByte7 ||\r
-                                       spare->ecc1[0]  != rbSpare.ecc1[0]  ||\r
-                                       spare->ecc1[1]  != rbSpare.ecc1[1]  ||\r
-                                       spare->ecc1[2]  != rbSpare.ecc1[2]  ||\r
-                                       spare->ecc2[0]  != rbSpare.ecc2[0]  ||\r
-                                       spare->ecc2[1]  != rbSpare.ecc2[1]  ||\r
-                                       spare->ecc2[2]  != rbSpare.ecc2[2] )\r
-                               {\r
+#ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY\r
+                               if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare))\r
+                                                       {\r
                                        // Didn't verify\r
-                                       yaffs_DeleteChunk(dev,chunk);\r
-                                       T((TSTR("**>> yaffs write failed on chunk %d" TENDSTR), chunk));\r
+                                       T((TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk));\r
 \r
                                        writeOk = 0;\r
-                               }                                       \r
+                               }       \r
+#endif                         \r
                                \r
                        }\r
+                       if(writeOk)\r
+                       {\r
+                               // Copy the data into the write buffer.\r
+                               // NB We do this at the end to prevent duplicates in the case of a write error.\r
+                               //Todo\r
+                               yaffs_HandleWriteChunkOk(dev,chunk,data,spare);\r
+                       }\r
+                       else\r
+                       {\r
+                               yaffs_HandleWriteChunkError(dev,chunk);\r
+                       }\r
                }\r
+               \r
        } while(chunk >= 0 && ! writeOk);\r
        \r
        if(attempts > 1)\r
@@ -260,7 +299,107 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
        return chunk;\r
 }\r
 \r
+///\r
+// Functions for robustisizing\r
+//\r
+//\r
+\r
+static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)\r
+{\r
+       // Ding the blockStatus in the first two pages of the block.\r
+       \r
+       yaffs_Spare spare;\r
 \r
+       memset(&spare, 0xff,sizeof(yaffs_Spare));\r
+\r
+       spare.blockStatus = 0;\r
+       \r
+       yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK, NULL , &spare);\r
+       yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK + 1, NULL , &spare);\r
+       \r
+       dev->blockInfo[blockInNAND].blockState = YAFFS_BLOCK_STATE_DEAD;\r
+       dev->nRetiredBlocks++;\r
+}\r
+\r
+\r
+\r
+static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)\r
+{\r
+       dev->doingBufferedBlockRewrite = 1;\r
+       //\r
+       //      Remove erased chunks\r
+       //  Rewrite existing chunks to a new block\r
+       //      Set current write block to the new block\r
+       \r
+       dev->doingBufferedBlockRewrite = 0;\r
+       \r
+       return 1;\r
+}\r
+\r
+\r
+static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)\r
+{\r
+       int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;\r
+\r
+       // Mark the block for retirement\r
+       dev->blockInfo[blockInNAND].needsRetiring = 1;\r
+\r
+       //TODO  \r
+       // Just do a garbage collection on the affected block then retire the block\r
+       // NB recursion\r
+}\r
+\r
+\r
+static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)\r
+{\r
+}\r
+\r
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)\r
+{\r
+}\r
+\r
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare)\r
+{\r
+}\r
+\r
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)\r
+{\r
+       int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;\r
+\r
+       // Mark the block for retirement\r
+       dev->blockInfo[blockInNAND].needsRetiring = 1;\r
+       // Delete the chunk\r
+       yaffs_DeleteChunk(dev,chunkInNAND);\r
+}\r
+\r
+\r
+\r
+\r
+static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1)\r
+{\r
+\r
+\r
+       if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 ||\r
+               s0->tagByte0 != s1->tagByte0 ||\r
+               s0->tagByte1 != s1->tagByte1 ||\r
+               s0->tagByte2 != s1->tagByte2 ||\r
+               s0->tagByte3 != s1->tagByte3 ||\r
+               s0->tagByte4 != s1->tagByte4 ||\r
+               s0->tagByte5 != s1->tagByte5 ||\r
+               s0->tagByte6 != s1->tagByte6 ||\r
+               s0->tagByte7 != s1->tagByte7 ||\r
+               s0->ecc1[0]  != s1->ecc1[0]  ||\r
+               s0->ecc1[1]  != s1->ecc1[1]  ||\r
+               s0->ecc1[2]  != s1->ecc1[2]  ||\r
+               s0->ecc2[0]  != s1->ecc2[0]  ||\r
+               s0->ecc2[1]  != s1->ecc2[1]  ||\r
+               s0->ecc2[2]  != s1->ecc2[2] )\r
+               {\r
+                       return 0;\r
+               }\r
+       \r
+       return 1;\r
+}\r
 \r
 \r
 ///////////////////////// Object management //////////////////\r
@@ -1291,7 +1430,12 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                                break;\r
                }\r
 \r
-               yaffs_UpdateObjectHeader(in,name);\r
+               if(yaffs_UpdateObjectHeader(in,name,0) < 0)\r
+               {\r
+                       // Could not create the object header, fail the creation\r
+                       yaffs_UnlinkWorker(in);\r
+                       in = NULL;\r
+               }\r
 \r
        }\r
        \r
@@ -1354,7 +1498,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
                obj->dirty = 1;\r
                yaffs_AddObjectToDirectory(newDir,obj);\r
                \r
-               if(yaffs_UpdateObjectHeader(obj,newName) >= 0)\r
+               if(yaffs_UpdateObjectHeader(obj,newName,0) >= 0)\r
                {\r
                        return YAFFS_OK;\r
                }\r
@@ -1468,6 +1612,7 @@ void yaffs_ObjectTest(yaffs_Device *dev)
 \r
 static void yaffs_InitialiseBlocks(yaffs_Device *dev)\r
 {\r
+       //Todo we're assuming the malloc will pass.\r
        dev->blockInfo = YMALLOC(dev->nBlocks * sizeof(yaffs_BlockInfo));\r
        memset(dev->blockInfo,0,dev->nBlocks * sizeof(yaffs_BlockInfo));\r
        dev->allocationBlock = -1; // force it to get a new one\r
@@ -1512,21 +1657,52 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
 }\r
 \r
 \r
-static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)\r
+static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)\r
+{\r
+       yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];\r
+       \r
+       int erasedOk = 0;\r
+       \r
+       // If the block is still healthy erase it and mark as clean.\r
+       // If the block has had a data failure, then retire it.\r
+       bi->blockState = YAFFS_BLOCK_STATE_DIRTY;\r
+\r
+       if(!bi->needsRetiring)\r
+       {\r
+               erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);\r
+               if(!erasedOk)\r
+               {\r
+                       T((TSTR("**>> Erasure failed %d" TENDSTR),blockNo));\r
+               }\r
+       }\r
+       \r
+       if( erasedOk )\r
+       {\r
+               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;\r
+               dev->nErasedBlocks++;\r
+               bi->pagesInUse = 0;\r
+               bi->pageBits = 0;\r
+       \r
+               T((TSTR("Erased block %d" TENDSTR),blockNo));\r
+       }\r
+       else\r
+       {\r
+               yaffs_RetireBlock(dev,blockNo);\r
+               T((TSTR("**>> Block %d retired" TENDSTR),blockNo));\r
+       }\r
+}\r
+\r
+\r
+static int yaffs_FindBlockForAllocation(yaffs_Device *dev)\r
 {\r
        int i;\r
        \r
-       if(useReserve && dev->nErasedBlocks < 1)\r
+       if(dev->nErasedBlocks < 1)\r
        {\r
                // Hoosterman we've got a problem.\r
                // Can't get space to gc\r
                return -1;\r
        }\r
-       else if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)\r
-       {\r
-               // We are not in GC, so we hold some in reserve so we can get\r
-               // a gc done.\r
-       }\r
        \r
        // Find an empty block.\r
        \r
@@ -1550,21 +1726,6 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)
 }\r
 \r
 \r
-static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)\r
-{\r
-       yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];\r
-       \r
-       // Mark as dirty, erase it and mark as clean.\r
-       bi->blockState = YAFFS_BLOCK_STATE_DIRTY;\r
-       yaffs_EraseBlockInNAND(dev,blockNo);\r
-       bi->blockState = YAFFS_BLOCK_STATE_EMPTY;\r
-       dev->nErasedBlocks++;\r
-       bi->pagesInUse = 0;\r
-       bi->pageBits = 0;\r
-       \r
-       T((TSTR("Erased block %d" TENDSTR),blockNo));\r
-}\r
-\r
 \r
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)\r
 {\r
@@ -1573,10 +1734,16 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
        if(dev->allocationBlock < 0)\r
        {\r
                // Get next block to allocate off\r
-               dev->allocationBlock = yaffs_FindBlockForAllocation(dev,useReserve);\r
+               dev->allocationBlock = yaffs_FindBlockForAllocation(dev);\r
                dev->allocationPage = 0;\r
        }\r
        \r
+       if(!useReserve &&  dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)\r
+       {\r
+               // Not enough space to allocate unless we're allowed to use the reserve.\r
+               return -1;\r
+       }\r
+       \r
        // Next page please....\r
        if(dev->allocationBlock >= 0)\r
        {\r
@@ -1597,12 +1764,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
                        dev->allocationBlock = -1;\r
                }\r
 \r
-#ifdef YAFFS_PARANOID\r
-               if(yaffs_CheckChunkErased(dev,retVal) == YAFFS_FAIL)\r
-               {\r
-                       T((TSTR("..................Trying to allocate non-erased page %d" TENDSTR),retVal));\r
-               }\r
-#endif         \r
+\r
                return retVal;\r
                \r
        }\r
@@ -1642,7 +1804,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                        \r
                        //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));\r
                        \r
-                       yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare);\r
+                       yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1);\r
                        \r
                        yaffs_GetTagsFromSpare(&spare,&tags);\r
                        tags.serialNumber++;\r
@@ -1696,7 +1858,15 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
        if(dev->garbageCollectionRequired)\r
        {\r
                dev->garbageCollectionRequired = 0;\r
-               block = yaffs_FindDirtiestBlock(dev);\r
+               if(dev->blockSelectedForGC >= 0)\r
+               {\r
+                       block = dev->blockSelectedForGC;\r
+               }\r
+               else\r
+               {\r
+                       block = yaffs_FindDirtiestBlock(dev);\r
+               }\r
+               \r
                if(block >= 0)\r
                {\r
                        return yaffs_GarbageCollectBlock(dev,block);\r
@@ -1755,9 +1925,9 @@ static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_
        if(tags)\r
        {\r
                yaffs_Spare spare;\r
-               if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare) == YAFFS_OK)\r
+               if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK)\r
                {\r
-                       *chunkDeleted = (yaffs_countBits[spare.pageStatus] < 7) ? 1 : 0;\r
+                       *chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;\r
                        yaffs_GetTagsFromSpare(&spare,tags);\r
                        return YAFFS_OK;\r
                }\r
@@ -2089,7 +2259,7 @@ int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffe
     \r
     if(chunkInNAND >= 0)\r
     {\r
-               return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL);\r
+               return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL,1);\r
        }\r
        else\r
        {\r
@@ -2101,16 +2271,21 @@ int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffe
 \r
 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)\r
 {\r
-       int block = chunkId / YAFFS_CHUNKS_PER_BLOCK;\r
-       int page = chunkId % YAFFS_CHUNKS_PER_BLOCK;\r
+       int block;\r
+       int page;\r
        yaffs_Spare spare;\r
+       \r
+       if(chunkId <= 0) return;        \r
                \r
+       block = chunkId / YAFFS_CHUNKS_PER_BLOCK;\r
+       page = chunkId % YAFFS_CHUNKS_PER_BLOCK;\r
        yaffs_SpareInitialise(&spare);\r
        \r
        spare.pageStatus = 0; // To mark it as deleted.\r
 \r
        \r
        yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);\r
+       yaffs_HandleUpdateChunk(dev,chunkId,&spare);\r
                        \r
        \r
        // Pull out of the management area.\r
@@ -2224,7 +2399,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
 // UpdateObjectHeader updates the header on NAND for an object.\r
 // If name is not NULL, then that new name is used.\r
 //\r
-int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)\r
+int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)\r
 {\r
 \r
        yaffs_Device *dev = in->myDev;\r
@@ -2239,7 +2414,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
     yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew;\r
     yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;\r
     \r
-    if(!in->fake)\r
+    if(!in->fake || force)\r
     {\r
   \r
                yaffs_CheckGarbageCollection(dev);              \r
@@ -2250,7 +2425,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
     \r
                if(prevChunkId >= 0)\r
                {\r
-                       yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL);        \r
+                       yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL,1);      \r
                }\r
 \r
                // Header data\r
@@ -2264,17 +2439,29 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
                oh->st_ctime = in->st_ctime;\r
                oh->st_rdev = in->st_rdev;\r
        \r
-               oh->parentObjectId = in->parent->objectId;\r
+               if(in->parent)\r
+               {\r
+                       oh->parentObjectId = in->parent->objectId;\r
+               }\r
+               else\r
+               {\r
+                       oh->parentObjectId = 0;\r
+               }\r
+               \r
                oh->sum = in->sum;\r
                if(name && *name)\r
                {\r
                        memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);\r
                        strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);\r
                }\r
-               else\r
+               else if(prevChunkId)\r
                {       \r
                        memcpy(oh->name, ohOld->name,YAFFS_MAX_NAME_LENGTH + 1);\r
                }\r
+               else\r
+               {\r
+                       memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);   \r
+               }\r
        \r
                switch(in->variantType)\r
                {\r
@@ -2597,7 +2784,7 @@ int yaffs_FlushFile(yaffs_Object *in)
        \r
                in->st_mtime = CURRENT_TIME;\r
 \r
-               retVal = yaffs_UpdateObjectHeader(in,NULL);\r
+               retVal = yaffs_UpdateObjectHeader(in,NULL,0);\r
        }\r
        else\r
        {\r
@@ -2747,7 +2934,7 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
                yaffs_HashObject(hl);\r
                \r
                // Update the hardlink which has become an object\r
-               yaffs_UpdateObjectHeader(hl,NULL);\r
+               yaffs_UpdateObjectHeader(hl,NULL,0);\r
 \r
                // Finally throw away the deleted object\r
                yaffs_DeleteChunk(obj->myDev,obj->chunkId);\r
@@ -2842,16 +3029,31 @@ static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
 {\r
        yaffs_Spare spare;\r
        \r
-       yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare);\r
+       yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare,1);\r
+#if 1\r
+       if(yaffs_CountBits(spare.blockStatus) < 7)\r
+       {\r
+               return 1;\r
+       }\r
+#else\r
        if(spare.blockStatus != 0xFF)\r
        {\r
                return 1;\r
        }\r
-       yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare);\r
+#endif\r
+       yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare,1);\r
+\r
+#if 1\r
+       if(yaffs_CountBits(spare.blockStatus) < 7)\r
+       {\r
+               return 1;\r
+       }\r
+#else\r
        if(spare.blockStatus != 0xFF)\r
        {\r
                return 1;\r
        }\r
+#endif\r
        \r
        return 0;\r
        \r
@@ -2902,13 +3104,13 @@ static int yaffs_Scan(yaffs_Device *dev)
                        // Read the spare area and decide what to do\r
                        chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;\r
                        \r
-                       yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare);\r
+                       yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare,1);\r
 \r
                        \r
                        // This block looks ok, now what's in this chunk?\r
                        yaffs_GetTagsFromSpare(&spare,&tags);\r
                        \r
-                       if(yaffs_countBits[spare.pageStatus] < 6)\r
+                       if(yaffs_CountBits(spare.pageStatus) < 6)\r
                        {\r
                                // A deleted chunk\r
                                deleted++;\r
@@ -2953,6 +3155,11 @@ static int yaffs_Scan(yaffs_Device *dev)
                                if(in->variant.fileVariant.scannedFileSize <endpos)\r
                                {\r
                                        in->variant.fileVariant.scannedFileSize = endpos;\r
+#ifndef CONFIG_YAFFS_USE_HEADER_FILE_SIZE\r
+                                               in->variant.fileVariant.fileSize =      \r
+                                                       in->variant.fileVariant.scannedFileSize;\r
+#endif\r
+\r
                                }\r
                                //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  \r
                        }\r
@@ -2963,7 +3170,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                dev->blockInfo[blk].pageBits |= (1 << c);\r
                                dev->blockInfo[blk].pagesInUse++;\r
                                                        \r
-                               yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL);\r
+                               yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL,1);\r
                                \r
                                oh = (yaffs_ObjectHeader *)chunkData;\r
                                \r
@@ -2989,7 +3196,25 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        }\r
                                }\r
                                \r
-                               if(!in->valid)\r
+                               if(!in->valid &&\r
+                                  (tags.objectId == YAFFS_OBJECTID_ROOT ||\r
+                                   tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))\r
+                               {\r
+                                       // We only load some info, don't fiddle with directory structure\r
+                                       in->valid = 1;\r
+                                       in->variantType = oh->type;\r
+       \r
+                                       in->st_mode  = oh->st_mode;\r
+                                       in->st_uid   = oh->st_uid;\r
+                                       in->st_gid   = oh->st_gid;\r
+                                       in->st_atime = oh->st_atime;\r
+                                       in->st_mtime = oh->st_mtime;\r
+                                       in->st_ctime = oh->st_ctime;\r
+                                       in->st_rdev = oh->st_rdev;\r
+                                       in->chunkId  = chunk;\r
+\r
+                               }\r
+                               else if(!in->valid)\r
                                {\r
                                        // we need to load this info\r
                                \r
@@ -3038,7 +3263,9 @@ static int yaffs_Scan(yaffs_Device *dev)
                                                case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem\r
                                                        break;\r
                                                case YAFFS_OBJECT_TYPE_FILE:\r
+#ifdef CONFIG_YAFFS_USE_HEADER_FILE_SIZE\r
                                                        in->variant.fileVariant.fileSize = oh->fileSize;\r
+#endif\r
                                                        break;\r
                                                case YAFFS_OBJECT_TYPE_HARDLINK:\r
                                                        in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;\r
@@ -3235,7 +3462,7 @@ int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize)
        \r
                if(obj->chunkId >= 0)\r
                {\r
-                       yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);\r
+                       yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL,1);\r
                }\r
                strncpy(name,oh->name,buffSize - 1);\r
        }\r
@@ -3332,7 +3559,7 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
        \r
        if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);\r
        \r
-       yaffs_UpdateObjectHeader(obj,NULL);\r
+       yaffs_UpdateObjectHeader(obj,NULL,1);\r
        \r
        return YAFFS_OK;\r
        \r
@@ -3411,7 +3638,6 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        int bits;\r
 \r
 \r
-       dev = dev;\r
        \r
        if(!yaffs_CheckStructures())\r
        {\r
@@ -3447,12 +3673,15 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        else\r
        {\r
                dev->chunkGroupBits = bits - 16;\r
-               dev->chunkGroupSize = nChunks/0x10000;\r
+               dev->chunkGroupSize = nChunks>> 16;\r
        }\r
        \r
        // More device initialisation\r
        dev->garbageCollectionRequired  = 0;\r
        dev->currentDirtyChecker = 0;\r
+       dev->bufferedBlock = -1;\r
+       dev->doingBufferedBlockRewrite = 0;\r
+       dev->blockSelectedForGC = -1;\r
        \r
        yaffs_InitialiseBlocks(dev);\r
        \r
@@ -3476,6 +3705,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->nBlockErasures = 0;\r
        dev->nGCCopies = 0;\r
        dev->nRetriedWrites = 0;\r
+       dev->nRetiredBlocks = 0;\r
 \r
        \r
        return YAFFS_OK;\r