上个学期开学时心血来潮突然想做一个自己的操作系统,后来项目考试竞赛一起压上来就搁置了。寒假有了点空闲,玩的间隙研究了下ext2 文件文件系统,聊作此文记录一下,省的忘掉……
说起文件系统就联想起存储设备,加之我的研究方向是嵌入式系统设计……那就用SD卡来作为实验载体吧(可怜我那饱经摧残的SD卡)。
第一步当然是进入Linux 系统将SD格式化成ext2 的格式,要格就充分点,索性我把MBR也重写了……这一步很简单,就不赘述了。
然后随便往卡中放上些东西,就开始我的ext2 之旅了。
要记录就详细点,从MBR 开始讲起:
master bootrecord (MBR) is a type of boot sector popularized by theIBM Personal Computer.
上面WiKi上的定义。我认为MBR的主要功能就是引导CPU的载入OS或其他的Boot loader。其结构说明了一切:
图1 MBR结构图
MBR位于存储设备的起始512个字节内,对大部分存储设别来说就是一个扇区的大小(也是普通硬盘的操作单位)。图中信息都很明确了,对我研究ext2 文件系统有用的是”Table of primary partitions“字段。这个字段记录了存储设备的主分区情况,从图中不难看出MBR中最多只能记录4条主分区信息,这也就解释了为什么windows中最多只能有三个主分区,什么你不要逻辑分区……好吧你最多可以拥有4个主分区,或者3个主分区加上一个扩展分区。因为我的SD卡只分了一个区所以”Tableof primary partitions“中只存了一项纪录。下一步就是从一项纪录中抽取分区的具体信息了。
表1 16 字节的分区信息纪录(所有多字节字段均为little-endian)
Offset | Description |
0x00 | 1Byte:Status(0x80 = 可引导的, 0x00 = 不可引导的, 其他 = 非法的) |
0x01 | 3Bytes:分区起始绝对扇区号,用CHS[*]地址标示 |
0x04 | 1Byte:分区类型(0x83 SD卡中的标号) |
0x05 | 3Bytes:分区结束绝对扇区号,用CHS[*]地址标示 |
0x08 | 4Bytes:LBA表示的分区起始绝对扇区号(这个才是我要看的,去你的CHS表示法) |
0x0C | 4Bytes:分区扇区数目 |
[*]CHS:柱面,磁头,扇区地址标示法,老物了……
没什么好说的,通过第三项确定分区类型,通过最后两项可以定位分区。
有了ext2 分区的起始绝对扇区号就可以定位了,下面开始ext2 之旅。
ext2文件系统也算是老物了,但现在用于不是很大的U盘和SD卡中还是很合适的。ext2 文件系统的组成如下表所示:
表2 ext2 文件系统组成示意图
Boot Block | Block Group 0 | Block Group 1 | … … | Block Group n |
BootBlock:就是上面的MBR,当然也可能是GPT 等等。真正的ext2分区就是一个个的Block Group.
直接上图,Block Group 0的结构:
1024 Bytes offset(分区开始前1024个字节没用) |
Super Block(1024 Bytes) |
Group Descriptors(n blocks) |
Data Block Bitmap(1 block) |
Inode Bitmap(1 block) |
Inode Table(n blocks) |
Data Blocks(n blocks) |
图2Block Group 0的结构信息
分区开始的前1024个字节是没用的……一开始怎么也找不到super block 就是栽在这货手里了。ext2文件系统中最为重要的两张表就是Super Block与Group Descriptors了,整个ext2文件系统中拿来用的(备份表等会再说)两张表各一份,均位于Block Group0中。当然,为了文件系统的健壮性(不像那该死的Fat表),在其他一些Block Group中还留有备份。Data Block Bitmap与Inode Bitmap是用来记录其所在Group的Block与Inode(说起Inode,等会详细介绍)的使用情况,在写文件系统时能排上用场。紧接着是Inode Table表。不像Fat32文件系统将所有文件的索引信息都集中于一个Fat表内,ext2文件系统将整个文件系统的索引信息分别存放于多张Inode Table中,虽然离散的存储位置可能会损失一部分的cache性能,但同时也提升了文件系统的可靠性,正所谓鱼与熊掌不可兼得啊。
字段的详细介绍不想多言,详细内容可以参看Dave Poirier 的文档http://www.nongnu.org/ext2-doc/ext2.html 。
下面来说说ext2文件系系统的组织形式。
ext2文件系统中单个文件数据的存放使用的是索引节点的形式,所有的文件、目录与链接都被视为一个节点,在节点中存有文件(广义上的文件)的详细信息,包括数据的索引表。而ext2文件系统的各个文件是通过目录的形式来组织的。
先来看看目录文件中到底放了些什么。ext2文件系统中允许两种目录组织形式:链式存放方式与索引存放方式。当然链式存放比较古老,速度也更慢,所以文件系统的设计者们在Revision 1中引入了hash表形式的索引目录,不过索引目录依然兼容链式目录。我的Linux系统使用的是Fedora16,不知怎搞的用她其中的硬盘工具格式化出来的SD卡竟然只有链式目录……我猜测可能是因为SD卡容量太小,格式化工具觉得没有使用索引目录的意义。那就讲讲链式目录吧。
顾名思义,链式目录就是将目录下的文件条目以一条链的结构组织起来,通过每个条目中的rec_len条目来定位下一个条目。
表3 链式目录格式中一条条目的组成
Offset | Size | Description |
0 | 4 | inode:本条目的inode号,0表示本条目未使用 |
4 | 2 | rec_len:下一个条目到本条目起始位置之间的间隔 |
6 | 1 | name_len:文件名长度 |
7 | 1 | file_type:文件类型 |
8 | 0-255 | file_name:文件名 |
? | ? | padding:为满足边界对齐插入空白(条目长度必须是4的整数倍) |
其中下一个条目的计算方法就是直接用本条目的起始地址加上rec_len就可以了。其他没什么好说的了……简单异常。
最后说说ext2中文件的组织形式,直接上图:
图3ext2文件系统文件组织形式
ext2文件系统中的文件具体内容在存储设备中是使用索引节点的方式存储的,最高层的索引节点位于每个inode内部,其中含有15项,每项4字节。
前12项直接存储的是数据块的地址(当然是Block块号),13项是一层间接地址,指向1个Block块大小的地址存储块,其中存有数据块的地址,当然是4字节一项,0表示结束。4层是二层间接地址,同理5层就是3层间接地址了。在一个BlockSize等于4KB的文件系统中(我的SD卡就是4KB),理论上最大的文件大小是:
12 * 4KB + 1024 * 4KB+ 1024 * 1024 * 4KB + 1024 * 1024 * 1024 * 4KB = 4299165744KB
大约是4TB的文件……基本上达不到。