summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorCharles Manning <cdhmanning@gmail.com>2009-11-05 13:15:21 +1300
committerArve Hjønnevåg <arve@android.com>2010-02-08 15:09:11 -0800
commit75e82381df19bcb8bf6681f3fe1a2a8360e6cddc (patch)
tree8e68a842012511e7786414d6473b88f48a6ee5cc /fs
parent8ff4860c2778c0be92a63808036de337d13fa864 (diff)
Add handling for unrooted files
Unrooted files should only happen due to a now fixed bug that would rmdir non-empty directories. Unrooted files are now re-rooted in lost_found. This also introduces a mechanism to empty out lost and found at mount, thus recaliming this space. This option may be controlled via a compile flag and overridden with a mount option. Signed-off-by: Charles Manning <cdhmanning@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/yaffs2/Kconfig8
-rw-r--r--fs/yaffs2/yaffs_fs.c18
-rw-r--r--fs/yaffs2/yaffs_guts.c123
-rw-r--r--fs/yaffs2/yaffs_guts.h2
4 files changed, 150 insertions, 1 deletions
diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
index c0e545b647b1..85844504057c 100644
--- a/fs/yaffs2/Kconfig
+++ b/fs/yaffs2/Kconfig
@@ -154,3 +154,11 @@ 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 mount"
+ 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/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
index 47cae6f4f92c..45aa158b18d3 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -1796,6 +1796,8 @@ typedef struct {
int skip_checkpoint_read;
int skip_checkpoint_write;
int no_cache;
+ int empty_lost_and_found_overridden;
+ int empty_lost_and_found;
} yaffs_options;
#define MAX_OPT_LEN 20
@@ -1811,6 +1813,9 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str)
memset(cur_opt, 0, MAX_OPT_LEN + 1);
p = 0;
+ while (*options_str == ',')
+ options_str++;
+
while (*options_str && *options_str != ',') {
if (p < MAX_OPT_LEN) {
cur_opt[p] = *options_str;
@@ -1830,6 +1835,12 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str)
else if (!strcmp(cur_opt, "no-checkpoint")) {
options->skip_checkpoint_read = 1;
options->skip_checkpoint_write = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-disable")) {
+ options->empty_lost_and_found = 0;
+ options->empty_lost_and_found_overridden = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-enable")) {
+ options->empty_lost_and_found = 1;
+ options->empty_lost_and_found_overridden = 1;
} else {
printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
cur_opt);
@@ -1935,6 +1946,13 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
#endif
+
+#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;
+
#ifdef CONFIG_YAFFS_AUTO_YAFFS2
if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
index 05ff48d1bc46..a565b08e6116 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -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,
@@ -5450,6 +5449,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;
@@ -7413,6 +7531,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) {
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
index a3b110291d38..acc2ae71c856 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -557,6 +557,8 @@ struct yaffs_DeviceStruct {
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
+ int emptyLostAndFound; /* Flasg to determine if lst+found should be emptied on init */
+
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
void *genericDevice; /* Pointer to device context