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
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;
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);
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) {
yaffs_FileStructure *fStruct,
__u32 chunkId);
-
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
}
+/*
+ * 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;
init_failed = 1;
yaffs_StripDeletedObjects(dev);
+ yaffs_FixHangingObjects(dev);
+ if(dev->emptyLostAndFound)
+ yaffs_EmptyLostAndFound(dev);
}
if (init_failed) {