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