Fix blocks per chunk in resize
[yaffs/.git] / yaffs_guts.c
index 365fa69636622e601a951a111d0b313808721863..fcb217ae850f3b4d98fc85abccac0c7a43684b26 100644 (file)
@@ -14,7 +14,7 @@
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.29 2003-08-29 17:53:05 aleph1 Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.44 2005-11-07 07:03:02 charles Exp $";
 
 #include "yportenv.h"
 
@@ -120,12 +120,12 @@ static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
 
 static __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 __inline__ void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
@@ -170,12 +170,12 @@ static __inline__ int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
 // Function to manipulate block info
 static  __inline__ yaffs_BlockInfo* yaffs_GetBlockInfo(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: getBlockInfo block %d is not valid" TENDSTR),blk));
                YBUG();
        }
-       return &dev->blockInfo[blk - dev->startBlock];
+       return &dev->blockInfo[blk - dev->internalStartBlock];
 }
 
 
@@ -198,14 +198,14 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
 
 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
 {
-       if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock)
+       if(chunkInNAND < dev->internalStartBlock * 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);
+       return dev->writeChunkToNAND(dev,chunkInNAND - dev->chunkOffset,data,spare);
 }
 
 
@@ -234,7 +234,7 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
 
        if(!dev->useNANDECC)
        {
-               retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+               retVal  = dev->readChunkFromNAND(dev,chunkInNAND - dev->chunkOffset,data,spare);
                if(data && doErrorCorrection)
                {
                        // Do ECC correction
@@ -249,23 +249,23 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
 
                        if(eccResult1>0)
                        {
-                               T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND - dev->chunkOffset));
                                dev->eccFixed++;
                        }
                        else if(eccResult1<0)
                        {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND - dev->chunkOffset));
                                dev->eccUnfixed++;
                        }
 
                        if(eccResult2>0)
                        {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND - dev->chunkOffset));
                                dev->eccFixed++;
                        }
                        else if(eccResult2<0)
                        {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND - dev->chunkOffset));
                                dev->eccUnfixed++;
                        }
 
@@ -280,26 +280,26 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
        {
         // 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);
+               retVal  = dev->readChunkFromNAND(dev,chunkInNAND - dev->chunkOffset,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));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND - dev->chunkOffset));
                        }
                        else if(nspare.eccres1<0)
                        {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND - dev->chunkOffset));
                        }
 
                        if(nspare.eccres2>0)
                        {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND - dev->chunkOffset));
                        }
                        else if(nspare.eccres2<0)
                        {
-                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND - dev->chunkOffset));
                        }
 
                        if(nspare.eccres1 || nspare.eccres2)
@@ -323,7 +323,7 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND
     // Might as well always allocate the larger size for dev->useNANDECC == true;
        static __u8 spare[sizeof(struct yaffs_NANDSpare)];      
 
-       dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
+       dev->readChunkFromNAND(dev,chunkInNAND - dev->chunkOffset,data,(yaffs_Spare *)spare);
        
        if(!init)
        {
@@ -344,7 +344,7 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND
 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
 {
        dev->nBlockErasures++;
-       return dev->eraseBlockInNAND(dev,blockInNAND);
+       return dev->eraseBlockInNAND(dev,blockInNAND - dev->blockOffset);
 }
 
 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
@@ -1085,7 +1085,7 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in
                                                if(limit)
                                                { 
                                                        *limit = *limit-1;
-                                                       if(limit <= 0) 
+                                                       if(*limit <= 0) 
                                                        { 
                                                                hitLimit = 1;
                                                        }
@@ -1156,6 +1156,8 @@ static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level
                        {
                            if(tn->level0[i])
                        {
+                                       // Note this does not find the real chunk, only the chunk group.
+                                       // We make an assumption that a chunk group is niot larger than a block.
                                        theChunk =  (tn->level0[i] << in->myDev->chunkGroupBits);
                                        T(YAFFS_TRACE_SCAN,(TSTR("soft delete tch %d cgb %d chunk %d" TENDSTR),
                                                tn->level0[i],in->myDev->chunkGroupBits,theChunk));
@@ -1409,7 +1411,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.
        }
@@ -1442,6 +1444,16 @@ static void yaffs_FreeObject(yaffs_Object *tn)
 
        yaffs_Device *dev = tn->myDev;
        
+#ifdef  __KERNEL__
+       if(tn->myInode)
+       {
+               // We're still hooked up to a cached inode.
+               // Don't delete now, but mark for later deletion
+               tn->deferedFree = 1;
+               return;
+       }
+#endif
+       
        yaffs_UnhashObject(tn);
        
        // Link into the free list.
@@ -1451,6 +1463,18 @@ static void yaffs_FreeObject(yaffs_Object *tn)
 }
 
 
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object *obj)
+{
+       if(obj->deferedFree)
+       {
+          yaffs_FreeObject(obj);
+       }
+}
+
+#endif
+
 
 
 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
@@ -1599,6 +1623,11 @@ 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 if it has been marked for freeing
+                               if(in->deferedFree) 
+                                   return NULL;
+#endif
                                return in;
                        }
                }
