Add fix for hanging objects
authorcharles <charles>
Sat, 7 Nov 2009 02:06:58 +0000 (02:06 +0000)
committercharles <charles>
Sat, 7 Nov 2009 02:06:58 +0000 (02:06 +0000)
Kconfig
moduleconfig.h
yaffs_fs.c
yaffs_guts.c
yaffs_guts.h

diff --git a/Kconfig b/Kconfig
index 1d3bb71..4a8b0c8 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -166,3 +166,12 @@ config YAFFS_SHORT_NAMES_IN_RAM
          but makes look-ups faster.
 
          If unsure, say Y.
+
+config YAFFS_EMPTY_LOST_AND_FOUND
+       bool "Empty lost and found on boot"
+       depends on YAFFS_FS
+       default n
+       help
+         If this is enabled then the contents of lost and found is
+         automatically dumped at mount.
+
index 99c9f6a..6468907 100644 (file)
 /* Meaning: Disables testing whether chunks are erased before writing to them*/
 #define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
 
+/* Default: Not Selected */
+/* Meaning: At mount automatically empty all files from lost and found. */
+/* This is done to fix an old problem where rmdir was not checking for an */
+/* empty directory. This can also be achieved with a mount option. */
+/* #define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND */
+
 /* Default: Selected */
 /* Meaning: Cache short names, taking more RAM, but faster look-ups */
 #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
index 93236e4..72f4b62 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 const char *yaffs_fs_c_version =
-    "$Id: yaffs_fs.c,v 1.85 2009-10-15 00:45:46 charles Exp $";
+    "$Id: yaffs_fs.c,v 1.86 2009-11-07 02:11:01 charles Exp $";
 extern const char *yaffs_guts_c_version;
 
 #include <linux/version.h>
@@ -118,7 +118,7 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
 #include "yaffs_mtdif1.h"
 #include "yaffs_mtdif2.h"
 
-unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
+unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
 unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
 unsigned int yaffs_auto_checkpoint = 1;
 
@@ -1814,11 +1814,13 @@ typedef struct {
        int no_cache;
        int tags_ecc_on;
        int tags_ecc_overridden;
-       int lazy_load_enabled;
-       int lazy_load_overridden;
+       int lazy_loading_enabled;
+       int lazy_loading_overridden;
+       int empty_lost_and_found;
+       int empty_lost_and_found_overridden;
 } yaffs_options;
 
-#define MAX_OPT_LEN 20
+#define MAX_OPT_LEN 30
 static int yaffs_parse_options(yaffs_options *options, const char *options_str)
 {
        char cur_opt[MAX_OPT_LEN + 1];
@@ -1850,12 +1852,18 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str)
                } else if (!strcmp(cur_opt, "tags-ecc-on")){
                        options->tags_ecc_on = 1;
                        options->tags_ecc_overridden = 1;
-               } else if (!strcmp(cur_opt, "lazy-load-off")){
-                       options->lazy_load_enabled = 0;
-                       options->lazy_load_overridden=1;
-               } else if (!strcmp(cur_opt, "lazy-load-on")){
-                       options->lazy_load_enabled = 1;
-                       options->lazy_load_overridden = 1;
+               } else if (!strcmp(cur_opt, "lazy-loading-off")){
+                       options->lazy_loading_enabled = 0;
+                       options->lazy_loading_overridden=1;
+               } else if (!strcmp(cur_opt, "lazy-loading-on")){
+                       options->lazy_loading_enabled = 1;
+                       options->lazy_loading_overridden = 1;
+               } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
+                       options->empty_lost_and_found = 0;
+                       options->empty_lost_and_found_overridden=1;
+               } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
+                       options->empty_lost_and_found = 1;
+                       options->empty_lost_and_found_overridden=1;
                } else if (!strcmp(cur_opt, "no-cache"))
                        options->no_cache = 1;
                else if (!strcmp(cur_opt, "no-checkpoint-read"))
@@ -2075,8 +2083,8 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
 #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
        dev->disableLazyLoad = 1;
 #endif
-       if(options.lazy_load_overridden)
-               dev->disableLazyLoad = !options.lazy_load_enabled;
+       if(options.lazy_loading_overridden)
+               dev->disableLazyLoad = !options.lazy_loading_enabled;
 
 #ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
        dev->noTagsECC = 1;
@@ -2084,6 +2092,12 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        if(options.tags_ecc_overridden)
                dev->noTagsECC = !options.tags_ecc_on;
 
