diff packages/fs/yaffs/current/src/yaffs_guts.c @ 353:fa7270d25c51

Merge from upstream
author Ross Younger <wry@ecoscentric.com>
date Tue, 17 Nov 2009 10:49:51 +0000
parents yaffs_guts.c@cc31d3d1ea89 yaffs_guts.c@1c56b1df53d8
children 68aafa1d2927
line wrap: on
line diff
--- a/packages/fs/yaffs/current/src/yaffs_guts.c
+++ b/packages/fs/yaffs/current/src/yaffs_guts.c
@@ -117,7 +117,6 @@ static yaffs_Tnode *yaffs_FindLevel0Tnod
 					yaffs_FileStructure *fStruct,
 					__u32 chunkId);
 
-
 /* Function to calculate chunk and offset */
 
 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
@@ -1328,7 +1327,7 @@ static void yaffs_InitialiseTnodes(yaffs
 }
 
 
-void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
+void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
 		unsigned val)
 {
 	__u32 *map = (__u32 *)tn;
@@ -1486,13 +1485,13 @@ static yaffs_Tnode *yaffs_AddOrFindLevel
 			if (tn) {
 				tn->internal[0] = fStruct->top;
 				fStruct->top = tn;
+				fStruct->topLevel++;
 			} else {
 				T(YAFFS_TRACE_ERROR,
-				  (TSTR("yaffs: no more tnodes" TENDSTR)));
+					(TSTR("yaffs: no more tnodes" TENDSTR)));
+				return NULL;
 			}
 		}
-
-		fStruct->topLevel = requiredTallness;
 	}
 
 	/* Traverse down to level 0, adding anything we need */
@@ -1511,6 +1510,8 @@ static yaffs_Tnode *yaffs_AddOrFindLevel
 			if ((l > 1) && !tn->internal[x]) {
 				/* Add missing non-level-zero tnode */
 				tn->internal[x] = yaffs_GetTnode(dev);
+				if(!tn->internal[x])
+					return NULL;
 
 			} else if (l == 1) {
 				/* Looking from level 1 at level 0 */
@@ -1523,6 +1524,8 @@ static yaffs_Tnode *yaffs_AddOrFindLevel
 				} else if (!tn->internal[x]) {
 					/* Don't have one, none passed in */
 					tn->internal[x] = yaffs_GetTnode(dev);
+					if(!tn->internal[x])
+						return NULL;
 				}
 			}
 
@@ -1646,7 +1649,7 @@ static int yaffs_DeleteWorker(yaffs_Obje
 
 					}
 
-					yaffs_PutLevel0Tnode(dev, tn, i, 0);
+					yaffs_LoadLevel0Tnode(dev, tn, i, 0);
 				}
 
 			}
@@ -1723,7 +1726,7 @@ static int yaffs_SoftDeleteWorker(yaffs_
 					 * a block.
 					 */
 					yaffs_SoftDeleteChunk(dev, theChunk);
-					yaffs_PutLevel0Tnode(dev, tn, i, 0);
+					yaffs_LoadLevel0Tnode(dev, tn, i, 0);
 				}
 
 			}
@@ -2174,17 +2177,19 @@ yaffs_Object *yaffs_CreateNewObject(yaff
 	if (number < 0)
 		number = yaffs_CreateNewObjectNumber(dev);
 
-	theObject = yaffs_AllocateEmptyObject(dev);
-	if (!theObject)
-		return NULL;
-
 	if (type == YAFFS_OBJECT_TYPE_FILE) {
 		tn = yaffs_GetTnode(dev);
-		if (!tn) {
-			yaffs_DoGenericObjectDeletion(theObject);
+		if (!tn)
 			return NULL;
-		}
-	}
+	}
+
+	theObject = yaffs_AllocateEmptyObject(dev);
+	if (!theObject){
+		if(tn)
+			yaffs_FreeTnode(dev,tn);
+		return NULL;
+	}
+
 
 	if (theObject) {
 		theObject->fake = 0;
@@ -2287,18 +2292,20 @@ static yaffs_Object *yaffs_MknodObject(y
 	if (yaffs_FindObjectByName(parent, name))
 		return NULL;
 
-	in = yaffs_CreateNewObject(dev, -1, type);
-
-	if (!in)
-		return YAFFS_FAIL;
-
 	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
 		str = yaffs_CloneString(aliasString);
-		if (!str) {
-			yaffs_DoGenericObjectDeletion(in);
+		if (!str)
 			return NULL;
-		}
-	}
+	}
+
+	in = yaffs_CreateNewObject(dev, -1, type);
+
+	if (!in){
+		if(str)
+			YFREE(str);
+		return NULL;
+	}
+
 
 
 
@@ -3361,7 +3368,7 @@ static int yaffs_FindAndDeleteChunkInFil
 
 		/* Delete the entry in the filestructure (if found) */
 		if (retVal != -1)
-			yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
+			yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
 	}
 
 	return retVal;