@@ -1636,11 +1665,8 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
 
 #else
 
-#if defined(CONFIG_KERNEL_2_5)
-               theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME.tv_sec;              
-#else
-               theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME;             
-#endif
+               theObject->yst_atime = theObject->yst_mtime =   theObject->yst_ctime = Y_CURRENT_TIME;
+
 #endif
                switch(type)
                {
@@ -1736,22 +1762,19 @@ 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);
                in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
-               in->win_ctime[1] = in->win_mtime[1] = in->win_atime[0];
+               in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
                
 #else
-#if defined(CONFIG_KERNEL_2_5)
-               in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME.tv_sec;
-#else
-               in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME;
-#endif
-               in->st_rdev  = rdev;
-               in->st_uid   = uid;
-               in->st_gid   = gid;
+
+               in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
+               in->yst_rdev  = rdev;
+               in->yst_uid   = uid;
+               in->yst_gid   = gid;
 #endif         
                in->nDataChunks = 0;
 
@@ -1805,7 +1828,7 @@ yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const char *name, __u32
 
 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const char *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 char *name, __u32 mode, __u32 uid, __u32 gid,const char *alias)
@@ -2031,11 +2054,11 @@ static int yaffs_FindDirtiestBlock(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)
                {
@@ -2046,12 +2069,12 @@ static int yaffs_FindDirtiestBlock(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();
@@ -2128,12 +2151,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);
@@ -2300,6 +2323,7 @@ static int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                                {
                                        // It's a header
                                        object->chunkId = newChunk;
+                                       object->serial = tags.serialNumber;
                                }
                                else
                                {
@@ -2841,6 +2865,7 @@ int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffe
        }
        else
        {
+               memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
                return 0;
        }
 
@@ -2864,10 +2889,13 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND)
        {
                yaffs_SpareInitialise(&spare);
 
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+
                 //read data before write, to ensure correct ecc 
-                //and transitions are guaranteed 1->0
+                //if we're using MTD verification under Linux
                 yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
-       
+#endif
+
                spare.pageStatus = 0; // To mark it as deleted.
 
        
@@ -2996,7 +3024,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)
                // 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];
@@ -3006,12 +3034,12 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)
                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)
                {
@@ -3113,7 +3141,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;
        
@@ -3646,7 +3674,8 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                        // using yaffs_DeleteChunk
 
                        chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
-                       if(chunkId < (dev->startBlock * 32) || chunkId >= ((dev->endBlock+1) * 32))
+                       if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) || 
+                          chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock))
                        {
                                //T(("Found daft chunkId %d for %d\n",chunkId,i));
                        }
@@ -3663,8 +3692,10 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                        int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK;
                        
                        // Got to read and rewrite the last chunk with its new size.
+                       // NB Got to zero pad to nuke old data
                        yaffs_ReadChunkDataFromObject(in,lastChunk,dev->localBuffer);
-                       
+                       memset(dev->localBuffer + sizeOfPartialChunk,0, YAFFS_BYTES_PER_CHUNK - sizeOfPartialChunk);
+
                        yaffs_WriteChunkDataToObject(in,lastChunk,dev->localBuffer,sizeOfPartialChunk,1);
                                
                }
@@ -3716,11 +3747,7 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime)
 #ifdef CONFIG_YAFFS_WINCE
                        yfsd_WinFileTimeNow(in->win_mtime);
 #else
-#if defined(CONFIG_KERNEL_2_5)
-                       in->st_mtime = CURRENT_TIME.tv_sec;
-#else
-                       in->st_mtime = CURRENT_TIME;
-#endif
+                       in->yst_mtime = Y_CURRENT_TIME;
 #endif
                }
 
@@ -3744,12 +3771,15 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
        
        yaffs_RemoveObjectFromDirectory(in);
        yaffs_DeleteChunk(in->myDev,in->chunkId,1);
+       in->chunkId = -1;
+#if 0
 #ifdef __KERNEL__
        if(in->myInode)
        {
                in->myInode->u.generic_ip = NULL;
-               in->myInode = 0;
+               in->myInode = NULL;
        }
+#endif
 #endif
        yaffs_FreeObject(in);
        return YAFFS_OK;
@@ -3787,6 +3817,8 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
 #ifdef __KERNEL__
                if(!in->myInode)
                {
+                       // Might be open at present,
+                       // Caught by delete_inode in yaffs_fs.c
                        immediateDeletion = 1;
 
                }
@@ -3944,6 +3976,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:
@@ -4034,7 +4069,7 @@ static int yaffs_Scan(yaffs_Device *dev)
        
        // Scan all the blocks...
        
-       for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
+       for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
        {
                deleted = 0;
                bi = yaffs_GetBlockInfo(dev,blk);
@@ -4158,7 +4193,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];
@@ -4167,12 +4202,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;
 
