logo资料库

jffs2源代码情景分析(beta2).pdf

第1页 / 共150页
第2页 / 共150页
第3页 / 共150页
第4页 / 共150页
第5页 / 共150页
第6页 / 共150页
第7页 / 共150页
第8页 / 共150页
资料共150页,剩余部分请下载后查看
前言(new)
第1章 jffs2的数据实体及其内核描述符(improved)
数据实体的内核描述符jffs2_raw_node_ref
文件的内核描述符jffs2_inode_cache
jffs2_raw_dirent数据实体及其上层数据结构
jffs2_raw_inode数据实体及其上层数据结构
第2章 描述jffs2特性的数据结构(improved)
文件系统超级块的u域:jffs2_sb_info数据结构
文件索引结点的u域:jffs2_inode_info数据结构
打开正规文件后相关数据结构之间的引用关系
第3章 注册文件系统
init_jffs2_fs函数
register_filesystem函数
第4章 挂载文件系统(improved)
jffs2_read_super函数
jffs2_do_fill_super函数
jffs2_do_mount_fs函数
jffs2_build_filesystem函数
jffs2_scan_medium函数
jffs2_scan_eraseblock函数
jffs2_scan_inode_node函数
jffs2_scan_make_ino_cache函数
jffs2_scan_dirent_node函数
full_name_hash函数
jffs2_add_fd_to_list函数
jffs2_build_inode_pass1函数
第5章 打开文件时建立inode的方法
iget和iget4函数
get_new_inode函数
jffs2_read_inode函数
jffs2_do_read_inode函数(improved)
jffs2_get_inode_nodes函数
第6章 jffs2中写正规文件的方法
sys_write函数
generic_file_write函数
jffs2_prepare_write函数
jffs2_commit_write函数
jffs2_write_inode_range函数
jffs2_write_dnode函数
第7章 jffs2中读正规文件的方法
jffs2_readpage函数
jffs2_do_readpage_nolock函数
jffs2_read_inode_range函数
jffs2_read_dnode函数
第8章 jffs2中符号链接文件的方法表(new)
jffs2_follow_link函数
jffs2_getlink函数
第9章 jffs2中目录文件的方法表(new)
jffs2_create函数
jffs2_new_inode函数
jffs2_do_create函数
jffs2_do_new_inode函数
第10章 jffs2的Garbage Collection
jffs2_start_garbage_collect_thread函数
jffs2_garbage_collect_thread函数
jffs2_garbage_collect_pass函数
jffs2_erase_pending_trigger函数
第11章 讨论和体会
什么是日志文件系统,为什么要使用jffs2
为什么需要红黑树
何时、如何判断数据实体是过时的
后记
附录 用jffs2map2模块导出文件的数据实体(new)
观察根目录文件的数据实体
观察符号链接的信息
A symbolic link, the linked file is mnt/ramfs/tmp
观察正规文件创建后的数据实体
观察jffs2_raw_inode数据实体的大小上限
目录 声明 你可以自由地随意修改本文档的任何文字内容及图表,但是如果你在自己的文档中以任何形式直接引用了 本文档的任何原有文字或图表并希望发布你的文档,那么你也得保证让所有得到你的文档的人同时享有你 曾经享有过的权利。 JFFS2 源代码情景分析(Beta2) 作者在www.linuxforum.net上的ID为shrek2 欢迎补充,欢迎批评指正! 前言(new) ................................................................................................................................................ 4 第 1 章 jffs2 的数据实体及其内核描述符(improved) ................................ 5 数据实体的内核描述符jffs2_raw_node_ref.................................................................................................... 6 文件的内核描述符jffs2_inode_cache .............................................................................................................. 6 jffs2_raw_dirent数据实体及其上层数据结构................................................................................................. 7 jffs2_raw_inode数据实体及其上层数据结构 ............................................................................................... 10 第 2 章 描述jffs2 特性的数据结构(improved) ................................................ 14 文件系统超级块的u域:jffs2_sb_info数据结构 .......................................................................................... 14 文件索引结点的u域:jffs2_inode_info数据结构......................................................................................... 18 打开正规文件后相关数据结构之间的引用关系.......................................................................................... 19 第 3 章 注册文件系统 ..................................................................................................................... 21 init_jffs2_fs函数.............................................................................................................................................. 21 register_filesystem函数................................................................................................................................... 23 第 4 章 挂载文件系统(improved) ................................................................................ 25 jffs2_read_super函数 ...................................................................................................................................... 25 jffs2_do_fill_super函数................................................................................................................................... 27 jffs2_do_mount_fs函数................................................................................................................................... 30 jffs2_build_filesystem函数 ............................................................................................................................. 31 jffs2_scan_medium函数.................................................................................................................................. 34 jffs2_scan_eraseblock函数.............................................................................................................................. 40 jffs2_scan_inode_node函数 ............................................................................................................................ 52 1
目录 jffs2_scan_make_ino_cache函数 .................................................................................................................... 55 jffs2_scan_dirent_node函数............................................................................................................................ 56 full_name_hash函数........................................................................................................................................ 59 jffs2_add_fd_to_list函数................................................................................................................................. 60 jffs2_build_inode_pass1 函数 ......................................................................................................................... 61 第 5 章 打开文件时建立inode的方法 .............................................................................. 63 iget和iget4 函数 .............................................................................................................................................. 63 get_new_inode函数......................................................................................................................................... 65 jffs2_read_inode函数 ...................................................................................................................................... 68 jffs2_do_read_inode函数(improved) ......................................................................................................... 73 jffs2_get_inode_nodes函数............................................................................................................................. 78 第 6 章 jffs2 中写正规文件的方法 ..................................................................................... 88 sys_write函数.................................................................................................................................................. 89 generic_file_write函数.................................................................................................................................... 90 jffs2_prepare_write函数.................................................................................................................................. 98 jffs2_commit_write函数................................................................................................................................ 102 jffs2_write_inode_range函数 ........................................................................................................................ 104 jffs2_write_dnode函数.................................................................................................................................. 107 第 7 章 jffs2 中读正规文件的方法 ....................................................................................111 jffs2_readpage函数.........................................................................................................................................111 jffs2_do_readpage_nolock函数......................................................................................................................111 jffs2_read_inode_range函数 ......................................................................................................................... 112 jffs2_read_dnode函数 ................................................................................................................................... 115 第 8 章 jffs2 中符号链接文件的方法表(new) ................................................. 120 jffs2_follow_link函数 ................................................................................................................................... 120 jffs2_getlink函数........................................................................................................................................... 121 第 9 章 jffs2 中目录文件的方法表(new) ............................................................. 122 jffs2_create函数 ............................................................................................................................................ 122 jffs2_new_inode函数 .................................................................................................................................... 124 jffs2_do_create函数 ...................................................................................................................................... 126 jffs2_do_new_inode函数............................................................................................................................... 129 第 10 章 jffs2 的Garbage Collection ................................................................................. 131 jffs2_start_garbage_collect_thread函数........................................................................................................ 131 jffs2_garbage_collect_thread函数................................................................................................................. 132 jffs2_garbage_collect_pass函数.................................................................................................................... 135 jffs2_erase_pending_trigger函数 .................................................................................................................. 141 第 11 章 讨论和体会......................................................................................................................... 142 2
目录 什么是日志文件系统,为什么要使用jffs2 ................................................................................................ 142 为什么需要红黑树 ....................................................................................................................................... 142 何时、如何判断数据实体是过时的 ........................................................................................................... 143 后记................................................................................................................................................................... 144 附录 用jffs2map2 模块导出文件的数据实体(new)..................................... 145 观察根目录文件的数据实体 ....................................................................................................................... 145 观察符号链接的信息 ................................................................................................................................... 147 观察正规文件创建后的数据实体 ............................................................................................................... 147 观察jffs2_raw_inode数据实体的大小上限 ................................................................................................. 148 3
前言 前言(new) 第 1 稿后拜读了情景分析中文件系统的相关章节,将 ext2 与 jffs2 相类比,显著地加深了对上层文件系统 相关概念的理解,尤其是 VFS 框架的数据结构的设计思想,比如为了实现良好的可移植性和重用性,上层 VFS 框架代码就必须与具体的应用(底层具体文件系统)无关,而这一点恰恰是通过设计中间层的函数指 针接口实现的。依靠接口实现的封装性是可移植性的基础。还有 VFS 各数据结构的设计目的和设计方法等 等,比如只有尽可能地概括各种不同文件系统的共性才能使 VFS 具有良好的通用性,同时通过各种数据结 构中的 union,让具体文件系统的实现来定义、解释、使用其特有数据结构、描述在具体设备上具体文件 系统的数据组织格式。“union 域反映了各种不同文件系统在上层数据结构上的差异”。 第 2 稿对第 1 稿的改进也主要集中在对 jffs2 相关数据结构的理解和 ext2 与 jffs2 的类比上,这样可以加深 对 jffs2 数据结构的理解。对于已经看过第 1 稿的朋友,再翻翻第 1、2 章就差不多了。另外有兴趣的话也 可以再看看其它新增的章节。 第 1 稿中只涉及了正规文件的访问方法,第 2 稿中补充了符号链接文件和目录文件的相关方法。这些补充 可以验证、加深对各种类型文件在 jffs2 中的实现方法的理解,比如可以通过目录文件的 create 方法看到在 创建正规文件时是如何设置 inode 的 u 域、向父目录文件增加 jffs2_raw_dirent 目录项的(具体操作不止这 些)。由于我目前的兴趣主要集中在内核中那些与具体应用无关的上层框架上面,而不是与具体应用相关 的最底层代码,所以第 1 稿中有关 jffs2 某些实现细节的遗留问题暂时还没有继续研究下去,请大家谅解。 感谢论坛上所有鼓励支持我、尤其是那些向我提出问题的朋友,你们的提问促使我研究得更深入一些。完 成第 1 稿后我就曾打算通过继续阅读 mkfs.jffs2 的源代码、或者编写一个能导出指定的 jffs2 文件系统上所 有数据结点的模块来加深对 jffs2 的理解。在和网友们讨论 jffs2 对 jffs2_raw_inode 数据结点的最大长度限 制时我完成了这个模块,目前它可以导出指定 jffs2 文件系统上指定文件的所有数据结点的信息,这样每次 从根目录开始就可以逐层得到文件系统目录树中任何一个文件的数据结点信息了。 人们对 Linux 的喜爱很大程度上源自于它的可实践性,从而极大地调动研究和使用的积极性。通过这个可 以导出一个文件在 flash 上的物理实体的模块,jffs2 的概念前所未有地清晰、真实,也进一步改正、完善 了对目录文件和 jffs2_raw_dirent 的理解,有兴趣的朋友可以参见附录及附件源代码,或者进一步改进这个 模块。(在第 1 稿中曾错误地认为目录文件是没有 jffs2_raw_inode 数据实体的,很抱歉,而实际情况是除 了根目录外所有目录都由惟一的、用于描述其类型和其它管理信息的 jffs2_raw_inode,与此相关的 jffs2_full_dnode 则由 jffs2_inode_info 的 metadata 域直接指向。) Let’s DIY Linux! 2006 年 1 月 18 日星期三 4
第 1 章 jffs2 的数据实体及其内核描述符 第 1 章 jffs2 的数据实体及其内核描述符(improved) 存储于辅存的任何文件都至少包含三种类型的信息:文件的数据本身、描述文件属性的管理信息、以及描 述文件在文件系统内部的位置信息。文件的位置信息用于实现“从路径名找到文件”的机制。jffs2 在 flash 上只有两种类型的数据实体:jffs2_raw_inode 和 jffs2_raw_dirent,前者包含文件的管理信息,类似于 ext2 中的磁盘索引结点 ext2_inode,后者用于描述文件在文件系统中的位置,类似于 ext2 中的 ext2_dir_entry_2 目录项实体。 与 ext2_inode 可以定位磁盘文件的磁盘块相比,jffs2_raw_inode 没有这种“索引”功能,flash 上文件的数 据是由若干离散的 jffs2_raw_inode 数据结点进行描述的。与 ext2_dir_entry_2 类似,jffs2_raw_dirent 也描述 了文件名及其索引结点编号之间的映射关系,是文件硬链接的物理实体。 在 ext2 中目录文件所占的磁盘块由其 ext2_inode 进行索引,在一个磁盘块内部为描述其下子目录、子文件 的 ext2_dir_entry_2 实体。由于 ext2_dir_entry_2 可指明自身的长度,而且它们在磁盘块内部是连续存放的, 所以并不需要描述其所在目录文件的索引结点号。而 jffs2 中目录文件由一个 jffs2_raw_inode 数据实体和若 干 jffs2_raw_dirent 数据实体组成,由于目录文件的数据实体之间都是离散存放的,所以每个 jffs2_raw_dirent 中还得描述其所属目录文件的索引结点号,参见下文。 正规文件、符号链接文件、SOCKET/FIFO 文件、设备文件都由一个或多个 jffs2_raw_inode 来表示,而紧 随 jffs2_raw_inode 数据结构后的为相关数据块,不同文件所需要的 jffs2_raw_inode 个数及其后数据的内容 如下表所示: 文件类型 目录文件 1 正规文件 符号链接文件 SOCKET/FIFO 文件 设备文件 所需 jffs2_raw_inode 结点的个数 后继数据的内容 (根目录除外) >= 1 1 1 1 无 文件的数据 被链接的文件名 无 设备号 另外,所有文件都至少存在一个 jffs2_raw_dirent 数据实体(具体个数由其硬链接个数决定),它们组成其 父目录文件的内容。区分 jffs2_raw_dirent 和 jffs2_raw_inode 是为了实现硬链接:在 jffs 版本 1 中就只有类 似 jffs2_raw_inode 的一种数据实体,只能实现符号链接。(注:根目录没有父目录了,自然不需要 jffs2_raw_dirent。另外它也没有那个惟一的 jffs2_raw_inode。) jffs2_raw_dirent 和 jffs2_raw_inode 数据实体都以相同的“头”开始: struct jffs2_unknown_node { /* All start like this */ jint16_t magic; jint16_t nodetype; 5
第 1 章 jffs2 的数据实体及其内核描述符 jint32_t totlen; /* So we can skip over nodes we don't grok */ jint32_t hdr_crc; } __attribute__((packed)); 其中 nodetype 指明数据结点的具体类型 JFFS_NODETYPE_DIRENT 或者 JFFS2_NODETYPE_INODE; totlen 为包括后继数据的整个数据实体的总长度;hdr_crc 为头部中其它域的 CRC 校验值。另外整个数据结 构在内存中以“紧凑”方式进行存储,这样当从 flash 上复制数据实体的头部到该数据结构后,其各个域 就能够“各得其所”了。 数据实体的内核描述符jffs2_raw_node_ref struct jffs2_raw_node_ref *next_in_ino; struct jffs2_raw_node_ref *next_phys; uint32_t flash_offset; uint32_t totlen; flash 上每个数据实体的位置、长度都由 jffs2_raw_node_ref 数据结构描述: struct jffs2_raw_node_ref { }; 其中 flash_offset 表示相应数据实体在 flash 分区上的物理地址,totlen 为包括后继数据的总长度。同一个文 件的多个 jffs2_raw_node_ref 由 next_in_ino 组成一个循环链表,链表首为文件内核描述符 jffs2_inode_cache 数 据 结 构 的 nodes 域 , 链 表 末 尾 元 素 的 next_in_ino 则 指 向 jffs2_inode_cache , 这 样 任 何 一 个 jffs2_raw_node_ref 元素就都知道自己所在的文件了。 一个 flash 擦除块内所有数据实体的内核描述符由 next_phys 域组织成一个链表,其首尾元素分别由擦除块 描述符 jffs2_eraseblock 数据结构的 first_node 和 last_node 域指向。 文件的内核描述符jffs2_inode_cache 每一个文件在内核中都由惟一的 jffs2_inode_cache 数据结构表示,其最主要的作用就是提供了“文件及其 数据之间的映射机制”: struct jffs2_inode_cache { }; struct jffs2_full_dirent *scan_dents; struct jffs2_inode_cache *next; struct jffs2_raw_node_ref *nodes; uint32_t ino; int nlink; int state; 6
第 1 章 jffs2 的数据实体及其内核描述符 ino 为文件的在文件系统中唯一的索引结点号;所有文件内核描述符被组织在一个 inocache_list 哈希表中, next 用于组织冲突项的链表。 nlink 为文件的硬链接个数,在挂载文件系统时会计算指向每个文件的目录项个数,然后赋值给 nlink。注 意上层 VFS 所使用的 nlink 与此不同:在打开文件时会首先将 jffs2_inode_cache 的 nlink 复制到 inode 的 nlink,然后对于非叶目录,会根据其下子目录的目录项个数增加 inode 的 nlink。详见后文。 上层 VFS 的 inode 的主要作用之一就是描述文件及其数据之间的映射关系。由于不同文件系统中数据的组 织格式不同,所以这种映射关系的描述符自然放到 inode 的 u 域中,由具体文件系统的方法实现。就 ext2 而言,ext2_inode_info 的 i_data[]索引文件的磁盘块,而其“物质基础”为文件磁盘索引结点 ext2_inode 的 i_block[]数组;就 jffs2 而言,根据文件类型的不同由 jffs2_inode_info 的 fragtree/dents/metadata 描述 flash 数据实体相关上层数据结构的组织,其“物质基础”就是 jffs2_inode_cache 的 nodes 链表,它组织了文件 所有数据实体的内核描述符 jffs2_raw_node_ref 数据结构,在挂载文件系统时建立。 在挂载 jffs2 文件系统时将遍历整个文件系统(扫描 jffs2 文件系统映象所在的整个 flash 分区),为 flash 上 每个 jffs2_raw_dirent 和 jffs2_raw_inode 数据实体创建相应的内核描述符 jffs2_raw_node_ref、为每个文件创 建内核描述符 jffs2_inode_cache,具体过程详见下文。另外在打开文件时,如果是目录文件,则还要为每 个 jffs2_raw_dirent 创建相应的 jffs2_full_dirent 数据结构并组织为链表;如果是正规文件等,则为每个 jffs2_raw_inode 创建相应的 jffs2_full_dnode、jffs2_tmp_dnode_info、jffs2_node_frag 数据结构,并组织到红 黑树中,详见下文。 jffs2_raw_dirent数据实体及其上层数据结构 /* == JFFS_NODETYPE_DIRENT */ jffs2_raw_dirent 数据实体为 jffs2 中目录项的表示形式,即硬链接的物理实体。文件的目录项组成了其父目 录文件的“数据”。定义如下: struct jffs2_raw_dirent { } __attribute__((packed)); jint16_t magic; jint16_t nodetype; jint32_t totlen; jint32_t hdr_crc; jint32_t pino; jint32_t version; jint32_t ino; jint32_t mctime; uint8_t nsize; uint8_t type; uint8_t unused[2]; jint32_t node_crc; jint32_t name_crc; uint8_t name[0]; /* == zero for unlink */ 7
第 1 章 jffs2 的数据实体及其内核描述符 紧随jffs2_raw_dirent的是相应文件的文件名,长度由nsize域表示,而name域预留了文件名字符串结束符的 空间,ino表示相应文件的索引结点号。如前所述flash上目录文件的若干jffs2_raw_dirent数据实体是离散的, 而且也没有类似ext2_inode的“索引”机制,所以就必须由每个jffs2_raw_dirent数据实体表明自己所属的目 录文件。pino即是为这个目的设计的,表示该目录项所属的目录文件的索引节点号。另外在挂载文件系统 时,会将jffs2_raw_dirent数据实体的描述符加入pino所指文件,即该目录项所属目录文件的jffs2_inode_cache 的nodes链表,参见jffs2_scan_dirent_node函数。 版本号 version 是相对于某一文件内部的概念。任何文件都由若干 jffs2_raw_dirent 或者 jffs2_raw_inode 数 据实体组成,修改文件的“某一个区域”时将向 flash 写入新的数据实体,它的 version 总是不断递增的。 一个文件的所有数据实体的最高 version 号由其 inode 的 u 域,即 jffs2_inode_info 数据结构中的 highest_version 记录。文件内同一“区域”可能由若干数据实体表示,它们的 version 互不相同,而且除了 最新的一个数据结点外,其余的都被标记为“过时”。(另外,按照 jffs2 作者的论文,如果 flash 上数据实 体含有相同的数据则允许它们的 version 号相同) 打开目录文件时要创建其VFS的dentry 、inode、file对象,在创建inode时要调用super_operations函数指针 接 口 中 的read_inode 方 法 , 根 据 相 应 的 内 核 描 述 符jffs2_raw_node_ref 为 每 个 目 录 项 创 建 一 个 上 层 的 jffs2_full_dirent数据结构,并读出jffs2_raw_dirent数据实体后的文件名到jffs2_full_dirent数据结构后面。 jffs2_full_dirent组成的链表则由目录文件的索引结点inode.u.dents(即jffs2_inode_info.dents)指向,参见图 1。 jffs2_full_dirent 数据结构在打开目录文件时才创建,用于保存读出的 jffs2_raw_dirent 数据实体的结果,其 定义如下: struct jffs2_full_dirent { }; 其中 raw 指向相应的 jffs2_raw_node_ref 结构,紧随其后的为从 flash 上读出的文件名。 总之,在打开一个目录文件后其相关数据结构的关系如下图所示(假设该目录有 2 个目录项,没有画出 file、 dentry)。其中对 inode 的 u 域即 jffs2_inode_info 数据结构的解释参见下文。 (注:很抱歉,在第 1 稿中我曾错误地认为目录文件只包含jffs2_raw_dirent数据实体,而实际上目录文件、 设备文件、符号链接文件都有惟一的jffs2_raw_inode数据实体,在打开文件时为其创建的jffs2_full_dnode 由其inode的u域jffs2_inode_info的metedata指向。一个目录文件的数据实体信息可以使用jffs2map2 模块导 出,参见附录) struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *next; uint32_t version; uint32_t ino; unsigned int nhash; unsigned char type; unsigned char name[0]; /* == zero for unlink */ 8
分享到:
收藏