Clean ups and improve some out of memory handling
[yaffs2.git] / yaffs_guts.c
index 0bab9cf00f5ea6f8c67146835ff82b048912ffac..df8efbe3c6371ac22914fc444492775f8cf82c48 100644 (file)
  */
 
 const char *yaffs_guts_c_version =
-    "$Id: yaffs_guts.c,v 1.100 2009-12-22 04:09:06 charles Exp $";
+    "$Id: yaffs_guts.c,v 1.107 2010-02-17 02:01:25 charles Exp $";
 
 #include "yportenv.h"
+#include "yaffs_trace.h"
 
 #include "yaffsinterface.h"
 #include "yaffs_guts.h"
@@ -1188,11 +1189,22 @@ static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
  * adds them to the tnode free list.
  * Don't use this function directly
  */
+static Y_INLINE int yaffs_CalcTnodeSize(yaffs_Device *dev)
+{
+       int tnodeSize;
+       /* Calculate the tnode size in bytes for variable width tnode support.
+        * Must be a multiple of 32-bits  */
+       tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+       if (tnodeSize < sizeof(yaffs_Tnode))
+               tnodeSize = sizeof(yaffs_Tnode);
+       return tnodeSize;
+}
 
 static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
 {
        int i;
-       int tnodeSize;
+       int tnodeSize = yaffs_CalcTnodeSize(dev);
        yaffs_Tnode *newTnodes;
        __u8 *mem;
        yaffs_Tnode *curr;
@@ -1202,12 +1214,6 @@ static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
        if (nTnodes < 1)
                return YAFFS_OK;
 
-       /* Calculate the tnode size in bytes for variable width tnode support.
-        * Must be a multiple of 32-bits  */
-       tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
-       if (tnodeSize < sizeof(yaffs_Tnode))
-               tnodeSize = sizeof(yaffs_Tnode);
 
        /* make these things */
 
@@ -1280,6 +1286,11 @@ static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
 {
        yaffs_Tnode *tn = NULL;
 
+#ifdef CONFIG_YAFFS_VALGRIND_TEST
+       tn = YMALLOC(yaffs_CalcTnodeSize(dev));
+       if(tn)
+               dev->nTnodesCreated++;
+#else
        /* If there are none left make more */
        if (!dev->freeTnodes)
                yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
@@ -1296,7 +1307,7 @@ static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
                dev->freeTnodes = dev->freeTnodes->internal[0];
                dev->nFreeTnodes--;
        }
-
+#endif
        dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
 
        return tn;
@@ -1305,10 +1316,7 @@ static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
 {
        yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
-       int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
-       if (tnodeSize < sizeof(yaffs_Tnode))
-               tnodeSize = sizeof(yaffs_Tnode);
+       int tnodeSize = yaffs_CalcTnodeSize(dev);
 
        if (tn)
                memset(tn, 0, tnodeSize);
@@ -1320,6 +1328,10 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
 static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
 {
        if (tn) {
+#ifdef CONFIG_YAFFS_VALGRIND_TEST
+               YFREE(tn);
+               dev->nTnodesCreated--;
+#else
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
                if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
                        /* Hoosterman, this thing looks like it is already in the list */
@@ -1331,6 +1343,7 @@ static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
                tn->internal[0] = dev->freeTnodes;
                dev->freeTnodes = tn;
                dev->nFreeTnodes++;
+#endif
        }
        dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
 }
@@ -1351,6 +1364,7 @@ static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
 
        dev->freeTnodes = NULL;
        dev->nFreeTnodes = 0;
+       dev->nTnodesCreated = 0;
 }
 
 static void yaffs_InitialiseTnodes(yaffs_Device *dev)
@@ -1547,7 +1561,6 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
                                tn->internal[x] = yaffs_GetTnode(dev);
                                if(!tn->internal[x])
                                        return NULL;
-
                        } else if (l == 1) {
                                /* Looking from level 1 at level 0 */
                                if (passedTn) {
@@ -1807,6 +1820,10 @@ static void yaffs_SoftDeleteFile(yaffs_Object *obj)
  * level 0 tnode entries must be zeroed out.
  * Could also use this for file deletion, but that's probably better handled
  * by a special case.
+ *
+ * This function is recursive. For levels > 0 the function is called again on
+ * any sub-tree. For level == 0 we just check if the sub-tree has data.
+ * If there is no data in a subtree then it is pruned.
  */
 
 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
@@ -1818,17 +1835,27 @@ static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
        if (tn) {
                hasData = 0;
 
-               for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
-                       if (tn->internal[i] && level > 0) {
-                               tn->internal[i] =
-                                   yaffs_PruneWorker(dev, tn->internal[i],
-                                                     level - 1,
-                                                     (i == 0) ? del0 : 1);
+               if(level > 0){
+                       for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+                               if (tn->internal[i]) {
+                                       tn->internal[i] =
+                                               yaffs_PruneWorker(dev, tn->internal[i],
+                                                       level - 1,
+                                                       (i == 0) ? del0 : 1);
+                               }
+
+                               if (tn->internal[i])
+                                       hasData++;
                        }
+               } else {
+                       int tnodeSize_u32 = yaffs_CalcTnodeSize(dev)/sizeof(__u32);
+                       __u32 *map = (__u32 *)tn;
 
-                       if (tn->internal[i])
-                               hasData++;
-               }
+                        for(i = 0; !hasData && i < tnodeSize_u32; i++){
+                                if(map[i])
+                                        hasData++;
+                        }
+                }
 
                if (hasData == 0 && del0) {
                        /* Free and return NULL */
@@ -1942,8 +1969,10 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
 {
        yaffs_Object *tn = NULL;
 
-#ifdef VALGRIND_TEST
+#ifdef CONFIG_YAFFS_VALGRIND_TEST
        tn = YMALLOC(sizeof(yaffs_Object));
+       if(tn)
+               dev->nObjectsCreated++;
 #else
        /* If there are none left make more */
        if (!dev->freeObjects)
@@ -2030,17 +2059,16 @@ static void yaffs_FreeObject(yaffs_Object *tn)
 {
        yaffs_Device *dev = tn->myDev;
 
-#ifdef __KERNEL__
        T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
-#endif
 
+       if (!tn)
+               YBUG();
        if (tn->parent)
                YBUG();
        if (!ylist_empty(&tn->siblings))
                YBUG();
 
 
-#ifdef __KERNEL__
        if (tn->myInode) {
                /* We're still hooked up to a cached inode.
                 * Don't delete now, but mark for later deletion
@@ -2048,12 +2076,12 @@ static void yaffs_FreeObject(yaffs_Object *tn)
                tn->deferedFree = 1;
                return;
        }
-#endif
 
        yaffs_UnhashObject(tn);
 
-#ifdef VALGRIND_TEST
+#ifdef CONFIG_YAFFS_VALGRIND_TEST
        YFREE(tn);
+       dev->nObjectsCreated--;
        tn = NULL;
 #else
        /* Link into the free list. */
@@ -2090,6 +2118,7 @@ static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
 
        dev->freeObjects = NULL;
        dev->nFreeObjects = 0;
+       dev->nObjectsCreated = 0;
 }
 
 static void yaffs_InitialiseObjects(yaffs_Device *dev)
@@ -2211,7 +2240,7 @@ yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
                                    yaffs_ObjectType type)
 {
-       yaffs_Object *theObject;
+       yaffs_Object *theObject=NULL;
        yaffs_Tnode *tn = NULL;
 
        if (number < 0)
@@ -2353,6 +2382,7 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
 
 
 
+
        if (in) {
                in->hdrChunk = 0;
                in->valid = 1;
@@ -2901,12 +2931,7 @@ static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
                int nBytes = 0;
                int nBlocks;
                int devBlocks = (dev->endBlock - dev->startBlock + 1);
-               int tnodeSize;
-
-               tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
-               if (tnodeSize < sizeof(yaffs_Tnode))
-                       tnodeSize = sizeof(yaffs_Tnode);
+               int tnodeSize = yaffs_CalcTnodeSize(dev);
 
                nBytes += sizeof(yaffs_CheckpointValidity);
                nBytes += sizeof(yaffs_CheckpointDevice);
@@ -3224,7 +3249,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                                                        object->serial =   tags.serialNumber;
                                                } else {
                                                        /* It's a data chunk */
-                                                       yaffs_PutChunkIntoFile
+                                                       int ok;
+                                                       ok = yaffs_PutChunkIntoFile
                                                            (object,
                                                             tags.chunkId,
                                                             newChunk, 0);
@@ -3536,7 +3562,6 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
        if(!chunkInNAND)
                /* Dummy insert, bail now */
                return YAFFS_OK;
-               
 
        existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
 
@@ -3723,8 +3748,14 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
 
        yaffs_CheckGarbageCollection(dev);
 
-       /* Get the previous chunk at this location in the file if it exists */
+       /* Get the previous chunk at this location in the file if it exists.
+        * If it does not exist then put a zero into the tree. This creates
+        * the tnode now, rather than later when it is harder to clean up.
+        */
        prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
+       if(prevChunkId <= 0 &&
+               !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0)){
+       }
 
        /* Set up new tags */
        yaffs_InitialiseTags(&newTags);
@@ -4405,11 +4436,7 @@ static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
        int i;
        yaffs_Device *dev = in->myDev;
        int ok = 1;
-       int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
-       if (tnodeSize < sizeof(yaffs_Tnode))
-               tnodeSize = sizeof(yaffs_Tnode);
-
+       int tnodeSize = yaffs_CalcTnodeSize(dev);
 
        if (tn) {
                if (level > 0) {
@@ -4460,10 +4487,7 @@ static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
        yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
        yaffs_Tnode *tn;
        int nread = 0;
-       int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
-       if (tnodeSize < sizeof(yaffs_Tnode))
-               tnodeSize = sizeof(yaffs_Tnode);
+       int tnodeSize = yaffs_CalcTnodeSize(dev);
 
        ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
 
@@ -5233,13 +5257,8 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
        int retVal;
        int immediateDeletion = 0;
 
-#ifdef __KERNEL__
        if (!in->myInode)
                immediateDeletion = 1;
-#else
-       if (in->inUse <= 0)
-               immediateDeletion = 1;
-#endif
 
        if (immediateDeletion) {
                retVal =
@@ -5359,13 +5378,8 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
 
        int immediateDeletion = 0;
 
-#ifdef __KERNEL__
        if (!obj->myInode)
                immediateDeletion = 1;
-#else
-       if (obj->inUse <= 0)
-               immediateDeletion = 1;
-#endif
 
        if(obj)
                yaffs_UpdateParent(obj->parent);
@@ -5382,23 +5396,26 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
                 * Instead, we do the following:
                 * - Select a hardlink.
                 * - Unhook it from the hard links
-                * - Unhook it from its parent directory (so that the rename can work)
+                * - Move it from its parent directory (so that the rename can work)
                 * - Rename the object to the hardlink's name.
                 * - Delete the hardlink
                 */
 
                yaffs_Object *hl;
+               yaffs_Object *parent;
                int retVal;
                YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
 
                hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
 
+               yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+               parent = hl->parent;
+
                ylist_del_init(&hl->hardLinks);
-               ylist_del_init(&hl->siblings);
 
-               yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+               yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl);
 
-               retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
+               retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0);
 
                if (retVal == YAFFS_OK)
                        retVal = yaffs_DoGenericObjectDeletion(hl);