@@ -4184,7 +4219,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];
@@ -4193,12 +4228,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;
 
@@ -4219,8 +4254,9 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        {
                                                // Hoosterman, another problem....
                                                // We're trying to use a non-directory as a directory
-                                               // Todo ... handle
-                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan" TENDSTR)));
+                                               
+                                               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;
 
                                        }
                                
@@ -4542,10 +4578,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;
        }
 }
@@ -4569,19 +4605,14 @@ 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 defined(CONFIG_KERNEL_2_5)
-       if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime.tv_sec;
-       if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime.tv_sec;
-       if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime.tv_sec;
-#else
-       if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime;
-       if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime;
-       if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime;
-#endif
+       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);
        
@@ -4590,23 +4621,20 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
        return YAFFS_OK;
        
 }
+
 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;
-       
-#if defined(CONFIG_KERNEL_2_5)
-       attr->ia_atime.tv_sec = obj->st_atime;  valid |= ATTR_ATIME;
-       attr->ia_ctime.tv_sec = obj->st_ctime;  valid |= ATTR_CTIME;
-       attr->ia_mtime.tv_sec = obj->st_mtime;  valid |= ATTR_MTIME;
-#else  
-       attr->ia_atime = obj->st_atime; valid |= ATTR_ATIME;
-       attr->ia_ctime = obj->st_ctime; valid |= ATTR_CTIME;
-       attr->ia_mtime = obj->st_mtime; valid |= ATTR_MTIME;
-#endif 
+       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->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;
        
        attr->ia_valid = valid;
@@ -4670,17 +4698,16 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        int extraBits;
        int nBlocks;
 
-       if(     dev->nBytesPerChunk != YAFFS_BYTES_PER_CHUNK ||
-       
+       if(     dev->nBytesPerChunk != YAFFS_BYTES_PER_CHUNK || 
                dev->nChunksPerBlock < 2 ||
                dev->nReservedBlocks < 2 ||
-               dev->startBlock <= 0 ||
+               dev->startBlock < 0 ||
                dev->endBlock <= 0 ||
                dev->endBlock <= (dev->startBlock + dev->nReservedBlocks)
          )
        {
                //these parameters must be set before stating yaffs
-               // Other parameters startBlock,
+               // Other parameters internalStartBlock,
                return YAFFS_FAIL;
        }
 
@@ -4699,8 +4726,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        }
 
        dev->isMounted = 1;
-       
-       if(dev->startBlock <= 0 ||
+
+       if(dev->startBlock < 0 ||
           (dev->endBlock - dev->startBlock) < 10)
        {
                T(YAFFS_TRACE_ALWAYS,(TSTR("startBlock %d or endBlock %d invalid\n" TENDSTR),
@@ -4708,15 +4735,32 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
                return YAFFS_FAIL;
        }
        
-       nBlocks = dev->endBlock - dev->startBlock + 1;
+       
+       // Do we need to add an offset to use block 0?
+       
+       dev->internalStartBlock = dev->startBlock;
+       dev->internalEndBlock = dev->endBlock;
+       dev->blockOffset = 0;
+       dev->chunkOffset = 0;
+       
+       if(dev->startBlock == 0)
+       {
+               dev->internalStartBlock++;
+               dev->internalEndBlock++;
+               dev->blockOffset++;
+               dev->chunkOffset = dev->nChunksPerBlock;                
+       }
+       
+       
+       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++)
        {
@@ -4738,7 +4782,18 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        {
                dev->chunkGroupBits = bits - 16;
        }
+       
        dev->chunkGroupSize = 1 << dev->chunkGroupBits;
+
+       if(dev->nChunksPerBlock < dev->chunkGroupSize)
+       {
+               // We have a problem because the soft delete won't work if
+               // the chunk group size > chunks per block.
+               // This can be remedied by using larger "virtual blocks".
+               
+               return YAFFS_FAIL;
+       }
+
        
        
        
@@ -4755,6 +4810,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->eccUnfixed=0;
        dev->tagsEccFixed=0;
        dev->tagsEccUnfixed=0;
+       dev->nErasedBlocks=0;
        
        dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
        
@@ -4824,7 +4880,10 @@ void yaffs_Deinitialise(yaffs_Device *dev)
                yaffs_DeinitialiseBlocks(dev);
                yaffs_DeinitialiseTnodes(dev);
                yaffs_DeinitialiseObjects(dev);
+               if(dev->nShortOpCaches > 0)
+                       YFREE(dev->srCache);
                YFREE(dev->localBuffer);
+               dev->isMounted = 0;
        }
        
 }
@@ -4873,7 +4932,7 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
        struct list_head *i;    
        yaffs_Object *l;
        
-       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);
                
@@ -4977,3 +5036,7 @@ void yaffs_GutsTest(yaffs_Device *dev)
 
 
 
+
+
+
+