If kernel/config.h is included in yportenv.h, then yportenv.h must be
[yaffs2.git] / yaffs_guts.c
index c24c3fe28310423e5ab205848c32a047673c6f71..63decdec51526bdbd85abdb22690730d27ee2c38 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
  *
@@ -14,7 +13,7 @@
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.7 2005-07-03 10:32:40 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.11 2005-07-27 02:00:48 charles Exp $";
 
 #include "yportenv.h"
 
@@ -141,6 +140,8 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj);
 
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
 
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
+
 #ifdef YAFFS_PARANOID
 static int yaffs_CheckFileSanity(yaffs_Object *in);
 #else
@@ -152,6 +153,8 @@ static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
 
 static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
 {
+       chunkInNAND -= dev->chunkOffset;
+       
        if(dev->readChunkWithTagsFromNAND)
                return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
        else
@@ -160,6 +163,8 @@ static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __
 
 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags)
 {
+       chunkInNAND -= dev->chunkOffset;
+       
        if(tags)
        {
                tags->sequenceNumber = dev->sequenceNumber;
@@ -185,6 +190,8 @@ static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkIn
 
 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
 {
+       blockNo -= dev->blockOffset;
+       
        if(dev->markNANDBlockBad)
                return dev->markNANDBlockBad(dev,blockNo);
        else
@@ -192,6 +199,8 @@ static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
 }
 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber)
 {
+       blockNo -= dev->blockOffset;
+       
        if(dev->queryNANDBlock)
                return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber);
        else
@@ -201,6 +210,8 @@ static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo,
 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
 {
        int result;
+       
+       blockInNAND -= dev->blockOffset;
 
        dev->nBlockErasures++;
        result = dev->eraseBlockInNAND(dev,blockInNAND);
@@ -279,12 +290,12 @@ static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
 
 static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
 {
-       if(blk < dev->startBlock || blk > dev->endBlock)
+       if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
        {
                T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
                YBUG();
        }
-       return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->startBlock));
+       return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
 }
 
 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
@@ -326,19 +337,6 @@ static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
        return 0;
 }
 
-#if 0
-// Function to manipulate block info
-static  Y_INLINE yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)
-{
-       if(blk < dev->startBlock || blk > dev->endBlock)
-       {
-               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk));
-               YBUG();
-       }
-       return &dev->blockInfo[blk - dev->startBlock];
-}
-#endif
-
 
 static  Y_INLINE int yaffs_HashFunction(int n)
 {
@@ -356,125 +354,6 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
        return dev->lostNFoundDir;
 }
 
-#if 0
-static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
-{
-       if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock)
-       {
-               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND));
-               return YAFFS_FAIL;
-       }
-
-       dev->nPageWrites++;
-       return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
-}
-
-
-
-static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
-                                                       int chunkInNAND, 
-                                                       __u8 *data, 
-                                                       yaffs_Spare *spare, 
-                                                       int doErrorCorrection)
-{
-       int retVal;
-       yaffs_Spare localSpare;
-
-       dev->nPageReads++;
-       
-       
-
-       
-       if(!spare && data)
-       {
-               // If we don't have a real spare, then we use a local one.
-               // Need this for the calculation of the ecc
-               spare = &localSpare;
-       }
-       
-
-       if(!dev->useNANDECC)
-       {
-               retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
-               if(data && doErrorCorrection)
-               {
-                       // Do ECC correction
-                       //Todo handle any errors
-               int eccResult1,eccResult2;
-               __u8 calcEcc[3];
-                
-                       yaffs_ECCCalculate(data,calcEcc);
-                       eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc);
-                       yaffs_ECCCalculate(&data[256],calcEcc);
-                       eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc);
-
-                       if(eccResult1>0)
-                       {
-                               T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
-                               dev->eccFixed++;
-                       }
-                       else if(eccResult1<0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
-                               dev->eccUnfixed++;
-                       }
-
-                       if(eccResult2>0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
-                               dev->eccFixed++;
-                       }
-                       else if(eccResult2<0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
-                               dev->eccUnfixed++;
-                       }
-
-                       if(eccResult1 || eccResult2)
-                       {
-                               // Hoosterman, we had a data problem on this page
-                               yaffs_HandleReadDataError(dev,chunkInNAND);
-                       }
-               }
-       }
-       else
-       {
-        // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device.
-       struct yaffs_NANDSpare nspare;
-               retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
-               memcpy (spare, &nspare, sizeof(yaffs_Spare));
-               if(data && doErrorCorrection)
-               {
-                       if(nspare.eccres1>0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
-                       }
-                       else if(nspare.eccres1<0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
-                       }
-
-                       if(nspare.eccres2>0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
-                       }
-                       else if(nspare.eccres2<0)
-                       {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
-                       }
-
-                       if(nspare.eccres1 || nspare.eccres2)
-                       {
-                               // Hoosterman, we had a data problem on this page
-                               yaffs_HandleReadDataError(dev,chunkInNAND);
-                       }
-
-               }
-       }
-       return retVal;
-}
-
-#endif
 
 
 
