了解一个文件系统,除了了解运行机制(RAM结构)外,还需了解文件系统怎样物理存储的。RAM数据结构是为文件系统更好运行,而物理存储是文件系统载体。文件系统出问题后,最终要从物理存储寻找数据。
参考“How Yaffs Works”,文件数据都以顺序日志形式写到flash中,日志的每个entry都是一个chunk大小,所存的数据类型有两种:
>>Data chunk: A chunk holding regular data file contents.
>>Object Header: A descriptor for an object(directory, regular data file, hard link, soft link, special descriptor, …). This holds details such as the identifier for the parent directory, object name, etc.
每个chunk都含有tags(默认存储在oob中),yaffs1的tags和yaffs2 tags不同,下以yaffs2为例进行说明。
即yaffs数据都以chunk(one page)为单位存储,每个chunk包含数据和标签(tags),chunk数据为文件系统实际数据;tags为yaffs文件系统需要,根据chunk数据属性而得。Chunk数据分为两类:一类为Data chunk,存储普通文件的内容(直接一字节一字节拷贝到flash,页未满时补0xFF,实为memset 0xFF而得),yaffs未分配具体数据结构(直接拷贝内容即可);另一类为所有文件(目录、普通文件、硬连接、软连接、字符设备、块设备、FIFO、Socket)的头,存储相关文件属性,yaffs提供struct yaffs_obj_hdr数据结构,该数据结构直接存储到一个chunk(一页page)上。根据utils/mkyaffs2image.c可知上述描述的详细过程。
根据上面描述,实际存储到flash上的数据结构有两种:struct yaffs_obj_hdr和struct yaffs_packed_tags2。(若包含其他特性,checkpoint、inband tags、Block summaries、extended tags,即flash存储其他信息提高flash性能,则flash上存储的数据结构更多。)utils/mkyaffs2image.c通过扫描整个yaffs文件系统,根据文件提取struct yaffs_obj_hdr和struct yaffs_packed_tags2,直接写到yaffs镜像中。
sizeof(struct yaffs_packed_tags2) = 28;
sizeof(struct yaffs_obj_hdr) = 512;
//yaffs_packedtags2.h
struct yaffs_packed_tags2_tags_only {
unsigned seq_number; //块序列号,每写一次加1,初始0x10000
unsigned obj_id; //对象id,每个对象唯一,初始0x101
unsigned chunk_id; //0,对象头;>0,该chunk在文件中位置
unsigned n_bytes; //chunk数据字节数,若为对象头则为0xFFFF
};
struct yaffs_packed_tags2 {
struct yaffs_packed_tags2_tags_only t;
struct yaffs_ecc_other ecc; //tags ECC校验,非chunk数据
};
//yaffs_ecc.h
struct yaffs_ecc_other {
unsigned char col_parity;
unsigned line_parity;
unsigned line_parity_prime;
};
//yaffs_guts.h
enum yaffs_obj_type {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
};
struct yaffs_obj_hdr {
u32 type; /* enum yaffs_obj_type */
/* Apply to everything */
u32 parent_obj_id;
u16 sum_no_longer_used; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
/* The following apply to all object types except for hard links */
u32 yst_mode; /* protection */
u32 yst_uid;
u32 yst_gid;
u32 yst_atime;
u32 yst_mtime;
u32 yst_ctime;
/* File size applies to files only */
u32 file_size_low;
/* Equivalent object id applies to hard links only. */
int equiv_id;
/* Alias is for symlinks only. */
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
u32 yst_rdev; /* stuff for block and char devices (major/min) */
u32 win_ctime[2];
u32 win_atime[2];
u32 win_mtime[2];
u32 inband_shadowed_obj_id;
u32 inband_is_shrink;
u32 file_size_high;
u32 reserved[1];
int shadows_obj; /* This object header shadows the
specified object if > 0 */
/* is_shrink applies to object headers written when wemake a hole. */
u32 is_shrink;
};
附注yaffs2镜像首页内容:
~$hexdump -C wang_yaffs2 | more
00000000 03 00 00 00 01 00 00 00 ff ff 74 6d 70 00 00 00 |..........tmp...|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000100 00 00 00 00 00 00 00 00 00 00 ff ff ed 41 00 00 |.............A..|
00000110 00 00 00 00 00 00 00 00 29 c4 e8 57 32 68 fa 56 |........)..W2h.V|
00000120 41 bb e4 57 ff ff ff ff ff ff ff ff ff ff ff ff |A..W............|
00000130 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
000001c0 ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 |................|
000001d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00000800 ff ff 00 10 00 00 01 01 00 00 00 00 00 00 ff ff |................|
00000810 00 00 25 00 00 00 00 00 00 00 ff ff ff ff ff ff |..%.............|
00000820 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00000840 03 00 00 00 01 00 00 00 ff ff 73 62 69 6e 00 00 |..........sbin..|
说明:上图表示的红色部分为yaffs2 tags数据,前面两个字符用作坏块标记(后面具体说明)。该镜像文件有默认源码mkyaffs2image基础上oob部分头两字节空置为0xFF所得。实际测试nandflash烧写该镜像后,文件系统仅启动一部分,之后停止不再显示信息。
后注:程序停止的原因为mkyaffs2image.c(即制作镜像工具)问题,其在打包镜像时,对于普通文件大小设置错误。在文件头中设置文件大小有file_size_low和file_size_high两部分组成(对普通文件有效),而对于普通文件,c中都通过stat.st_size>>32设置,而stat.st_size本身为32位,右移32位实际值仍为原值,导致文件设置大小过大。导致运行第一个文件时即停止不再运行。