Fix unmounting flag
[yaffs/.git] / yaffs_guts.c
index d7246590925400795b7831e3e74fe9d4fac54c8e..0ace425f92f3d055bf5ad7ced90354057f344676 100644 (file)
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.23 2003-04-03 17:32:11 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.39 2005-01-24 22:26:45 charles Exp $";
 
 #include "yportenv.h"
 
 #include "yaffsinterface.h"
 #include "yaffs_guts.h"
 
-
-
-
 #define YAFFS_PASSIVE_GC_CHUNKS 2
 
+#if 0
+// Use Steven Hill's ECC struff instead
 // External functions for ECC on data
 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-
+#define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc)
+#define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc)
+#else
+#include "yaffs_ecc.h"
+#endif
 
 // 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.
@@ -239,10 +242,10 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
                int eccResult1,eccResult2;
                __u8 calcEcc[3];
                 
-                       nand_calculate_ecc(data,calcEcc);
-                       eccResult1 = nand_correct_data (data,spare->ecc1, calcEcc);
-                       nand_calculate_ecc(&data[256],calcEcc);
-                       eccResult2 = nand_correct_data (&data[256],spare->ecc2, calcEcc);
+                       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)
                        {
@@ -582,8 +585,8 @@ void yaffs_SetObjectName(yaffs_Object *obj, const char *name)
 
 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
 {
-       nand_calculate_ecc (data , spare->ecc1);
-       nand_calculate_ecc (&data[256] , spare->ecc2);
+       yaffs_ECCCalculate(data , spare->ecc1);
+       yaffs_ECCCalculate(&data[256] , spare->ecc2);
 }
 
 void yaffs_CalcTagsECC(yaffs_Tags *tags)
@@ -779,11 +782,16 @@ static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
 {
        // Free the list of allocated tnodes
-       
+       yaffs_TnodeList *tmp;
+               
        while(dev->allocatedTnodeList)
        {
+               tmp =  dev->allocatedTnodeList->next;
+
                YFREE(dev->allocatedTnodeList->tnodes);
-               dev->allocatedTnodeList =  dev->allocatedTnodeList->next;
+               YFREE(dev->allocatedTnodeList);
+               dev->allocatedTnodeList = tmp;
+               
        }
        
        dev->freeTnodes = NULL;
@@ -1077,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;
                                                        }
@@ -1148,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));
@@ -1434,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.
@@ -1443,16 +1463,33 @@ 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)
 {
        // Free the list of allocated Objects
        
+       yaffs_ObjectList *tmp;
+       
        while( dev->allocatedObjectList)
        {
+               tmp =  dev->allocatedObjectList->next;
                YFREE(dev->allocatedObjectList->objects);
-               dev->allocatedObjectList =  dev->allocatedObjectList->next;
+               YFREE(dev->allocatedObjectList);
+               
+               dev->allocatedObjectList =  tmp;
        }
        
        dev->freeObjects = NULL;
@@ -1586,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;
                        }
                }
@@ -1622,7 +1664,9 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
                theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
 
 #else
-               theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME;
+
+               theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = Y_CURRENT_TIME;
+
 #endif
                switch(type)
                {
@@ -1723,10 +1767,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
 #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
-               in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME;
+
+               in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
                in->st_rdev  = rdev;
                in->st_uid   = uid;
                in->st_gid   = gid;
@@ -2278,6 +2323,7 @@ static int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                                {
                                        // It's a header
                                        object->chunkId = newChunk;
+                                       object->serial = tags.serialNumber;
                                }
                                else
                                {
@@ -2819,6 +2865,7 @@ int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffe
        }
        else
        {
+               memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
                return 0;
        }
 
@@ -2841,7 +2888,14 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND)
        if(markNAND)
        {
                yaffs_SpareInitialise(&spare);
-       
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+
+                //read data before write, to ensure correct ecc 
+                //if we're using MTD verification under Linux
+                yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
+#endif
+
                spare.pageStatus = 0; // To mark it as deleted.
 
        
@@ -3087,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;
        
@@ -3162,7 +3216,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
                        {
                                //T(("Grabbing empty %d\n",i));
                                
-                               printf("Grabbing empty %d\n",i);
+                               //printf("Grabbing empty %d\n",i);
                        
                                return &dev->srCache[i];
                        }
@@ -3186,7 +3240,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
        
                //T(("Grabbing non-empty %d\n",theOne));
                
-               if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
+               //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
                
                return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;
        }
@@ -3239,7 +3293,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
                        if(!cache || cache->dirty)
                        {
                        
-                               printf("Dirty ");
+                               //printf("Dirty ");
                                yaffs_FlushFilesChunkCache(theObj);
                
                                // Try again
@@ -3247,7 +3301,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
                        }
                        else
                        {
-                               printf(" pushout %d\n",pushout);
+                               //printf(" pushout %d\n",pushout);
                        }
                        
                }
@@ -3620,7 +3674,7 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                        // using yaffs_DeleteChunk
 
                        chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
-                       if(chunkId <= 0 || chunkId >= (dev->endBlock * 32))
+                       if(chunkId < (dev->startBlock * 32) || chunkId >= ((dev->endBlock+1) * 32))
                        {
                                //T(("Found daft chunkId %d for %d\n",chunkId,i));
                        }
@@ -3637,8 +3691,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);
                                
                }
@@ -3690,7 +3746,7 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime)
 #ifdef CONFIG_YAFFS_WINCE
                        yfsd_WinFileTimeNow(in->win_mtime);
 #else
-                       in->st_mtime = CURRENT_TIME;
+                       in->st_mtime = Y_CURRENT_TIME;
 #endif
                }
 
@@ -3714,12 +3770,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;
@@ -3757,6 +3816,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;
 
                }
@@ -4189,8 +4250,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;
 
                                        }
                                
@@ -4543,9 +4605,10 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
        if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
        if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
        
-       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;
+       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_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
        
@@ -4554,6 +4617,7 @@ 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;
@@ -4562,10 +4626,11 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
        attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
        attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
        
-       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;
        
+       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;
+
        attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
        
        attr->ia_valid = valid;
@@ -4629,8 +4694,7 @@ 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 ||
@@ -4697,7 +4761,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;
+       }
+
        
        
        
@@ -4783,7 +4858,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;
        }
        
 }
@@ -4810,7 +4888,7 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
        }
        
        
-       printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);   
+       // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);        
 
        if(nFree < 0) nFree = 0;
 
@@ -4825,6 +4903,7 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
        int nFree;
        int pending;
        int b;
+       int nDirtyCacheChunks=0;
        
        yaffs_BlockInfo *blk;
        
@@ -4872,6 +4951,20 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
 
        nFree += pending;
        
+       // Now count the number of dirty chunks in the cache and subtract those
+       
+       {
+               int i;
+               for(i = 0; i < dev->nShortOpCaches; i++)
+               {
+                       if(dev->srCache[i].dirty) nDirtyCacheChunks++;
+               }
+       }
+       
+       nFree -= nDirtyCacheChunks;
+       
+       nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
+       
        if(nFree < 0) nFree = 0;
 
        return nFree;   
@@ -4921,3 +5014,6 @@ void yaffs_GutsTest(yaffs_Device *dev)
 
 
 
+
+
+