@@ -774,13 +653,13 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
     {
        newTnodes[i].internal[0] = &newTnodes[i+1];
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
-       newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
+       newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
 #endif
     }
        
        newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
-       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
+       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
 #endif
        dev->freeTnodes = newTnodes;
        dev->nFreeTnodes+= nTnodes;
@@ -825,7 +704,7 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
        {
                tn = dev->freeTnodes;
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
-       if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
+       if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1)
                {
                        // Hoosterman, this thing looks like it isn't in the list
                                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
@@ -853,7 +732,7 @@ static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
                        // Hoosterman, this thing looks like it is already in the list
                                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
                }
-               tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
+               tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
 #endif
                tn->internal[0] = dev->freeTnodes;
                dev->freeTnodes = tn;
@@ -1212,6 +1091,7 @@ static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
        if(theBlock)
        {
                theBlock->softDeletions++;
+               dev->nFreeChunks++;
        }
 }
 
@@ -1508,7 +1388,7 @@ static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u3
                obj->unlinkAllowed= 0;  // ... or unlink it
                obj->deleted = 0;
                obj->unlinked = 0;
-               obj->st_mode = mode;
+               obj->yst_mode = mode;
                obj->myDev = dev;
                obj->chunkId = 0; // Not a valid chunk.
        }
@@ -1764,7 +1644,7 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
 
 #else
 
