文章目录[隐藏]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 你是不是认为这没啥了不起的。但这个破玩意,它就叫文件体系
- 后记
你手里有一块硬盘,大小为 1T
你还有一堆文件
这些文件在硬盘看来,就是一堆二进制数据而已
你预备把这些文件存储在硬盘上,并在须要的时候读取出来。
要设计怎样的软件,能力更便利地在硬盘中读写这些文件呢?
1
首先我不想和庞杂的扇区,装备驱动等细节打交道,因此我先实现了一个简略的功效,将硬盘按逻辑分成一个个的块,并可以以块为单位进行读写。
每个块就定义为两个物理扇区的大小,即 1024 字节,就是 1KB 啦。
硬盘太大不好剖析,我们就假设你的硬盘只有 1MB,那么这块硬盘则有 1024 个块。
OK,我们开端存文件啦!
预备一个文件
随意选个块放进去,3 号块吧!
胜利!首战告捷!
2
再存一个文件!
诶?发明问题了,万一这个文件也存到了 3 号块,不是把本来的文件笼罩了么?不行,得有一个处所记载,现在可应用的块有哪些,像这样。
块 0:未应用
块 1:未应用
块 2:未应用
块 3:已应用
块 4:未应用
…
块 1023:未应用
那我们就用 0 号块,来记载所有块的应用情形吧!怎么记载呢?
位图!
那我们给块 0 起个名字,叫块位图,之后这个块 0 就专门用来记载所有块的应用情形,不再用来存具体文件了。
当我们再存入一个新文件时,只须要在块位图中找到第一个为 0 的位,就可以找到第一个还未被应用的块,将文件存入。同时,别忘了把块位图中的相应地位 1。
完善!
3
下面,我们尝试读取刚刚的文件。
咦?又遇到问题了,我怎么找到刚刚的文件呢?依据块号么?这也太蠢了,就像你去书店找书,店员让你供给书的编号,而不是书名,显然不合理。
因此我们给每个文件起一个名字,叫文件名,通过它来寻找这个文件。
那必定就要有一个处所,记载文件名与块号的对应关系,像这样。
葵花宝典.txt:3 号块
数学期末温习资料.mp4:5 号块
低并发编程的机密.pdf:10 号块
…
别急,既然都要选一个处所记载文件名称了,不妨多记载一点我们关怀的信息吧,比如文件大小、文件创立时光、文件权限等。
这些东西自然也要保留在硬盘上,我们选择深圳生涯网用一个固定大小的空间,来表现这些信息,多大空间呢?128 字节吧。
为啥是 128 字节呢?我乐意。
我们将这 128 字节的构造体,叫做一个 inode。
之后,我们每存入一个新的文件,不但要占用一个块来寄存这个文件本身,还要占用一个 inode 来寄存文件的这些元信息,并且这个 inode 的所在块号这个字段,就指向这个文件所在的块号。
如果一个 inode 为 128 字节,那么一个块就可以容纳 8 个 inode,我们可以将这些 inode 编上号。
如果你认为 inode 数不够,也可以用两个或者多个块来寄存 inode 信息,但这样用于寄存数据的块就少了,这就看你自己的平衡了。
同样,和块位图管理块的应用情形一样,我们也须要一个 inode 位图,来管理 inode 的应用情形。我们就把 inode 位图,放在 1 号块吧!
同时,我们把 inode 信息,放在 2 号块,一共存 8 条 inode,这样我们的 2 号块就叫做 inode 表。
现在,我们的文件体系构造,变成了下面这个样子。
注意:块位图是管理可用的块,每一位代表一个块的应用与否。inode 位图管理的是一条一条的 inode,并不是 inode 所占用的块,比如上图中有 8 条 inode,则 inode 位图中就有 8 位是管理他们的应用与否。
4
现在,我们的文件很小,一个块就能容下。
但如果须要两个块、三个块、四个块呢?
很简略,我们只须要采取持续存储法,而 in深圳生涯网ode 则只记载文件的第一个块,以及后面还须要多少块,即可。
这种方法的缺陷就是:容易留下大大小小的空泛,新的文件到来以后,难以找到适合的空白块,空间会被糟蹋。
看来这种方法不行,那怎么办呢?
既然在 inode 中记载了文件所在的块号,为什么不扩大一下,多记载几块呢?
本来在 inode 中只记载了一个块号,现在扩大一下,记载 8 个块号!而且这些块不须要持续。
嗯,这是个可行的方法!
但是这也仅仅能表现 8 个块,能记载的最大文件是 8K(记住,一个块是 1K), 现在的文件轻松就超过这个限制了,这怎么办?
很简略,我们可以让其中一个块,作为间接索引。
这样瞬间就有 263 个块(多了 256 -1 个块)可用了,这种索引叫一级间接索引。
如果还嫌不够,就再弄一个块做一级间接索引,或者做二级间接索引(二级间接索引则可以多出 256 * 256 – 1 个块)。
我们的文件体系,暂且先只弄一个一级间接索引。硬盘一共才 1024 个块,一个文件 263 个块够大了。再大了不许可,就这么任性,爱用不用。
好了,现在我们已经可以保留很大的文件了,并且可以通过文件名和文件大小,将它们精确读取出来啦!
5
但我们得精益求精,我们再想想看这个文件体系有什么缺点。
比如,inode 数目不够时,我们是怎么得知的呢?是不是须要在 inode 位图中找,找不到了才知道不够用了?
同样,对于块数目不够时,也是如此。
要是有个全局的处所,来记载这一切,就好了,也便利随时调剂,比如这样
inode 数目
空闲 inode 数目
块数目
空闲块数目
那我们就再占用一个块来存储这些数据吧!由于他们看起来像是站在上帝视角来描写这个文件体系的,所以我们把它放在最开端的块上,并把它叫做超级块,现在的布局如下。
我们持续精益求精。
现在,块位图、inode 位图、inode 表,都是是固定地占领这块 1、块 2、块 3 这三个地位。
假如之后 inode 的数目很多,使得 inode 表或者 inode 位图须要占领多个块,怎么办?
或者,块的数目增多(硬盘本身大了,或者每个块变小了),块位图须要占领多个块,怎么办?
程序是逝世的,你不告知它哪个块表现什么,它可不会自己猜。
很简略,与超级块记载信息一样,这些信息也选择一个块来记载,就不怕了。那我们就选择紧跟在超级块后面的 1 号块来记载这些信息吧,并把它称之为块描写符。
当然,这些所在块号只是记载起始块号,块位图、inode 位图、inode 表分离都可以占用多个块。
好了,大功告成!深圳生涯网
6
现在,我们再尝试存入一批文件。
- 葵花宝典.txt
- 数学期末温习资料.mp4
- 赘婿1.mp4
- 赘婿2.mp4
- 赘婿3.mp4
- 赘婿4.mp4
- 低并发编程的机密.pdf
诶?这看着好不爽,所有的文件都是平铺开的,能不能拥有层级关系呢?比如这样
- 葵花宝典.txt
- 数学期末温习资料.mp4
- 赘婿
- 赘婿1.mp4
- 赘婿2.mp4
- 赘婿3.mp4
- 赘婿4.mp4
- 低并发编程的机密.pdf
我们将葵花宝典.txt 这种称为普通文件,将赘婿这种称为目录文件,如果要拜访赘婿1.mp4,那全文件名要写成
赘婿/赘婿1.mp4。
如何做到这一点呢?那我们又得把 inode 构造拿出来说事了。
此时须要一个属性来区分这个文件是普通文件,还是目录文件。
缺什么就补什么嘛,我们已经很熟习了,专门加一个 4 字节,来表现文件类型。
如果是普通文件,则这个 inode 所指向的数据块仍然和之前一样,就是文件本身原封不动的内容。
但如果是目录文件,则这个 inode 所指向的数据块,就须要重新计划了。
这个数据块里应当是什么样子呢?可以是一个一个指向不同 inode 的紧挨着的构造体,比如这样。
这样先通过 赘婿 这个目录文件,找到所在的数据块。再依据这个数据块里的一个个带有 inode 信息的构造体,找到这个目录下的所有文件。
完善!
7
不过这样的话,你想想看,如果想要查看一下赘婿这个目录下的所有文件(比如 ll 命令),将文件名和文件类型都展现出来,怎么办呢?
就须要把一个个构造体指向的 inode 从 inode 表中取出,再把文件名和文件类型取出,这很是糟蹋时光。
而让用户看到一个目录下的所有文件,又是一个极其常见的操作。
所以,不如把文件名和文件类型这种常见的信息,放在数据块中的构造体里吧。
同时,inode 构造中的文件名,好像就没啥用了,这种变长的东西放在这种定长的构造中本身就很讨厌,早就想给它去掉了。而且还能给其他信息省下空间,比如文件所在块的数组,就能再多几个了。
太好了,去掉它!
OK,大功告成,现在我们就可以给文件分门别类放进不同目录下了,还可以在目录下创立目录,无穷套娃!
8
现在的文件体系,已经比拟完美了,只是还有一点不太爽。
我们拜访到一个目录下,可以很舒畅地看到目录里的文件,然后再依据名称拜访这个目录下的文件或者目录,全部进程都是一个套路。
但是,最上层的目录下的所有文件,即根目录,现在仍然须要通过遍历所有的 inode 来获得,能不能和上面的套路统一呢?
答案非常简略,我们规定,inode 表中的 0 号 inode,就表现根目录,一切的拜访,就从这个根目录开端!
好了,这回没有然后了!
我们最后来观赏下我们的文件体系架构。
你是不是认为这没啥了不起的。但这个破玩意,它就叫文件体系
后记
这个文件体系,和 linux 上的经典文件体系 ext2 根本雷同。
下面是我画的 ext2 文件体系的构造(字段部分只画了核心字段)
估量你是看不清了,我说下重要异同点:
1. 超级块前面是启动块,这个是 PC 联盟给硬盘规定的 1KB 专属空间,任何文件体系都不能用它。
2. ext2 文件体系首先将全部硬盘分为很多块组,但如果只有一个块组的话,和我们的文件体系整体构造就完整一样了,分离是超级块、块描写符、块位图、inode 位图、inode 表、数据块。
3. ext2 文件体系的 inode 表中用 15 个块来定位文件,其中第 13 个块为一级间接索引、14 个为二级间接索引、15 个为三级间接索引。
4. ext2 文件体系的文件类型分得更多,还有常见的如块装备文件、字符装备文件、管道文件、socket 文件等。
5. ext2 文件体系的超级块、块描写符、inode 表中记载的信息更多,但核心的和我们的文件体系一样,而且这些字段在后续的 ext3 和 ext4 中不断增长,坚持向前兼容。
6. ext2 文件体系的 2 号 inode 为根目录,而我们的体系是 0 号 inode 为根目录,这个很随便,你设计一个文件体系定一个 187 号 inode 为根目录也没人拦着你。
如果你想懂得 ext2 文件体系的全体细节,有三种方法。
1. 看源码,linux1.0 后的源码都有 ext2 文件体系的实现,源码是最精确的。
2. 看官方文档,这里有个 pdf 衔接。https://www.nongnu.org/ext2-doc/ext2.pdf
3. 看优质博客,这里我推举一个。http://docs.linuxtone.org/ebooks/C