changeset 343:5d655bed5d6c

Add fix for hanging objects
author charles
date Sat, 07 Nov 2009 02:06:58 +0000
parents ea8ca3110673
children 90a548c51099
files yaffs_guts.c
diffstat 1 files changed, 122 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -113,7 +113,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,
@@ -5471,6 +5470,125 @@ static void yaffs_StripDeletedObjects(ya
 
 }
 
+/*
+ * 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;
@@ -7432,6 +7550,9 @@ int yaffs_GutsInitialise(yaffs_Device *d
 				init_failed = 1;
 
 		yaffs_StripDeletedObjects(dev);
+		yaffs_FixHangingObjects(dev);
+		if(dev->emptyLostAndFound)
+			yaffs_EmptyLostAndFound(dev);
 	}
 
 	if (init_failed) {
@@ -7455,7 +7576,6 @@ 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);