YAFFS2 的 `yaffs_obj` 数据结构详解
YAFFS2 的 yaffs_obj
数据结构详解
yaffs_obj
是 YAFFS2 文件系统中用于表示 文件系统对象(如文件、目录、符号链接等)的核心数据结构,负责管理对象的元数据、数据存储位置及与其他对象的关系。以下是其关键成员及功能的详细解析:
1. 基础信息
成员名 | 类型 | 说明 |
---|---|---|
obj_id | u32 | 对象唯一标识符,用于在哈希表中快速查找。 |
variant_type | yaffs_obj_type | 对象类型,取值包括 YAFFS_OBJECT_TYPE_FILE (文件)、YAFFS_OBJECT_TYPE_DIRECTORY (目录)、YAFFS_OBJECT_TYPE_SYMLINK (符号链接)、YAFFS_OBJECT_TYPE_HARDLINK (硬链接)等。 |
parent | struct yaffs_obj * | 父目录对象指针,用于构建目录树结构。 |
name | char * | 对象名称(如文件名或目录名),动态分配内存。 |
yst_mode | mode_t | 文件模式,包含权限位(如 S_IFREG 表示普通文件)。 |
yst_uid /yst_gid | uid_t /gid_t | 用户/组标识符,用于权限管理。 |
yst_atime /yst_mtime /yst_ctime | time_t | 访问/修改/创建时间戳。 |
2. 数据存储管理
成员名 | 类型 | 说明 |
---|---|---|
variant | union | 联合体,根据对象类型存储特定数据: |
- .file_variant | struct | 文件对象数据:包含文件大小、数据块链表等。 |
- .directory_variant | struct | 目录对象数据:包含子对象哈希表、目录项链表等。 |
- .symlink_variant | struct | 符号链接数据:存储目标路径字符串。 |
- .hardlink_variant | struct | 硬链接数据:指向原始文件的 yaffs_obj 指针。 |
hdr_chunk | int | 对象头存储的 NAND 页号,记录元数据(如文件大小、权限等)。 |
serial | u32 | 序列号,用于版本控制(如检查点恢复时验证对象一致性)。 |
3. 文件对象扩展(file_variant
)
当 variant_type
为 YAFFS_OBJECT_TYPE_FILE
时,variant.file_variant
包含以下关键字段:
struct {u32 file_size; // 文件大小(字节)u32 stored_size; // 实际存储大小(可能因压缩或对齐不同)struct yaffs_tnode *top; // 数据块树根节点,管理文件数据块u32 force_rewrite; // 强制重写标志(用于处理部分写入失败)
} file_variant;
- 数据块树:
YAFFS2 使用 Tnode树(一种平衡树结构)管理文件数据块的物理位置(NAND 页号),支持高效随机访问。
4. 目录对象扩展(directory_variant
)
当 variant_type
为 YAFFS_OBJECT_TYPE_DIRECTORY
时,variant.directory_variant
包含:
struct {struct list_head children; // 子对象链表(文件、子目录等)struct yaffs_dir *dirty; // 脏目录项链表(需同步到NAND)
} directory_variant;
- 目录项管理:
每个目录项(yaffs_dir_entry
)记录子对象的名称、对象ID和类型,通过哈希表加速查找。
5. 符号链接与硬链接
- 符号链接(
symlink_variant
):struct {char *alias; // 目标路径字符串(如 "/usr/bin") } symlink_variant;
- 硬链接(
hardlink_variant
):struct {struct yaffs_obj *equiv_obj; // 指向原始文件对象的指针u32 equiv_id; // 原始文件的对象ID } hardlink_variant;
6. 对象状态与缓存
成员名 | 类型 | 说明 |
---|---|---|
dirty | int | 脏标志,表示对象元数据或数据需要同步到NAND。 |
lazy_loaded | int | 延迟加载标志,表示对象数据尚未完全加载到内存。 |
shadowed_obj | struct yaffs_obj * | 影子对象指针,用于处理文件覆盖或重命名时的旧版本对象。 |
my_dev | struct yaffs_dev * | 所属设备指针,指向管理该对象的 yaffs_dev 结构。 |
7. 对象生命周期管理
- 创建对象:
通过yaffs_create_obj()
创建新对象,初始化基础字段并分配内存。 - 删除对象:
调用yaffs_del_obj()
释放资源,若为文件则释放数据块,若为目录则递归删除子对象。 - 哈希表管理:
对象通过obj_id
哈希到yaffs_dev.obj_bucket
中,加速查找:// 示例:查找对象 struct yaffs_obj *obj = yaffs_find_by_number(dev, obj_id);
典型应用场景
-
文件读写:
- 写入文件时,通过
file_variant.top
树分配数据块并更新file_size
。 - 读取文件时,根据偏移量查找对应的数据块页号,从NAND读取数据。
- 写入文件时,通过
-
目录遍历:
- 遍历
directory_variant.children
链表,获取目录下所有子对象。 - 添加/删除目录项时,更新链表和哈希表。
- 遍历
-
垃圾回收:
- 检查对象的
hdr_chunk
和variant.file_variant.top
,统计有效数据块。 - 若对象已删除(
yst_mode
无S_IFxxx
标志),回收其数据块。
- 检查对象的
-
检查点恢复:
- 从NAND读取对象头(
hdr_chunk
指向的页),重建yaffs_obj
结构。 - 通过
serial
验证对象一致性。
- 从NAND读取对象头(
调试与问题排查
- 对象泄漏:
检查yaffs_dev.obj_bucket
哈希表,确认未引用的对象是否被正确释放。 - 元数据损坏:
通过yaffs_check_obj()
验证对象字段的合法性(如parent
是否指向有效目录)。 - 性能分析:
监控yaffs_obj
的创建/删除频率,优化内存管理策略。
示例代码:遍历目录对象
void list_directory(struct yaffs_obj *dir) {struct list_head *entry;struct yaffs_dir_entry *de;if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) return;list_for_each(entry, &dir->variant.directory_variant.children) {de = list_entry(entry, struct yaffs_dir_entry, siblings);printf("Name: %s, ID: %u\n", de->name, de->obj_id);}
}
总结
yaffs_obj
是 YAFFS2 文件系统管理文件、目录等对象的 核心元数据结构,其设计充分考虑了嵌入式环境下的 内存效率 和 NAND特性。通过理解其成员变量及操作逻辑,开发者可以更高效地调试文件系统问题、优化存储性能,并实现定制化功能扩展。