+#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
+       dev->emptyLostAndFound = 1;
+#endif
+       if(options.empty_lost_and_found_overridden)
+               dev->emptyLostAndFound = options.empty_lost_and_found;
+
        /* ... and the functions. */
        if (yaffsVersion == 2) {
                dev->writeChunkWithTagsToNAND =
@@ -2284,7 +2298,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
 
 static struct proc_dir_entry *my_proc_entry;
 
-static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
+static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
 {
        buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
        buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
@@ -2319,10 +2333,19 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
        buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
        buf +=
            sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
+
+       return buf;
+}
+
+
+static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
+{
        buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
        buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC);
        buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
        buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
+       buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->emptyLostAndFound);
+       buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->disableLazyLoad);
 
        return buf;
 }
@@ -2345,27 +2368,35 @@ static int yaffs_proc_read(char *page,
        *(int *)start = 1;
 
        /* Print header first */
-       if (step == 0) {
+       if (step == 0)
                buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
                               "\n%s\n%s\n", yaffs_fs_c_version,
                               yaffs_guts_c_version);
-       }
-
-       /* hold lock_kernel while traversing yaffs_dev_list */
-       lock_kernel();
-
-       /* Locate and print the Nth entry.  Order N-squared but N is small. */
-       ylist_for_each(item, &yaffs_dev_list) {
-               yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
-               if (n < step) {
-                       n++;
-                       continue;
+       else if (step == 1)
+               buf += sprintf(buf,"\n");
+       else {
+               step-=2;
+               
+               /* hold lock_kernel while traversing yaffs_dev_list */
+               lock_kernel();
+
+               /* Locate and print the Nth entry.  Order N-squared but N is small. */
+               ylist_for_each(item, &yaffs_dev_list) {
+                       yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
+                       if (n < (step & ~1)) {
+                               n+=2;
+                               continue;
+                       }
+                       if((step & 1)==0){
+                               buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
+                               buf = yaffs_dump_dev_part0(buf, dev);
+                       } else
+                               buf = yaffs_dump_dev_part1(buf, dev);
+                       
+                       break;
                }
-               buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
-               buf = yaffs_dump_dev(buf, dev);
-               break;
+               unlock_kernel();
        }
-       unlock_kernel();
 
        return buf - page < count ? buf - page : count;
 }
@@ -2410,7 +2441,7 @@ static struct {
 };
 
 #define MAX_MASK_NAME_LENGTH 40
-static int yaffs_proc_write(struct file *file, const char *buf,
+static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
                                         unsigned long count, void *data)
 {
        unsigned rg = 0, mask_bitfield;
@@ -2502,6 +2533,13 @@ static int yaffs_proc_write(struct file *file, const char *buf,
        return count;
 }
 
+
+static int yaffs_proc_write(struct file *file, const char *buf,
+                                        unsigned long count, void *data)
+{
+        return yaffs_proc_write_trace_options(file, buf, count, data);
+}
+
 /* Stuff to handle installation of file systems */
 struct file_system_to_install {
        struct file_system_type *fst;
index ebcae97..fda5f8b 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 const char *yaffs_guts_c_version =
-    "$Id: yaffs_guts.c,v 1.92 2009-11-03 02:41:00 charles Exp $";
+    "$Id: yaffs_guts.c,v 1.93 2009-11-07 02:06:58 charles Exp $";
 
 #include "yportenv.h"
 
@@ -113,7 +113,6 @@ static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
                                        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(yaffs_Device *dev)
 
 }
 
+/*
+ * 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 *dev)
                                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 *dev)
        yaffs_VerifyFreeChunks(dev);
        yaffs_VerifyBlocks(dev);
 
-
        /* Clean up any aborted checkpoint data */
        if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
                yaffs_InvalidateCheckpoint(dev);
index 3385bd4..f47c65e 100644 (file)
@@ -405,6 +405,8 @@ typedef union {
        yaffs_HardLinkStructure hardLinkVariant;
 } yaffs_ObjectVariant;
 
+
+
 struct yaffs_ObjectStruct {
        __u8 deleted:1;         /* This should only apply to unlinked files. */
        __u8 softDeleted:1;     /* it has also been soft deleted */
@@ -532,6 +534,7 @@ typedef struct {
 
 /*----------------- Device ---------------------------------*/
 
+
 struct yaffs_DeviceStruct {
        struct ylist_head devList;
        const char *name;
@@ -768,7 +771,9 @@ struct yaffs_DeviceStruct {
        /* yaffs2 runtime stuff */
        unsigned sequenceNumber;        /* Sequence number of currently allocating block */
        unsigned oldestDirtySequence;
-
+       
+       /* Auto empty lost and found directory on mount */
+       int emptyLostAndFound;
 };
 
 typedef struct yaffs_DeviceStruct yaffs_Device;