Change the object type if it turns out to be wrong during a scan
authorCharles Manning <cdhmanning@gmail.com>
Tue, 21 Jan 2014 23:14:26 +0000 (12:14 +1300)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 21 Jan 2014 23:14:26 +0000 (12:14 +1300)
This might result in some files ending up in lost but at least we
can get the file system to mount.

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
yaffs_guts.c
yaffs_guts.h
yaffs_yaffs2.c

index 1fd464d68af798c5fcdd02c537c7804bcbd05a5f..d3e877fe3d1275e0c072e649ae1da1227376f9f6 100644 (file)
@@ -3950,6 +3950,70 @@ int yaffs_del_obj(struct yaffs_obj *obj)
        return ret_val;
 }
 
+
+static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
+                                  struct yaffs_obj *to_dir)
+{
+       struct yaffs_obj *obj;
+       struct list_head *lh;
+       struct list_head *n;
+
+       list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
+               obj = list_entry(lh, struct yaffs_obj, siblings);
+               yaffs_add_obj_to_dir(to_dir, obj);
+       }
+}
+
+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
+                                  enum yaffs_obj_type type)
+{
+       /* Tear down the old variant */
+       switch (obj->variant_type) {
+       case YAFFS_OBJECT_TYPE_FILE:
+               /* Nuke file data */
+               yaffs_resize_file(obj, 0);
+               yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+               obj->variant.file_variant.top = NULL;
+               break;
+       case YAFFS_OBJECT_TYPE_DIRECTORY:
+               /* Put the children in lost and found. */
+               yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
+               if (!list_empty(&obj->variant.dir_variant.dirty))
+                       list_del_init(&obj->variant.dir_variant.dirty);
+               break;
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+               /* Nuke symplink data */
+               kfree(obj->variant.symlink_variant.alias);
+               obj->variant.symlink_variant.alias = NULL;
+               break;
+       case YAFFS_OBJECT_TYPE_HARDLINK:
+               list_del_init(&obj->hard_links);
+               break;
+       default:
+               break;
+       }
+
+       memset(&obj->variant, 0, sizeof(obj->variant));
+
+       /*Set up new variant if the memset is not enough. */
+       switch (type) {
+       case YAFFS_OBJECT_TYPE_DIRECTORY:
+               INIT_LIST_HEAD(&obj->variant.dir_variant.children);
+               INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
+               break;
+       case YAFFS_OBJECT_TYPE_FILE:
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+       case YAFFS_OBJECT_TYPE_HARDLINK:
+       default:
+               break;
+       }
+
+       obj->variant_type = type;
+
+       return obj;
+
+}
+
 static int yaffs_unlink_worker(struct yaffs_obj *obj)
 {
        int del_now = 0;
index 05785367cb2e30a00daba4f928165d14ddaf0c33..d89f8b00de956c4c6c1881e2a48d42d2325841ff 100644 (file)
@@ -776,6 +776,7 @@ struct yaffs_dev {
        u32 n_page_writes;
        u32 n_page_reads;
        u32 n_erasures;
+       u32 n_bad_queries;
        u32 n_bad_markings;
        u32 n_erase_failures;
        u32 n_gc_copies;
@@ -854,6 +855,9 @@ int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
 
 int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
 int yaffs_del_obj(struct yaffs_obj *obj);
+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
+                                  enum yaffs_obj_type type);
+
 
 int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
 loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
index f1dc972276f78091b14a45e4ecfd54d1c406a5b1..8c31a661ff1d756778b25931233efa575f838b28 100644 (file)
@@ -1193,12 +1193,14 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
                }
 
                if (!in->valid && in->variant_type !=
-                   (oh ? oh->type : tags.extra_obj_type))
+                   (oh ? oh->type : tags.extra_obj_type)) {
                        yaffs_trace(YAFFS_TRACE_ERROR,
-                               "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan",
+                               "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
                                oh ? oh->type : tags.extra_obj_type,
                                in->variant_type, tags.obj_id,
                                chunk);
+                       in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
+               }
 
                if (!in->valid &&
                    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
@@ -1439,7 +1441,7 @@ int yaffs2_scan_backwards(struct yaffs_dev *dev)
                bi++;
        }
 
-       yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan);
+       yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
 
        cond_resched();