From: charles Date: Sat, 7 Nov 2009 02:06:58 +0000 (+0000) Subject: Add fix for hanging objects X-Git-Tag: pre-name-change~176 X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=commitdiff_plain;h=47f0aa3a5008048dd068bbc7fef87650d5df12fb Add fix for hanging objects --- diff --git a/Kconfig b/Kconfig index 1d3bb71..4a8b0c8 100644 --- 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. + diff --git a/moduleconfig.h b/moduleconfig.h index 99c9f6a..6468907 100644 --- a/moduleconfig.h +++ b/moduleconfig.h @@ -42,6 +42,12 @@ /* 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 diff --git a/yaffs_fs.c b/yaffs_fs.c index 93236e4..72f4b62 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -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 @@ -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; diff --git a/yaffs_guts.c b/yaffs_guts.c index ebcae97..fda5f8b 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -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); diff --git a/yaffs_guts.h b/yaffs_guts.h index 3385bd4..f47c65e 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -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;