Some improvements to garbage collection and st_xxx to yst_xxx changes
[yaffs2.git] / yaffs_guts.c
index e87109b..c776e78 100644 (file)
@@ -1,24 +1,27 @@
+
 /*
- * YAFFS: Yet another FFS. A NAND-flash specific file system.
- * yaffs_guts.c  The main guts of YAFFS
+ * YAFFS: Yet another FFS. A NAND-flash specific file system. 
  *
  * Copyright (C) 2002 Aleph One Ltd.
  *   for Toby Churchill Ltd and Brightstar Engineering
  *
  * Created by Charles Manning <charles@aleph1.co.uk>
  *
+ * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.2 2004-11-16 02:36:15 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.9 2005-07-18 23:16:04 charles Exp $";
 
 #include "yportenv.h"
 
 #include "yaffsinterface.h"
 #include "yaffs_guts.h"
+#include "yaffs_tagsvalidity.h"
+
 
 #include "yaffs_tagscompat.h"
 
@@ -40,6 +43,7 @@ int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
 #include "yaffs_ecc.h"
 #endif
 
+#if 0
 // countBits is a quick way of counting the number of bits in a byte.
 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
 
@@ -70,6 +74,8 @@ static int yaffs_CountBits(__u8 x)
        return retVal;
 }
 
+#endif
+
 
 #if 0
 // Stuff using yea olde tags
@@ -90,7 +96,9 @@ 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);
 // Local prototypes
 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
+#if 0
 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
+#endif
 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
 
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
@@ -107,11 +115,11 @@ static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo);
 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
 
 
-static int  yaffs_ValidateTags(yaffs_ExtendedTags *tags);
-
 // Robustification (if it ever comes about...)
 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
+#if 0
 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
+#endif
 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND,  const yaffs_ExtendedTags *tags);
@@ -133,6 +141,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
@@ -144,6 +154,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
@@ -152,6 +164,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;
@@ -177,6 +191,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
@@ -184,6 +200,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
@@ -193,6 +211,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);
@@ -201,7 +221,7 @@ int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
        return result;
 }
 
-int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
+static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
 {
        return dev->initialiseNAND(dev);
 }
@@ -271,12 +291,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)
@@ -318,19 +338,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)
 {
@@ -348,125 +355,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
 
 
 
@@ -475,7 +363,8 @@ int yaffs_CheckFF(__u8 *buffer,int nBytes)
        //Horrible, slow implementation
        while(nBytes--)
        {
-               if(*buffer != 0xFF) return 0; 
+               if(*buffer != 0xFF) return 0;
+               buffer++;
        }
        return 1;
 }
@@ -487,7 +376,8 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND
        __u8 *data = yaffs_GetTempBuffer(dev,__LINE__);
        yaffs_ExtendedTags tags;
 
-       dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
+// NCB         dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
+       yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
        
        if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
        {
@@ -577,7 +467,7 @@ static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
 }
 
 
-
+#if 0
 static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
 {
        dev->doingBufferedBlockRewrite = 1;
@@ -611,6 +501,8 @@ static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
 {
 }
 
+#endif
+
 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
 {
 }
@@ -1200,6 +1092,7 @@ static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
        if(theBlock)
        {
                theBlock->softDeletions++;
+               dev->nFreeChunks++;
        }
 }
 
@@ -1496,7 +1389,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.
        }
@@ -1709,6 +1602,12 @@ yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
                        in = list_entry(i, yaffs_Object,hashLink);
                        if(in->objectId == number)
                        {
+#ifdef __KERNEL__
+                               // Don't tell the VFS about this one if it is defered free
+                               if(in->deferedFree)
+                                 return NULL;
+#endif
+                                 
                                return in;
                        }
                }
@@ -1746,13 +1645,14 @@ 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)
                {
                        case YAFFS_OBJECT_TYPE_FILE: 
                                theObject->variant.fileVariant.fileSize = 0;
                                theObject->variant.fileVariant.scannedFileSize = 0;
+                               theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; // max __u32
                                theObject->variant.fileVariant.topLevel = 0;
                                theObject->variant.fileVariant.top  = yaffs_GetTnode(dev);
                                break;
@@ -1842,7 +1742,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);
@@ -1850,11 +1750,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;
 
@@ -1908,7 +1808,7 @@ yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32
 
 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
 {
-       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,rdev);
+       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL,parent,name,mode,uid,gid,NULL,NULL,rdev);
 }
 
 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
@@ -1943,6 +1843,12 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
        {
                newDir = obj->parent; // use the old directory
        }
+       
+       if(newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragendy: yaffs_ChangeObjectName: newDir is not a directory"TENDSTR)));
+               YBUG();
+       }
 
        // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
        if(obj->myDev->isYaffs2)
@@ -1972,7 +1878,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
                
                if(unlinkOp) obj->unlinked = 1;
                
-               // If it is a dletion then we mark it as a shrink for gc purposes.
+               // If it is a deletion then we mark it as a shrink for gc purposes.
                if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
                {
                        return YAFFS_OK;
@@ -2008,6 +1914,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object
 }
 
 
+#if 0
 
 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
 {
@@ -2037,7 +1944,7 @@ static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
        return ok;
 }
 
-#if 0
+
 void yaffs_ObjectTest(yaffs_Device *dev)
 {
        yaffs_Object *in[1000];
@@ -2144,7 +2051,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 &&
@@ -2199,13 +2106,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)
                {
@@ -2216,12 +2124,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();
@@ -2302,17 +2210,20 @@ 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));
        }
 }
 
+#if 0
 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,
@@ -2330,6 +2241,7 @@ static void yaffs_DumpBlockStats(yaffs_Device *dev)
 
        }
 }
+#endif
 
 
 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
@@ -2360,12 +2272,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);
@@ -2376,17 +2288,31 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
                        dev->sequenceNumber++;
                        bi->sequenceNumber = dev->sequenceNumber;
                        dev->nErasedBlocks--;           
-                       T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq  %d" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber));   
+                       T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber, dev->nErasedBlocks));      
                        return dev->allocationBlockFinder;
                }
        }
-               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been one" TENDSTR)));
+       
+       
+       T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR),dev->nErasedBlocks));
+       
+       
+       
 
        
        return -1;      
 }
 
 
+// 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)
 {
@@ -2400,7 +2326,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;
@@ -2443,14 +2369,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)
@@ -2491,8 +2409,13 @@ 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.
 
 
        if(!yaffs_StillSomeChunkBits(dev,block))
@@ -2503,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);
@@ -2534,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.
                                
@@ -2601,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++)
@@ -2623,6 +2547,9 @@ 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));
        }
+       
+       
+       //yaffs_VerifyFreeChunks(dev);
                        
        return YAFFS_OK;
 }
@@ -2689,38 +2616,7 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
 
 #endif
 
-#if 0
-#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2
-static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
-{
-       int block;
-       int aggressive=0;
-       
-       //yaffs_DoUnlinkedFileDeletion(dev);
-       
-       if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER))
-       {
-               aggressive = 1;
-       }               
-       
-       if(aggressive)
-       {
-               block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
-               
-               if(block >= 0)
-               {
-                       dev->garbageCollections++;
-                       return yaffs_GarbageCollectBlock(dev,block);
-               }       
-               else
-               {
-                       return YAFFS_FAIL;
-               }
-       }
 
-       return YAFFS_OK;
-}
-#endif
 
 // New garbage collector
 // If we're very low on erased blocks then we do aggressive garbage collection
@@ -2739,13 +2635,15 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
        int maxTries = 0;
        
        //yaffs_DoUnlinkedFileDeletion(dev);
+       
+       //yaffs_VerifyFreeChunks(dev);
 
        // 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;
@@ -2771,11 +2669,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;
 }
@@ -2784,19 +2682,6 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
 //////////////////////////// TAGS ///////////////////////////////////////
 
 
-void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
-{
-       memset(tags,0,sizeof(yaffs_ExtendedTags));
-       tags->validMarker0 = 0xAAAAAAAA;
-       tags->validMarker1 = 0x55555555;
-}
-
-static int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
-{
-       return (tags->validMarker0 == 0xAAAAAAAA &&     tags->validMarker1 == 0x55555555);
-
-}
-
 
 #if 0
 
@@ -2943,6 +2828,7 @@ static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chu
        
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
@@ -3086,12 +2972,27 @@ static int yaffs_CheckFileSanity(yaffs_Object *in)
 
 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
 {
+       // NB inScan is zero unless scanning. For forward scanning, inScan is > 0; for backward scanning inScan is < 0
        yaffs_Tnode *tn;
        yaffs_Device *dev = in->myDev;
        int existingChunk;
        yaffs_ExtendedTags existingTags;
        yaffs_ExtendedTags newTags;
        unsigned existingSerial, newSerial;
+       
+       if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
+       {
+               // Just ignore an attempt at putting a chunk into a non-file during scanning
+               // If it is not during Scanning then something went wrong!
+               if(!inScan)
+               {
+                       T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy:attempt to put data chunk into a non-file" TENDSTR)));
+                       YBUG();
+               }
+               
+               yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
+               return YAFFS_OK;
+       }
                
        tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
        if(!tn)
@@ -3101,12 +3002,16 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
 
        existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
        
-       if(inScan)
+       if(inScan != 0)
        {
                // If we're scanning then we need to test for duplicates
                // NB This does not need to be efficient since it should only ever 
                // happen when the power fails during a write, then only one
                // chunk should ever be affected.
+               //
+               // Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
+               // Update: For backward scanning we don't need to re-read tags so this is quite cheap.
+               
        
                
                if(existingChunk != 0)
@@ -3114,13 +3019,23 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
                        // NB Right now existing chunk will not be real chunkId if the device >= 32MB
                        //    thus we have to do a FindChunkInFile to get the real chunk id.
                        //
-                       // We have a duplicate now we need to decide which one to use
-                       // To do this we get both sets of tags and compare serial numbers.
-                       yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
+                       // We have a duplicate now we need to decide which one to use:
+                       //
+                       // Backwards scanning YAFFS2: The old one is what we use, dump the new one.
+                       // Forward scanning YAFFS2: The new one is what we use, dump the old one.
+                       // YAFFS1: Get both sets of tags and compare serial numbers.
+                       //
+                       //
+                       
+                       if(inScan > 0)
+                       {
+                               // Only do this for forward scanning
+                               yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
                        
                        
-                       // Do a proper find
-                       existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
+                               // Do a proper find
+                               existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
+                       }
 
                        if(existingChunk <=0)
                        {
@@ -3137,16 +3052,19 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
                        newSerial = newTags.serialNumber;
                        existingSerial = existingTags.serialNumber;
                        
-                       if( in->myDev->isYaffs2 ||
-                           existingChunk <= 0 ||
-                           ((existingSerial+1) & 3) == newSerial)
+                       if( (inScan > 0) &&
+                           ( in->myDev->isYaffs2  ||
+                             existingChunk <= 0 ||
+                            ((existingSerial+1) & 3) == newSerial))
                        {
+                               // Forward scanning.                            
                                // Use new
                                // Delete the old one and drop through to update the tnode
                                yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
                        }
                        else
                        {
+                               // Backward scanning or we want to use the existing one
                                // Use existing.
                                // Delete the new one and return early so that the tnode isn't changed
                                yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
@@ -3238,9 +3156,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 &&
@@ -3361,7 +3280,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];
@@ -3371,12 +3290,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)
                {
@@ -3410,7 +3329,8 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                                // Should not happen
                                break;
                        case YAFFS_OBJECT_TYPE_FILE:
-                               oh->fileSize = in->variant.fileVariant.fileSize;
+                               oh->fileSize = (oh->parentObjectId == YAFFS_OBJECTID_DELETED ||
+                                               oh->parentObjectId == YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.fileVariant.fileSize;
                                break;
                        case YAFFS_OBJECT_TYPE_HARDLINK:
                                oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
@@ -3433,8 +3353,16 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                newTags.chunkId = 0;
                newTags.objectId = in->objectId;
                newTags.serialNumber = in->serial;
-       
-
+               
+               // Add extra info for file header
+               
+               newTags.extraHeaderInfoAvailable = 1;
+               newTags.extraParentObjectId = oh->parentObjectId;
+               newTags.extraFileLength = oh->fileSize;
+               newTags.extraIsShrinkHeader = oh->isShrink;
+               newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+               newTags.extraObjectType  = in->variantType;
+               
                // Create new chunk in NAND
                newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
     
@@ -3489,7 +3417,7 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
        int lowest;
        int i;
        yaffs_ChunkCache *cache;
-       int chunkWritten;
+       int chunkWritten = 0;
        //int nBytes;
        int nCaches = obj->myDev->nShortOpCaches;
        
@@ -3620,11 +3548,14 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
                        // its cache, then  find again.
                        // NB what's here is not very accurate, we actually flush the object
                        // the last recently used page.
+                       
+                       // With locking we can't assume we can use entry zero
+                       
                
                        theObj = NULL;
-                       usage = 0;
+                       usage = -1;
                        cache = NULL;
-                       pushout = 0;
+                       pushout = -1;
        
                        for(i = 0; i < dev->nShortOpCaches; i++)
                        {
@@ -3654,7 +3585,6 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
                        }
                        
                }
-
                return cache;
        }
        else
@@ -3886,7 +3816,7 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB
 
 
 
-int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
+int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes, int writeThrough)
 {      
        
        int chunk;
@@ -3913,7 +3843,7 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                // OK now check for the curveball where the start and end are in
                // the same chunk.
                
-               if(     (start + n) < dev->nBytesPerChunk)
+               if((start + n) < dev->nBytesPerChunk)
                {
                        nToCopy = n;
                        
@@ -3941,11 +3871,11 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                {
                        // An incomplete start or end chunk (or maybe both start and end chunk)
                        if(dev->nShortOpCaches > 0)
-                       {
+                          {
                                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;
@@ -3970,6 +3900,16 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
 #endif
                                        cache->locked = 0;
                                        cache->nBytes = nToWriteBack;
+                                       
+                                       if(writeThrough)
+                                       {
+                                               chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
+                                                                                           cache->chunkId,
+                                                                                           cache->data,
+                                                                                           cache->nBytes,1);
+                                               cache->dirty = 0;
+                                       }
+
                                }
                                else
                                {
@@ -4074,10 +4014,10 @@ 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,("Found daft chunkId %d for %d\n",chunkId,i));
+                               T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i));
                        }
                        else
                        {
@@ -4133,9 +4073,11 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                
                yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
                
-               // TODO write a new object header to show we've shrunk the file
-               // Do this only if the file is not in the deleted directory.
-               if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED)
+               // Write a new object header to show we've shrunk the file
+               // Do this only if the file is not in the deleted directories.
+               if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+                  in->parent->objectId != YAFFS_OBJECTID_DELETED
+                 )
                {
                        yaffs_UpdateObjectHeader(in,NULL, 0, 1);
                }
@@ -4185,7 +4127,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
                }
@@ -4219,7 +4161,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
        yaffs_RemoveObjectFromDirectory(in);
        yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
        in->chunkId = -1;
-
+#if 0
 #ifdef __KERNEL__
        if(in->myInode)
        {
@@ -4227,6 +4169,8 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
                in->myInode = 0;
        }
 #endif
+#endif
+
        yaffs_FreeObject(in);
        return YAFFS_OK;
 
@@ -4276,6 +4220,10 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
                        T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
                        in->deleted=1;
                        in->myDev->nDeletedFiles++;
+                       if( 0 && in->myDev->isYaffs2)
+                       {
+                               yaffs_ResizeFile(in,0);
+                       }
                        yaffs_SoftDeleteFile(in);
                }
                else
@@ -4421,6 +4369,9 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
                        case YAFFS_OBJECT_TYPE_SYMLINK:
                                return yaffs_DeleteSymLink(obj);
                                break;
+                       case YAFFS_OBJECT_TYPE_SPECIAL:
+                               return yaffs_DoGenericObjectDeletion(obj);
+                               break;
                        case YAFFS_OBJECT_TYPE_HARDLINK:
                        case YAFFS_OBJECT_TYPE_UNKNOWN:
                        default:
@@ -4519,11 +4470,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  intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
        
        chunkData = yaffs_GetTempBuffer(dev,__LINE__);
        
@@ -4537,7 +4490,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);
@@ -4548,6 +4501,8 @@ static int yaffs_Scan(yaffs_Device *dev)
                
                bi->blockState = state;
                bi->sequenceNumber = sequenceNumber;
+
+               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
                
                if(state == YAFFS_BLOCK_STATE_DEAD)
                {
@@ -4555,6 +4510,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                }
                else if(state == YAFFS_BLOCK_STATE_EMPTY)
                {
+                       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
                        dev->nErasedBlocks++;
                        dev->nFreeChunks += dev->nChunksPerBlock;
                }
@@ -4610,13 +4566,15 @@ static int yaffs_Scan(yaffs_Device *dev)
        {
                startIterator = 0;
                endIterator = nBlocksToScan-1;
+               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
        }
        else
        {
-               startIterator = dev->startBlock;
-               endIterator = dev->endBlock;
+               startIterator = dev->internalStartBlock;
+               endIterator = dev->internalEndBlock;
        }
        
+       // For each block....
        for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
        {
        
@@ -4636,6 +4594,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                
                deleted = 0;
                
+               // For each chunk in each block that needs scanning....
                for(c = 0; c < dev->nChunksPerBlock && 
                                   state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
                {
@@ -4649,6 +4608,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                        
                        if(!dev->isYaffs2 && tags.chunkDeleted)
                        {
+                               // YAFFS1 only...
                                // A deleted chunk
                                deleted++;
                                dev->nFreeChunks ++;
@@ -4689,23 +4649,23 @@ static int yaffs_Scan(yaffs_Device *dev)
                        }
                        else if(tags.chunkId > 0)
                        {
-                               int endpos;
-                               // A data chunk.
+                               // chunkId > 0 so it is a data chunk...
+                               unsigned int endpos;
+
                                yaffs_SetChunkBit(dev,blk,c);
                                bi->pagesInUse++;
                                                                
                                in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
-                               // PutChunkIntoFIle checks for a clash (two data chunks with
+                               // PutChunkIntoFile checks for a clash (two data chunks with
                                // the same chunkId).
                                yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
                                endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
-                               if(in->variant.fileVariant.scannedFileSize <endpos)
+                               if(in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize <endpos)
                                {
                                        in->variant.fileVariant.scannedFileSize = endpos;
                                        if(!dev->useHeaderFileSize)
-                                       {
-                                               in->variant.fileVariant.fileSize =      
-                                                       in->variant.fileVariant.scannedFileSize;
+                                       {       
+                                                       in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
                                        }
 
                                }
@@ -4722,6 +4682,18 @@ static int yaffs_Scan(yaffs_Device *dev)
                                
                                oh = (yaffs_ObjectHeader *)chunkData;
                                
+                               in = yaffs_FindObjectByNumber(dev,tags.objectId);
+                               if(in && in->variantType != oh->type)
+                               {
+                                       // This should not happen, but somehow
+                                       // Wev'e ended up with an objectId that has been reused but not yet 
+                                       // deleted, and worse still it has changed type. Delete the old object.
+                                       
+                                       yaffs_DestroyObject(in);
+                                       
+                                       in = 0;
+                               }
+                               
                                in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
                                
                                if(in->valid)
@@ -4753,7 +4725,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];
@@ -4762,12 +4734,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;
 
@@ -4779,7 +4751,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];
@@ -4788,12 +4760,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;
 
@@ -4848,6 +4820,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                                        }
                                                        
                                                        if(dev->useHeaderFileSize)
+                                               
                                                                in->variant.fileVariant.fileSize = oh->fileSize;
                                                                
                                                        break;
@@ -4938,42 +4911,613 @@ static int yaffs_Scan(yaffs_Device *dev)
                        if(i)
                        {
                                l = list_entry(i, yaffs_Object,siblings);
-                               if(l->deleted)
-                               {
-                                       yaffs_DestroyObject(l);         
-                               }
+                               yaffs_DestroyObject(l);         
                        }
                }       
        }
        
        yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
+
+       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
+
        return YAFFS_OK;
 }
 
 
+static int yaffs_ScanBackwards(yaffs_Device *dev)
+{
+       yaffs_ExtendedTags tags;
+       int blk;
+       int blockIterator;
+       int startIterator;
+       int endIterator;
+       int nBlocksToScan = 0;
+       
+       int chunk;
+       int c;
+       int deleted;
+       yaffs_BlockState state;
+       yaffs_Object *hardList = NULL;
+       yaffs_Object *hl;
+       yaffs_BlockInfo *bi;
+       int sequenceNumber;     
+       yaffs_ObjectHeader *oh;
+       yaffs_Object *in;
+       yaffs_Object *parent;
+       int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+       
+       __u8 *chunkData;
 
-////////////////////////// Directory Functions /////////////////////////
-
+       yaffs_BlockIndex *blockIndex = NULL;
 
-static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
-{
 
-       if(obj->siblings.prev == NULL)
+       if(!dev->isYaffs2)
        {
-               // Not initialised
-               INIT_LIST_HEAD(&obj->siblings);
-               
+               T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
+               return YAFFS_FAIL;
        }
-       else if(!list_empty(&obj->siblings))
+       
+       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)
        {
-               // If it is holed up somewhere else, un hook it
-               list_del_init(&obj->siblings);
+               blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
        }
-       // Now add it
-       list_add(&obj->siblings,&directory->variant.directoryVariant.children);
-       obj->parent = directory;
        
-       if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
+       
+       // Scan all the blocks to determine their state
+       for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
+       {
+               bi = yaffs_GetBlockInfo(dev,blk);
+               yaffs_ClearChunkBits(dev,blk);
+               bi->pagesInUse = 0;
+               bi->softDeletions = 0;
+                               
+               yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
+               
+               bi->blockState = state;
+               bi->sequenceNumber = sequenceNumber;
+
+               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
+               
+               if(state == YAFFS_BLOCK_STATE_DEAD)
+               {
+                       T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
+               }
+               else if(state == YAFFS_BLOCK_STATE_EMPTY)
+               {
+                       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
+                       dev->nErasedBlocks++;
+                       dev->nFreeChunks += dev->nChunksPerBlock;
+               }
+               else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
+               {
+                                       
+                       // Determine the highest sequence number
+                       if( dev->isYaffs2 &&
+                           sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+                           sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
+                        {
+                               
+                               blockIndex[nBlocksToScan].seq = sequenceNumber;
+                               blockIndex[nBlocksToScan].block = blk;
+                               
+                               nBlocksToScan++;
+
+                               if(sequenceNumber >= dev->sequenceNumber)
+                               {
+                                       dev->sequenceNumber = sequenceNumber;
+                               }
+                       }
+                       else if(dev->isYaffs2)
+                       {
+                               // TODO: Nasty sequence number!
+                               T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
+
+                       }
+               }
+       }
+       
+       // Sort the blocks
+       // Dungy old bubble sort for now...
+       if(dev->isYaffs2)
+       {
+               yaffs_BlockIndex temp;
+               int i;
+               int j;
+               
+               for(i = 0; i < nBlocksToScan; i++)
+                       for(j = i+1; j < nBlocksToScan; j++)
+                        if(blockIndex[i].seq > blockIndex[j].seq)
+                        {
+                               temp = blockIndex[j];
+                               blockIndex[j] = blockIndex[i];
+                               blockIndex[i] = temp;
+                        }
+       }
+       
+       
+       // 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));
+       }
+
+       
+       // For each block.... backwards
+       for(blockIterator = endIterator; blockIterator >= startIterator; blockIterator--)
+       {
+       
+               // get the block to scan in the correct order
+               blk = blockIndex[blockIterator].block;
+
+
+               bi = yaffs_GetBlockInfo(dev,blk);
+               state = bi->blockState;
+               
+               deleted = 0;
+               
+               if( 0 && // Disable since this is redundant.
+                   state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
+               {
+                       // Let's look at the first chunk in the block
+                       chunk = blk * dev->nChunksPerBlock;
+                       
+                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
+
+                       // Let's have a good look at this chunk...
+       
+                       if(!tags.chunkUsed)
+                       {
+                               // An unassigned chunk in the block
+                               // This means that either the block is empty or 
+                               // this is the one being allocated from
+                               
+                               // We're looking at the first chunk in the block so the block is unused
+                               state = YAFFS_BLOCK_STATE_EMPTY;
+                               dev->nErasedBlocks++;
+                               dev->nFreeChunks += dev->nChunksPerBlock;
+                       }
+               
+               }
+               
+               // For each chunk in each block that needs scanning....
+               for(c = dev->nChunksPerBlock-1; c >= 0 && 
+                                 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+                                  state == YAFFS_BLOCK_STATE_ALLOCATING); c--)
+               {
+                       // Scan backwards... 
+                       // Read the tags and decide what to do
+                       chunk = blk * dev->nChunksPerBlock + c;
+                       
+                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
+
+                       // Let's have a good look at this chunk...
+       
+                       if(!tags.chunkUsed)
+                       {
+                               // An unassigned chunk in the block
+                               // This means that either the block is empty or 
+                               // this is the one being allocated from
+                               
+                               if(c == 0)
+                               {
+                                       // We're looking at the first chunk in the block so the block is unused
+                                       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));
+                                       }
+                                       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;
+                               
+                               __u32 chunkBase = (tags.chunkId - 1)* dev->nBytesPerChunk;
+
+                               yaffs_SetChunkBit(dev,blk,c);
+                               bi->pagesInUse++;
+                                                               
+                               in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
+                               if(in->variantType == YAFFS_OBJECT_TYPE_FILE &&
+                                  chunkBase < in->variant.fileVariant.shrinkSize)
+                               {
+                                       // This has not been invalidated by a resize
+                                       yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,-1);
+                               
+                               
+                                       // File size is calculated by looking at the data chunks if we have not 
+                                       // seen an object header yet. Stop this practice once we find an object header.
+                                       endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
+                                       if(!in->valid && // have not got an object header yet
+                                          in->variant.fileVariant.scannedFileSize <endpos)
+                                       {
+                                               in->variant.fileVariant.scannedFileSize = endpos;
+                                               in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
+                                       }
+
+                               }
+                               else
+                               {
+                                       // This chunk has been invalidated by a resize, so delete
+                                       yaffs_DeleteChunk(dev,chunk,1,__LINE__);
+                                       
+                                       
+                               }
+                               //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  
+                       }
+                       else
+                       {
+                               // chunkId == 0, so it is an ObjectHeader.
+                               // Thus, we read in the object header and make the object
+                               yaffs_SetChunkBit(dev,blk,c);
+                               bi->pagesInUse++;
+                               
+                               oh = NULL;
+                               in = NULL;
+                               
+                               if(tags.extraHeaderInfoAvailable)
+                               {
+                                       in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,tags.extraObjectType);
+                               }
+
+                               
+                               if(!in || !in->valid)
+                               {
+                               
+                                       // If we don't have  valid info then we need to read the chunk
+                                       // TODO In future we can probably defer reading the chunk and 
+                                       // living with invalid data until needed.
+                                                               
+                                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
+                               
+                                       oh = (yaffs_ObjectHeader *)chunkData;
+                               
+                                       if(!in)
+                                          in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
+                                       
+                               }
+                               
+                               if(!in)
+                               {
+                                       // TODO Hoosterman we have a problem!
+                                       T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: Could not make object for object  %d  at chunk %d during scan" TENDSTR),tags.objectId,chunk));
+
+                               }
+                               
+                               if(in->valid)
+                               {
+                                       // We have already filled this one. We have a duplicate that will be discarded, but 
+                                       // we first have to suck out resize info if it is a file.
+                                       
+                                       if( (in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
+                                           ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+                                           (tags.extraHeaderInfoAvailable && tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
+                                          )
+                                       {
+                                               __u32 thisSize = (oh) ? oh->fileSize : tags.extraFileLength;
+                                               __u32 parentObjectId = (oh) ? oh->parentObjectId : tags.extraParentObjectId;
+                                               unsigned isShrink = (oh)  ? oh->isShrink : tags.extraIsShrinkHeader;
+                                               
+                                               // If it is deleted (unlinked at start also means deleted)
+                                               // we treat the file size as being zeroed at this point.
+                                               if(parentObjectId == YAFFS_OBJECTID_DELETED ||
+                                                  parentObjectId == YAFFS_OBJECTID_UNLINKED)
+                                               {
+                                                       thisSize = 0;
+                                                       isShrink = 1;
+                                               }
+                                                                                               
+                                               if(in->variant.fileVariant.shrinkSize > thisSize)
+                                               {
+                                                       in->variant.fileVariant.shrinkSize = thisSize;
+                                               }
+                                               
+                                               if(isShrink)
+                                               {
+                                                       bi->hasShrinkHeader = 1;
+                                               }
+                                               
+                                       }
+                                       // Use existing - destroy this one.
+                                       yaffs_DeleteChunk(dev,chunk,1,__LINE__);
+               
+                               }
+                               
+                               if(!in->valid &&
+                                  (tags.objectId == YAFFS_OBJECTID_ROOT ||
+                                   tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
+                               {
+                                       // We only load some info, don't fiddle with directory structure
+                                       in->valid = 1;
+                                       in->variantType = oh->type;
+       
+                                       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];
+                                       in->win_mtime[0] = oh->win_mtime[0];
+                                       in->win_atime[1] = oh->win_atime[1];
+                                       in->win_ctime[1] = oh->win_ctime[1];
+                                       in->win_mtime[1] = oh->win_mtime[1];
+#else
+                                       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;
+
+                               }
+                               else if(!in->valid)
+                               {
+                                       // we need to load this info
+                               
+                                       in->valid = 1;
+                                       in->variantType = oh->type;
+       
+                                       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];
+                                       in->win_mtime[0] = oh->win_mtime[0];
+                                       in->win_atime[1] = oh->win_atime[1];
+                                       in->win_ctime[1] = oh->win_ctime[1];
+                                       in->win_mtime[1] = oh->win_mtime[1];
+#else
+                                       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;
+
+                                       yaffs_SetObjectName(in,oh->name);
+                                       in->dirty = 0;
+                                                       
+                                       // directory stuff...
+                                       // hook up to parent
+       
+                                       parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
+                                       if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
+                                       {
+                                               // Set up as a directory
+                                               parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
+                                               INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
+                                       }
+                                       else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+                                       {
+                                               // Hoosterman, another problem....
+                                               // We're trying to use a non-directory as a directory
+
+                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
+                                               parent = dev->lostNFoundDir;
+                                       }
+                               
+                                       yaffs_AddObjectToDirectory(parent,in);
+
+                                       if((parent == dev->deletedDir ||
+                                          parent == dev->unlinkedDir))
+                                       {
+                                               in->deleted = 1; // If it is unlinked at start up then it wants deleting
+                                       }
+                                       
+                                       if( oh->isShrink)
+                                       {
+                                               // Mark the block as having a shrinkHeader
+                                               bi->hasShrinkHeader = 1;
+                                       }
+                                       
+                               
+                                       // Note re hardlinks.
+                                       // Since we might scan a hardlink before its equivalent object is scanned
+                                       // we put them all in a list.
+                                       // After scanning is complete, we should have all the objects, so we run through this
+                                       // list and fix up all the chains.              
+       
+                                       switch(in->variantType)
+                                       {
+                                               case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
+                                                       break;
+                                               case YAFFS_OBJECT_TYPE_FILE:
+
+                                                       
+                                                       if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
+                                                       {
+                                                               in->variant.fileVariant.fileSize = oh->fileSize;
+                                                               in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
+                                                       }
+                                                       
+                                                                                                       
+                                                       
+                                                       if(in->variant.fileVariant.shrinkSize > oh->fileSize)
+                                                       {
+                                                               in->variant.fileVariant.shrinkSize = oh->fileSize;
+                                                       }
+                                                                                                       
+                                                               
+                                                       break;
+                                               case YAFFS_OBJECT_TYPE_HARDLINK:
+                                                       in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
+                                                       in->hardLinks.next = (struct list_head *)hardList;
+                                                       hardList = in;
+                                                       break;
+                                               case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
+                                                       break;
+                                               case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
+                                                       break;
+                                               case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
+                                                       in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
+                                                       break;
+                                       }
+
+#if 0
+                                       if(parent == dev->deletedDir)
+                                       {
+                                               yaffs_DestroyObject(in);
+                                               bi->hasShrinkHeader = 1;
+                                       }
+#endif
+                                       //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
+                               }
+                       }
+               }
+               
+               if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
+               {
+                       // If we got this far while scanning, then the block is fully allocated.
+                       state = YAFFS_BLOCK_STATE_FULL; 
+               }
+               
+               bi->blockState = state;
+               
+               // Now let's see if it was dirty
+               if(     bi->pagesInUse == 0 &&
+                       !bi->hasShrinkHeader &&
+               bi->blockState == YAFFS_BLOCK_STATE_FULL)
+           {
+               yaffs_BlockBecameDirty(dev,blk);
+           }
+
+       }
+       
+       if(blockIndex)
+       {
+               YFREE(blockIndex);
+       }
+       
+       // Ok, we've done all the scanning.
+       
+       // Fix up the hard link chains.
+       // We should now have scanned all the objects, now it's time to add these 
+       // hardlinks.
+       while(hardList)
+       {
+               hl = hardList;
+               hardList = (yaffs_Object *)(hardList->hardLinks.next);
+               
+               in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
+               
+               if(in)
+               {
+                       // Add the hardlink pointers
+                       hl->variant.hardLinkVariant.equivalentObject=in;
+                       list_add(&hl->hardLinks,&in->hardLinks);
+               }
+               else
+               {
+                       //Todo Need to report/handle this better.
+                       // Got a problem... hardlink to a non-existant object
+                       hl->variant.hardLinkVariant.equivalentObject=NULL;
+                       INIT_LIST_HEAD(&hl->hardLinks);
+                       
+               }
+               
+       }
+       
+       {
+               struct list_head *i;    
+               struct list_head *n;
+                       
+               yaffs_Object *l;
+               
+               // Soft delete all the unlinked files
+               list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
+               {
+                       if(i)
+                       {
+                               l = list_entry(i, yaffs_Object,siblings);
+                               yaffs_DestroyObject(l);         
+                       }
+               }       
+               
+               // Soft delete all the deletedDir files
+               list_for_each_safe(i,n,&dev->deletedDir->variant.directoryVariant.children)
+               {
+                       if(i)
+                       {
+                               l = list_entry(i, yaffs_Object,siblings);
+                               yaffs_DestroyObject(l);         
+                               
+                       }
+               }       
+       }
+       
+       yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
+
+       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards ends" TENDSTR)));
+
+       return YAFFS_OK;
+}
+
+
+
+////////////////////////// Directory Functions /////////////////////////
+
+
+static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
+{
+
+       if(!directory)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a null pointer directory" TENDSTR)));
+               YBUG();
+       }
+       if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a non-directory" TENDSTR)));
+               YBUG();
+       }
+
+               if(obj->siblings.prev == NULL)
+       {
+               // Not initialised
+               INIT_LIST_HEAD(&obj->siblings);
+               
+       }
+       else if(!list_empty(&obj->siblings))
+       {
+               // If it is holed up somewhere else, un hook it
+               list_del_init(&obj->siblings);
+       }
+       // Now add it
+       list_add(&obj->siblings,&directory->variant.directoryVariant.children);
+       obj->parent = directory;
+       
+       if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
        {
                obj->unlinked = 1;
                obj->myDev->nUnlinkedFiles++;
@@ -4996,6 +5540,18 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
        
        yaffs_Object *l;
        
+
+       if(!directory)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
+               YBUG();
+       }
+       if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
+               YBUG();
+       }
+
        sum = yaffs_CalcNameSum(name);
        
        list_for_each(i,&directory->variant.directoryVariant.children)
@@ -5035,6 +5591,17 @@ int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *
        struct list_head *i;    
        yaffs_Object *l;
        
+
+       if(!theDir)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
+               YBUG();
+       }
+       if(theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
+               YBUG();
+       }
        
        list_for_each(i,&theDir->variant.directoryVariant.children)
        {
@@ -5166,10 +5733,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;
        }
 }
@@ -5193,13 +5760,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);
        
@@ -5212,13 +5779,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;
        
@@ -5313,13 +5880,28 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        int extraBits;
        int nBlocks;
 
+       T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
        // Check stuff that must be set
 
        if(!dev)
        {
-               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device\n" TENDSTR)));
+               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.
 
@@ -5327,15 +5909,21 @@ 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\n" TENDSTR)));
+               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
+                  dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
                return YAFFS_FAIL;
        }
 
+       if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
+               return YAFFS_FAIL;
+       }
 
        // Got the right mix of functions?
        //
@@ -5368,15 +5956,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++)
        {
@@ -5428,6 +6016,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->tagsEccFixed=0;
        dev->tagsEccUnfixed=0;
        dev->nErasureFailures = 0;
+       dev->nErasedBlocks = 0;
        
        //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
        // Initialise temporary buffers
@@ -5442,7 +6031,6 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        
 
        
-       
        yaffs_InitialiseBlocks(dev,nBlocks);
        
        yaffs_InitialiseTnodes(dev);
@@ -5479,7 +6067,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
        
        dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
-       dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+       dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_DELETED, S_IFDIR);
 
        dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
        dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
@@ -5491,18 +6079,24 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        }
                
        // Now scan the flash.  
-       yaffs_Scan(dev);
+       
+       if(dev->isYaffs2)
+               yaffs_ScanBackwards(dev);
+       else
+               yaffs_Scan(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;
                
 }
@@ -5571,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);
                
@@ -5591,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++;
                }
@@ -5644,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 //////////////////////////////////
 
@@ -5686,4 +6281,3 @@ void yaffs_GutsTest(yaffs_Device *dev)
 #endif
 
 
-