阅读linux 的源码的时候对minix 文件系统有很多的疑惑,根据自己的认识将这些做一个总结。
MINIX 文件系统由六个部分组成,分别是引导块,超级块,i结点位图,逻辑块位图,i结点,数据块。
引导块:上电由计算机BIOS读取的部分,格式固定,所有的盘都包含这个部分,不作为启动盘的磁盘引导块内容为0。
超级块:存放盘设备上文件系统的结构信息,并说明各个部分的大小。
struct d_super_block {
unsigned short s_ninodes;
unsigned short s_nzones;
unsigned short s_imap_blocks;
unsigned short s_zmap_blocks;
unsigned short s_firstdatazone;
unsigned short s_log_zone_size;
unsigned long s_max_size;
unsigned short s_magic;
};
i结点位图:说明i结点的使用情况,每一位代表一个i结点。
逻辑块位图:说明数据盘块的使用情况,每一位表示一个数据块的使用情况。
i结点:存储结点信息,32个自己存储一个i结点
struct d_inode {
unsigned short i_mode;
unsigned short i_uid;
unsigned long i_size;
unsigned long i_time;
unsigned char i_gid;
unsigned char i_nlinks;
unsigned short i_zone[9];
};
数据块:存储文件的目录或者文件的内容
通过一个实际的例子来认识MINIX文件系统的结构:
1:使用指令dd if=/dev/zero of=minix.img bs=1k count=360 生成一个文件
2:将文件格式化成为minix 格式的文件系统 mkfs.minix -1 minix.img
从中可以看到有128 个i结点,总共有360个块,数据区从第8个块开始。使用指令hexdump -C minix.img可以查看文件系统的二进制格式
上图的第二个红色框内就是超级块的内容,我们来解析一下相关的部分:
struct d_super_block {
unsigned short s_ninodes; //0x0080,十进制128,inode总共128个
unsigned short s_nzones; //0x0168,十进制360,总共360个zone
unsigned short s_imap_blocks; //0x0001,十进制1,inode位图占1个块
unsigned short s_zmap_blocks; //0x0001,十进制1,zone位图占1个块
unsigned short s_firstdatazone;//0x0008,十进制8,第一个数据区编号是8
unsigned short s_log_zone_size;//0x0000,log表示的一块数据大小,1kb
unsigned long s_max_size; //0x10081c00,十进制268966912,最大文件长度
unsigned short s_magic; //0x138f,minix魔数
};
i节点位图数据
再来看i结点位图部分:从超级块中看到有128个i结点,那么可以算出来需要128/8 =16个byte 的数据来管理i结点。128 个bit 位来表示128个i结点,但是由于第一个bit 位不使用,并且被设置为1(0x3=00000011),所有后的第17个字节的fe 贡献出来一个bit (0xfe=11111110).从这个数据来看i结点被使用了一个,0x3=00000011,红色的1表示第一个i结点被使用。从图中可以看出第一个i结点中数据部分不是0,有相关的内容。
再来看i结点的数据内容 :
根据数据结构解析内容:
struct d_inode {
unsigned short i_mode; //0x41ed,040755, 目录文件, rwxr-xr-x
unsigned short i_uid; //0x03e8
unsigned long i_size; //0x00000040
unsigned long i_time; //0x663c6817
unsigned char i_gid; //0xe8
unsigned char i_nlinks; //0x02
unsigned short i_zone[9]; //{0x0008,0x0000重复8次}
};
从中可以看到size 是0x40 有64个byte ,原因是文件系统有“.”和“..”两个目录项。从数据块中可以看到2e是“.”的ASSIC 码表示。
在文件系统中,.
和 ..
有特殊的含义,尤其在 UNIX 和 Linux 系统中。
-
.
(点):- 表示当前目录。当你在一个目录中执行操作或引用文件时,
.
用来指代当前目录。例如,./my_textfile
表示当前目录下的名为my_textfile
的文件。 - 在文件路径中,
.
也常常用于表示相对路径的起始位置。
- 表示当前目录。当你在一个目录中执行操作或引用文件时,
-
..
(点点):- 表示当前目录的上一级目录,即父目录。当你想要访问上一级目录中的文件或目录时,可以使用
..
。例如,../my_runfile
表示上一级目录下的名为my_runfile
的文件。 - 在文件系统的根目录中,
..
和.
是相同的,因为根目录没有父目录。
- 表示当前目录的上一级目录,即父目录。当你想要访问上一级目录中的文件或目录时,可以使用
这两个特殊标记在 UNIX 和 Linux 系统中非常常见,用于方便地导航和引用文件系统中的文件和目录。它们也用于文件路径的构造,使得用户可以使用相对路径而不是绝对路径来引用文件。
再来看逻辑块位图部分:有44个byte ,44x8=352个数据块。1个引导块,1个超级块,1个i结点位图块,1个逻辑位图块,4个i节点块(128x32=4096,需要4k的数据存储i结点,所以有4个i节点块),总的块数是360. 首位不用置为1,最后的0xfe补一个bit位。
目前我们的文件系统中是一个空的,只有“.”和“..”两个默认的目录项,我们在PC上挂载文件系统,然后新建一个dir 文件夹,再在里面新建一个文件看看MINIX各个部分的变化情况。通过指令sudo mount minix.img -o loop mnt来挂载文件系统。
从图中看出,除了超级块和,引导块其它部分都有变化。i结点位图第一个byte 从0x3变成了0x17(00010111),从中可以看出有三个i结点被使用,分别是第一个,第二个和第四个。逻辑块位图的第一个byte从0x3变成了0x0f(00001111)第一个,第二个,第三个数据块被使用了。i结点部分
0x1000~0x101F,0x1020~0x103F,0x1060~0x107F这几个地址中存储的是3个i结点。分别对应于0x0008,0x0009,0x000a这三个块。第一个是根目录的i结点,通过它可以找到根目录下的文件目录内容。
找到内容“.”,“..”和“dir”。可以看到dir 在的i节点号是0x0002.
从2号i结点中我们找到dir 内容,首先确认2号结点存储的数据在9号数据块中
然后从9x1024=0x2400这个地址的起始位,长度是0x80
里面记录了一些内容:02 00 2e 表示“.”在2号结点。01 00 2e 2e 表示“..”在1号结点,04 00 74 65 73 74 2e 74 78 74 对应4号结点的test.txt文件,我们再通过4号结点查找文件的内容。
文件内容在第0xa个数据块处,10x1024 = 0x2800处,长度是0x00000007个字节。
找到文件的内容31 32 33 34 35 0a 0a 。
回顾整个过程./dir/test.txt,这个文件我们是怎么找到它的内容的,首先在利用根目录的i结点找到根目录下的所有目录项,然后从中找到dir 的i结点号,然后通过dir的i结点号找到下面的所有目录项,然后找到test.txt的i结点号,然后找到文件中的内容。
本文简单总结了MINIX 文件系统的数据结构,是大家在学习linux内核文件系统的时候有一个基本的了解,详细的介绍可以看看《linux内核完全注释》这本书的第九章。