@@ -3431,6 +3438,8 @@ static int yaffs_PutChunkIntoFile(yaffs_
 	/* NB inScan is zero unless scanning.
 	 * For forward scanning, inScan is > 0;
 	 * for backward scanning inScan is < 0
+	 *
+	 * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
 	 */
 
 	yaffs_Tnode *tn;
@@ -3462,6 +3471,11 @@ static int yaffs_PutChunkIntoFile(yaffs_
 					NULL);
 	if (!tn)
 		return YAFFS_FAIL;
+	
+	if(!chunkInNAND)
+		/* Dummy insert, bail now */
+		return YAFFS_OK;
+		
 
 	existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
 
@@ -3543,7 +3557,7 @@ static int yaffs_PutChunkIntoFile(yaffs_
 	if (existingChunk == 0)
 		in->nDataChunks++;
 
-	yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
+	yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
 
 	return YAFFS_OK;
 }
@@ -3666,11 +3680,19 @@ static int yaffs_WriteChunkDataToObject(
 		YBUG();
 	}
 	
+	/*
+	 * If there isn't already a chunk there then do a dummy
+	 * insert to make sue we have the desired tnode structure.
+	 */
+	if(prevChunkId < 1 &&
+		yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0) != YAFFS_OK)
+		return -1;
+		
 	newChunkId =
 	    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
 					      useReserve);
 
-	if (newChunkId >= 0) {
+	if (newChunkId > 0) {
 		yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
 
 		if (prevChunkId > 0)
@@ -5488,9 +5510,126 @@ static void yaffs_StripDeletedObjects(ya
 	}
 
 }
-#endif
-
-#ifndef CONFIG_YAFFS_NO_YAFFS1
+
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ *  This code assumes that we don't ever change the current relationships between
+ *  directories:
+ *   rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
+ *   lostNfound->parent == rootDir
+ *
+ * This fixes the problem where directories might have inadvertently been deleted
+ * leaving the object "hanging" without being rooted in the directory tree.
+ */
+ 
+static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
+{
+	return (obj == dev->deletedDir ||
+		obj == dev->unlinkedDir||
+		obj == dev->rootDir);
+}
+
+static void yaffs_FixHangingObjects(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	yaffs_Object *parent;
+	int i;
+	struct ylist_head *lh;
+	struct ylist_head *n;
+	int depthLimit;
+	int hanging;
+
+
+	/* Iterate through the objects in each hash entry,
+	 * looking at each object.
+	 * Make sure it is rooted.
+	 */
+
+	for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {
+		ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
+			if (lh) {
+				obj = ylist_entry(lh, yaffs_Object, hashLink);
+				parent= obj->parent;
+				
+				if(yaffs_HasNULLParent(dev,obj)){
+					/* These directories are not hanging */
+					hanging = 0;
+				}
+				else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+					hanging = 1;
+				else if(yaffs_HasNULLParent(dev,parent))
+					hanging = 0;
+				else {
+					/*
+					 * Need to follow the parent chain to see if it is hanging.
+					 */
+					hanging = 0;
+					depthLimit=100;
+
+					while(parent != dev->rootDir &&
+						parent->parent &&
+						parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+						depthLimit > 0){
+						parent = parent->parent;
+						depthLimit--;
+					}
+					if(parent != dev->rootDir)
+						hanging = 1;
+				}
+				if(hanging){
+					T(YAFFS_TRACE_SCAN,
+					  (TSTR("Hanging object %d moved to lost and found" TENDSTR),
+					  	obj->objectId));
+					yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
+				}
+			}
+		}
+	}
+}
+
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
+{
+	yaffs_Object *obj;
+	struct ylist_head *lh;
+	struct ylist_head *n;
+
+	if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+		YBUG();
+	
+	ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
+		if (lh) {
+			obj = ylist_entry(lh, yaffs_Object, siblings);
+			if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
+				yaffs_DeleteDirectoryContents(obj);
+
+			T(YAFFS_TRACE_SCAN,
+				(TSTR("Deleting lost_found object %d" TENDSTR),
+				obj->objectId));
+
+			/* Need to use UnlinkObject since Delete would not handle
+			 * hardlinked objects correctly.
+			 */
+			yaffs_UnlinkObject(obj); 
+		}
+	}
+			
+}
+
+static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
+{
+	yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
+}
+
 static int yaffs_Scan(yaffs_Device *dev)
 {
 	yaffs_ExtendedTags tags;
@@ -7465,8 +7604,10 @@ int yaffs_GutsInitialise(yaffs_Device *d
                 init_failed = 1;
 
             yaffs_StripDeletedObjects(dev);
+		yaffs_FixHangingObjects(dev);
+		if(dev->emptyLostAndFound)
+			yaffs_EmptyLostAndFound(dev);
 #endif
-        }
 	}
 
 	if (init_failed) {
@@ -7490,6 +7631,9 @@ int yaffs_GutsInitialise(yaffs_Device *d
 	yaffs_VerifyFreeChunks(dev);
 	yaffs_VerifyBlocks(dev);
 
+	/* Clean up any aborted checkpoint data */
+	if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
+		yaffs_InvalidateCheckpoint(dev);
 
 	T(YAFFS_TRACE_TRACING,
 	  (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));