*** empty log message ***
[yaffs/.git] / yaffs_guts.c
index b042a9a7c61dbaf9a0f659e503d34c60525a0583..eaa18fda50db7701b6235d0621ff51cb7141d41f 100644 (file)
@@ -72,7 +72,7 @@ static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force
 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
 static int yaffs_CheckStructures(void);
-static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
 
 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
@@ -833,8 +833,9 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru
 
 // DeleteWorker scans backwards through the tnode tree and deletes all the
 // chunks and tnodes in the file
+// Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
 
-static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
 {
        int i;
        int chunkInInode;
@@ -842,6 +843,7 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
        yaffs_Tags tags;
        int found;
        int chunkDeleted;
+       int allDone = 1;
        
        
        if(tn)
@@ -849,17 +851,28 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
                if(level > 0)
                {
                
-                       for(i = YAFFS_NTNODES_INTERNAL -1; i >= 0 && (!limit || *limit > 0); i--)
+                       for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
                        {
                            if(tn->internal[i])
                        {
-                                       yaffs_DeleteWorker(in,tn->internal[i],level - 1,
+                                       if(limit && (*limit) < 0)
+                                       {
+                                               allDone = 0;
+                                       }
+                                       else
+                                       {
+                                               allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
                                                                                (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
-                                       yaffs_FreeTnode(in->myDev,tn->internal[i]);
-                               tn->internal[i] = NULL;
+                                       }
+                                       if(allDone)
+                                       {
+                                               yaffs_FreeTnode(in->myDev,tn->internal[i]);
+                                       tn->internal[i] = NULL;
+                                       }
                            }
                    
                        }
+                       return (allDone) ? 1 : 0;
                }
                else if(level == 0)
                {
@@ -904,11 +917,15 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
                            }
                    
                        }
+                       return 1;
+
                        
                }
                
        }
        
+       return 1;
+       
 }
 
 
@@ -1929,14 +1946,19 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
        {
                yaffs_Object *obj = dev->unlinkedDeletion;
                int limit;
+               int delresult;
                limit = 50; // Max number of chunks to delete in a file. NB this can be exceeded, but not by much.
-               yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
+               delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
+               
                if(obj->nDataChunks == 0)
                {
                        // Done all the deleting of data chunks.
                        // Now dump the header and clean up
-                       yaffs_DoGenericObjectDeletion(dev->unlinkedDeletion);
+                       yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
+                       yaffs_DoGenericObjectDeletion(obj);
                        dev->nDeletedFiles--;
+                       dev->nUnlinkedFiles--;
+                       dev->nBackgroundDeletions++;
                        dev->unlinkedDeletion = NULL;   
                }
        }
@@ -3071,11 +3093,35 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
        return  yaffs_DoGenericObjectDeletion(in);
 #else
        int retVal;
+       int immediateDeletion=0;
        retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL);
        if(retVal == YAFFS_OK)
        {
-               in->unlinked = 1;
-               in->renameAllowed = 0;
+               //in->unlinked = 1;
+               //in->myDev->nUnlinkedFiles++;
+               //in->renameAllowed = 0;
+#ifdef __KERNEL__
+               if(in->myInode)
+               {
+                       immediateDeletion = 1;
+
+               }
+#endif
+#if WIN32
+               if(in->inUse <= 0)
+               {
+                       immediateDeletion = 1;
+
+               }
+#endif
+               
+               if(immediateDeletion)
+               {
+                       T((TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
+                       in->deleted=1;
+                       in->myDev->nDeletedFiles++;
+               }
+       
        }
        return retVal;
 
@@ -3090,9 +3136,12 @@ int yaffs_DeleteFile(yaffs_Object *in)
        {
                retVal = yaffs_UnlinkFile(in);
        }
-       if(retVal == YAFFS_OK && in->unlinked)
+       if(retVal == YAFFS_OK && 
+          in->unlinked &&
+          !in->deleted)
        {
                in->deleted = 1;
+               in->myDev->nDeletedFiles++;
        }
        return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
 }
@@ -3639,6 +3688,7 @@ static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *ob
        if(directory == obj->myDev->unlinkedDir)
        {
                obj->unlinked = 1;
+               obj->myDev->nUnlinkedFiles++;
                obj->renameAllowed = 0;
        }
 }
@@ -3986,6 +4036,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->doingBufferedBlockRewrite = 0;
        dev->blockSelectedForGC = -1;
        dev->nDeletedFiles = 0;
+       dev->nBackgroundDeletions=0;
+       dev->nUnlinkedFiles = 0;
        
        yaffs_InitialiseBlocks(dev,nBlocks);