-               theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;               
+               theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;            
 #endif
                switch(type)
                {
@@ -1861,7 +1741,7 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                in->valid = 1;
                in->variantType = type;
 
-               in->st_mode  = mode;
+               in->yst_mode  = mode;
                
 #ifdef CONFIG_YAFFS_WINCE
                yfsd_WinFileTimeNow(in->win_atime);
@@ -1869,11 +1749,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
                
 #else
-               in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
+               in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
 
-               in->st_rdev  = rdev;
-               in->st_uid   = uid;
-               in->st_gid   = gid;
+               in->yst_rdev  = rdev;
+               in->yst_uid   = uid;
+               in->yst_gid   = gid;
 #endif         
                in->nDataChunks = 0;
 
@@ -2170,7 +2050,7 @@ static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *
        {
                seq = dev->sequenceNumber;
 
-               for(i = dev->startBlock; i <= dev->endBlock; i++)
+               for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
                {
                        b = yaffs_GetBlockInfo(dev,i);
                        if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
@@ -2225,13 +2105,14 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
        }
 
        pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
        if(aggressive)
        {
-               iterations = dev->endBlock - dev->startBlock + 1;
+               iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
        }
        else
        {
-               iterations = dev->endBlock - dev->startBlock + 1;
+               iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
                iterations = iterations / 16; 
                if(iterations > 200)
                {
@@ -2242,12 +2123,12 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
        for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
        {
                b++;
-               if ( b < dev->startBlock || b > dev->endBlock)
+               if ( b < dev->internalStartBlock || b > dev->internalEndBlock)
                {
-                       b =  dev->startBlock;
+                       b =  dev->internalStartBlock;
                }
 
-               if(b < dev->startBlock || b > dev->endBlock)
+               if(b < dev->internalStartBlock || b > dev->internalEndBlock)
                {
                        T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
                        YBUG();
@@ -2328,6 +2209,8 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
        }
        else
        {
+               dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
+               
                yaffs_RetireBlock(dev,blockNo);
                T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
        }
@@ -2339,7 +2222,7 @@ static void yaffs_DumpBlockStats(yaffs_Device *dev)
        int i,j;
        yaffs_BlockInfo *bi;
        
-       for(i= dev->startBlock; i <=dev->endBlock; i++)
+       for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++)
        {
                bi = yaffs_GetBlockInfo(dev,i);
                T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
@@ -2388,12 +2271,12 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
        
        // Find an empty block.
        
-       for(i = dev->startBlock; i <= dev->endBlock; i++)
+       for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
        {
                dev->allocationBlockFinder++;
-               if(dev->allocationBlockFinder < dev->startBlock || dev->allocationBlockFinder> dev->endBlock) 
+               if(dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock) 
                {
-                       dev->allocationBlockFinder = dev->startBlock;
+                       dev->allocationBlockFinder = dev->internalStartBlock;
                }
                
                bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
@@ -2420,6 +2303,15 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
 }
 
 
+// To determine if we have enough space we just look at the 
+// number of erased blocks.
+
+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
+{
+       int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
+       return (dev->nFreeChunks > reservedChunks);
+}
+
 
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
 {
@@ -2433,7 +2325,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
                dev->allocationPage = 0;
        }
        
-       if(!useReserve &&  dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
+       if(!useReserve &&  !yaffs_CheckSpaceForAllocation(dev))
        {
                // Not enough space to allocate unless we're allowed to use the reserve.
                return -1;
@@ -2476,14 +2368,6 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
 }
 
 
-// To determine if we have enough space we just look at the 
-// number of erased blocks.
-// The cache is allowed to use reserved blocks.
-
-static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
-{
-       return (dev->nErasedBlocks >= dev->nReservedBlocks);
-}
 
 
 static int yaffs_GetErasedChunks(yaffs_Device *dev)
@@ -2524,9 +2408,15 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 
        T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
        //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
+       
+       //yaffs_VerifyFreeChunks(dev);
 
        bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
+       
+       dev->nFreeChunks -= bi->softDeletions;  // Take off the number of soft deleted entries because
+                                               // they're going to get really deleted during GC.
 
+       dev->isDoingGC = 1;
 
        if(!yaffs_StillSomeChunkBits(dev,block))
        {
@@ -2536,7 +2426,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
        else
        {
 
-                       __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+       __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
 
        for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; 
            chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
@@ -2567,7 +2457,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                        if(object && object->deleted && tags.chunkId != 0)
                        {
                                // Data chunk in a deleted file, throw it away
-                               // It's a deleted data chunk,
+                               // It's a soft deleted data chunk,
                                // No need to copy this, just forget about it and fix up the
                                // object.
                                
@@ -2634,6 +2524,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 
        yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
 
+       //yaffs_VerifyFreeChunks(dev);
 
        // Do any required cleanups
        for(i = 0; i < cleanups; i++)
@@ -2656,6 +2547,11 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
        {
                        T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
        }
+       
+       
+       dev->isDoingGC = 0;
+       
+       //yaffs_VerifyFreeChunks(dev);
                        
        return YAFFS_OK;
 }
@@ -2740,14 +2636,20 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
        int gcOk = YAFFS_OK;
        int maxTries = 0;
        
-       //yaffs_DoUnlinkedFileDeletion(dev);
+       //yaffs_VerifyFreeChunks(dev);
+       
+       if(dev->isDoingGC)
+       {
+               // Bail out so we don't get recursive gc
+               return YAFFS_OK;
+       }
 
        // This loop should pass the first time.
        // We'll only see looping here if the erase of the collected block fails.
        
        do{
                maxTries++;
-               if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
+               if(dev->nErasedBlocks < dev->nReservedBlocks)
                {
                        // We need a block soon...
                        aggressive = 1;
@@ -2773,11 +2675,11 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
                        gcOk =  yaffs_GarbageCollectBlock(dev,block);
                }
 
-               if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)
+               if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0
                {
                        T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
                }
-       } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
+       } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
 
        return aggressive ? gcOk: YAFFS_OK;
 }
@@ -3260,9 +3162,10 @@ void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
            bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
            bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
        {
-               dev->nFreeChunks++;
+               dev->nFreeChunks++;
 
                yaffs_ClearChunkBit(dev,block,page);
+               
                bi->pagesInUse--;
                
                if(bi->pagesInUse == 0 &&
@@ -3383,7 +3286,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                // Header data
                oh->type = in->variantType;
                
-               oh->st_mode = in->st_mode;
+               oh->yst_mode = in->yst_mode;
 
 #ifdef CONFIG_YAFFS_WINCE
                oh->win_atime[0] = in->win_atime[0];
@@ -3393,12 +3296,12 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                oh->win_ctime[1] = in->win_ctime[1];
                oh->win_mtime[1] = in->win_mtime[1];
 #else
-               oh->st_uid = in->st_uid;
-               oh->st_gid = in->st_gid;
-               oh->st_atime = in->st_atime;
-               oh->st_mtime = in->st_mtime;
-               oh->st_ctime = in->st_ctime;
-               oh->st_rdev = in->st_rdev;
+               oh->yst_uid = in->yst_uid;
+               oh->yst_gid = in->yst_gid;
+               oh->yst_atime = in->yst_atime;
+               oh->yst_mtime = in->yst_mtime;
+               oh->yst_ctime = in->yst_ctime;
+               oh->yst_rdev = in->yst_rdev;
 #endif 
                if(in->parent)
                {
@@ -3517,7 +3420,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
 {
        yaffs_Device *dev = obj->myDev;
-       int lowest;
+       int lowest = -99; // Stop compiler whining.
        int i;
        yaffs_ChunkCache *cache;
        int chunkWritten = 0;
@@ -3978,7 +3881,7 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                                yaffs_ChunkCache *cache;
                                // If we can't find the data in the cache, then load it up.
                                cache = yaffs_FindChunkCache(in,chunk);
-                               if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
+                               if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
                                {
                                        cache = yaffs_GrabChunkCache(in->myDev);
                                        cache->object = in;
@@ -4117,8 +4020,8 @@ static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
                chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
                if(chunkId > 0)
                {
-                       if(chunkId < (dev->startBlock * dev->nChunksPerBlock) || 
-                      chunkId >= ((dev->endBlock+1) * dev->nChunksPerBlock))
+                       if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) || 
+                      chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock))
                        {
                                T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i));
                        }
@@ -4230,7 +4133,7 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime)
                        yfsd_WinFileTimeNow(in->win_mtime);
 #else
 
-                       in->st_mtime = Y_CURRENT_TIME;
+                       in->yst_mtime = Y_CURRENT_TIME;
 
 #endif
                }
@@ -4573,13 +4476,13 @@ static int yaffs_Scan(yaffs_Device *dev)
        yaffs_ObjectHeader *oh;
        yaffs_Object *in;
        yaffs_Object *parent;
-       int nBlocks = dev->endBlock - dev->startBlock + 1;
+       int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
        
        __u8 *chunkData;
 
        yaffs_BlockIndex *blockIndex = NULL;
 
-       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts  startblk %d endblk %d..." TENDSTR),dev->startBlock,dev->endBlock));
+       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts  intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
        
        chunkData = yaffs_GetTempBuffer(dev,__LINE__);
        
@@ -4593,7 +4496,7 @@ static int yaffs_Scan(yaffs_Device *dev)
        
        
        // Scan all the blocks to determine their state
-       for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
+       for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
        {
                bi = yaffs_GetBlockInfo(dev,blk);
                yaffs_ClearChunkBits(dev,blk);
@@ -4673,8 +4576,8 @@ static int yaffs_Scan(yaffs_Device *dev)
        }
        else
        {
-               startIterator = dev->startBlock;
-               endIterator = dev->endBlock;
+               startIterator = dev->internalStartBlock;
+               endIterator = dev->internalEndBlock;
        }
        
        // For each block....
@@ -4828,7 +4731,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -4837,12 +4740,12 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -4854,7 +4757,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -4863,12 +4766,12 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -5047,7 +4950,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        yaffs_ObjectHeader *oh;
        yaffs_Object *in;
        yaffs_Object *parent;
-       int nBlocks = dev->endBlock - dev->startBlock + 1;
+       int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
        
        __u8 *chunkData;
 
@@ -5060,21 +4963,18 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                return YAFFS_FAIL;
        }
        
-       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts  startblk %d endblk %d..." TENDSTR),dev->startBlock,dev->endBlock));
+       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts  intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
                
        chunkData = yaffs_GetTempBuffer(dev,__LINE__);
        
        
        dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
        
-       if(dev->isYaffs2)
-       {
-               blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
-       }
+       blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
        
        
        // Scan all the blocks to determine their state
-       for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
+       for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
        {
                bi = yaffs_GetBlockInfo(dev,blk);
                yaffs_ClearChunkBits(dev,blk);
@@ -5128,7 +5028,6 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        
        // Sort the blocks
        // Dungy old bubble sort for now...
-       if(dev->isYaffs2)
        {
                yaffs_BlockIndex temp;
                int i;
@@ -5146,12 +5045,9 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        
        
        // Now scan the blocks looking at the data.
-       if(dev->isYaffs2)
-       {
-               startIterator = 0;
-               endIterator = nBlocksToScan-1;
-               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
-       }
+       startIterator = 0;
+       endIterator = nBlocksToScan-1;
+       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
 
        
        // For each block.... backwards
@@ -5364,7 +5260,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -5373,12 +5269,12 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -5390,7 +5286,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -5399,12 +5295,12 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -5836,10 +5732,10 @@ unsigned yaffs_GetObjectType(yaffs_Object *obj)
                case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
                case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
                case YAFFS_OBJECT_TYPE_SPECIAL:         
-                       if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
-                       if(S_ISCHR(obj->st_mode)) return DT_CHR;
-                       if(S_ISBLK(obj->st_mode)) return DT_BLK;
-                       if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
+                       if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
+                       if(S_ISCHR(obj->yst_mode)) return DT_CHR;
+                       if(S_ISBLK(obj->yst_mode)) return DT_BLK;
+                       if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
                default: return DT_REG; break;
        }
 }
@@ -5863,13 +5759,13 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
 {
        unsigned int valid = attr->ia_valid;
        
-       if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
-       if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
-       if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
+       if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
+       if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
+       if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
        
-       if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
-       if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
-       if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+       if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+       if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+       if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
        
        if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
        
@@ -5882,13 +5778,13 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
 {
        unsigned int valid = 0;
        
-       attr->ia_mode = obj->st_mode;   valid |= ATTR_MODE;
-       attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
-       attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
+       attr->ia_mode = obj->yst_mode;  valid |= ATTR_MODE;
+       attr->ia_uid = obj->yst_uid;            valid |= ATTR_UID;
+       attr->ia_gid = obj->yst_gid;            valid |= ATTR_GID;
        
-       Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime;  valid |= ATTR_ATIME;
-       Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME;
-       Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME;
+       Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME;
+       Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;        valid |= ATTR_CTIME;
+       Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;        valid |= ATTR_MTIME;
 
        attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
        
@@ -5991,6 +5887,20 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
                return YAFFS_FAIL;
        }
+       
+       dev->internalStartBlock = dev->startBlock;
+       dev->internalEndBlock =  dev->endBlock;
+       dev->blockOffset = 0;
+       dev->chunkOffset = 0;
+       dev->nFreeChunks = 0;
+       
+       if(dev->startBlock == 0)
+       {
+               dev->internalStartBlock = dev->startBlock + 1;
+               dev->internalEndBlock =  dev->endBlock + 1;
+               dev->blockOffset = 1;
+               dev->chunkOffset = dev->nChunksPerBlock;
+       }
 
        // Check geometry parameters.
 
@@ -5998,9 +5908,9 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
                (!dev->isYaffs2 && dev->nBytesPerChunk !=512)  ||
                dev->nChunksPerBlock < 2 ||
                dev->nReservedBlocks < 2 ||
-               dev->startBlock <= 0 ||
-               dev->endBlock <= 0 ||
-               dev->endBlock <= (dev->startBlock + dev->nReservedBlocks + 2) // otherwise it is too small
+               dev->internalStartBlock <= 0 ||
+               dev->internalEndBlock <= 0 ||
+               dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small
          )
        {
                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
@@ -6045,15 +5955,15 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->isMounted = 1;
 
 
-       nBlocks = dev->endBlock - dev->startBlock + 1;
+       nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
 
 
 
        // OK now calculate a few things for the device
        // Calculate chunkGroupBits.
-       // We need to find the next power of 2 > than endBlock
+       // We need to find the next power of 2 > than internalEndBlock
        
-       x = dev->nChunksPerBlock * (dev->endBlock+1);
+       x = dev->nChunksPerBlock * (dev->internalEndBlock+1);
        
        for(bits = extraBits = 0; x > 1; bits++)
        {
@@ -6106,6 +6016,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->tagsEccUnfixed=0;
        dev->nErasureFailures = 0;
        dev->nErasedBlocks = 0;
+       dev->isDoingGC = 0;
        
        //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
        // Initialise temporary buffers
@@ -6176,12 +6087,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        
        // Zero out stats
        dev->nPageReads = 0;
-    dev->nPageWrites =  0;
+       dev->nPageWrites =  0;
        dev->nBlockErasures = 0;
        dev->nGCCopies = 0;
        dev->nRetriedWrites = 0;
 
        dev->nRetiredBlocks = 0;
+       
+       yaffs_VerifyFreeChunks(dev);
 
        T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
        return YAFFS_OK;
@@ -6252,19 +6165,15 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
 
 #endif
 
-int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+static int  yaffs_CountFreeChunks(yaffs_Device *dev)
 {
        int nFree;
-       int pending;
        int b;
-       int nDirtyCacheChunks=0;
-       
-       yaffs_BlockInfo *blk;
-       
-       struct list_head *i;    
-       yaffs_Object *l;
+
+       yaffs_BlockInfo *blk;   
+
        
-       for(nFree = 0, b = dev->startBlock; b <= dev->endBlock; b++)
+       for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
        {
                blk = yaffs_GetBlockInfo(dev,b);
                
@@ -6272,44 +6181,36 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
                {
                        case YAFFS_BLOCK_STATE_EMPTY:
                        case YAFFS_BLOCK_STATE_ALLOCATING: 
-                       case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
+                       case YAFFS_BLOCK_STATE_COLLECTING:
+                       case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
                        default: break;
                }
+
        }
        
+       return nFree;
+}      
        
-       pending = 0;
-       
-       // To the free chunks add the chunks that are in the deleted unlinked files.
-       list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
-       {
-               if(i)
-               {
-                       l = list_entry(i, yaffs_Object,siblings);
-                       if(l->deleted)
-                       {
-                               pending++;
-                               pending += l->nDataChunks;
-                       }
-               }
-       }
-       
-       
-       
-       //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
-       
-       if(nFree != dev->nFreeChunks) 
-       {
-       //      printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
-       }
 
-       nFree += pending;
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+{
+       // This is what we report to the outside world
+
+       int nFree;
+       int nDirtyCacheChunks;
+               
+#if 1  
+       nFree = dev->nFreeChunks;
+#else
+       nFree = yaffs_CountFreeChunks(dev);
+#endif
        
        // Now count the number of dirty chunks in the cache and subtract those
        
        {
                int i;
-               for(i = 0; i < dev->nShortOpCaches; i++)
+               for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
                {
                        if(dev->srCache[i].dirty) nDirtyCacheChunks++;
                }
@@ -6325,7 +6226,20 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
        
 }
 
+static int  yaffs_freeVerificationFailures;
 
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
+{
+       int counted = yaffs_CountFreeChunks(dev);
+       
+       int difference = dev->nFreeChunks - counted;
+       
+       if(difference)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference)); 
+               yaffs_freeVerificationFailures++;       
+       }
+}
 
 /////////////////// YAFFS test code //////////////////////////////////