[Yaffs] Backward scan failure and variant_type

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Bob Dunlop
Date:  
To: yaffs
Subject: [Yaffs] Backward scan failure and variant_type
Hi,

I've been chasing a problem with mounting a corrupted (by power loss) YAFFS2
filesystem. The mount would fail during the initial backward scan and as a
result the system wouldn't boot.


Traced it to a piece of code circa line 1226 of yaffs_yaffs2.c (hopefully
enough context here for people to find it.)


                        } else {
/*HERE --> */                   in->variant_type = tags.extra_obj_type;
                                parent = yaffs_find_or_create_by_number(dev,
                                                tags.extra_parent_id,
                                                YAFFS_OBJECT_TYPE_DIRECTORY);
                                file_size = tags.extra_length;
                                is_shrink = tags.extra_is_shrink;
                                equiv_id = tags.extra_equiv_id;
                                in->lazy_loaded = 1;
                        }
                        in->dirty = 0;


                        if (!parent)
                                alloc_failed = 1;


                        /* directory stuff...
                         * hook up to parent
                         */



Anyway this assignment changes the object type but does not make any changes
or checks of the variant union within the object.

In our case changing a directory to a plain file caused the linked list headers
in the variant.dir_variant part of the union to become corrupt values in
variant.file_variant.top_level. This in turn caused the next call to
yaffs_put_chunk_in_file() on this object to fail and the entire backwards
scan to be abandoned with a fatal error.

One solution I've tried, and it works as far as getting to a login prompt, is
to refuse the make the change if it would change a directory into something
else.


diff --git a/yaffs_yaffs2.c b/yaffs_yaffs2.c
index 961f01e..46162de 100644
--- a/yaffs_yaffs2.c
+++ b/yaffs_yaffs2.c
@@ -1224,7 +1224,14 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
                 is_shrink = oh->is_shrink;
                 equiv_id = oh->equiv_id;
             } else {
-                in->variant_type = tags.extra_obj_type;
+                if ( in->variant_type != tags.extra_obj_type ) {
+                    if ( in->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY )
+                        yaffs_trace(YAFFS_TRACE_ERROR,
+                            "Cowardly refusing to convert directory for object %d",
+                            tags.obj_id);
+                    else
+                            in->variant_type = tags.extra_obj_type;
+                }
                 parent = yaffs_find_or_create_by_number(dev,
                         tags.extra_parent_id,
                         YAFFS_OBJECT_TYPE_DIRECTORY);



An alternate that also works is to make the conversion and fixup the object's
variant.file_variant structure at the same time. This was my preferred option
until I started to think about what I should do if the directory had any
children, orphan the children moving them to lost+found ?

I think this points to a more general problem.  Any changes to an object's
variant_type should really require a check and potential fixup of the
corresponding variant union.  What does the team think ?
-- 
        Bob Dunlop