你手里有一个1T大小的硬盘。
你还有一堆文件。
这些文件对硬盘来说只是一堆二进制数据。
你要把这些文件储存在硬盘上,必要时把它们读出来。
应该设计什么样的软件来更方便地读写硬盘中的这些文件?
一个
首先我不想处理复杂的扇区,设备驱动等细节,所以我先实现了一个简单的效果,把硬盘逻辑上分成块,读写可以以块为单位。
每个块定义为两个物理扇区的大小,即1024字节,即1KB。
硬盘太大无法分析,我们假设你的硬盘只有1MB,那么这个硬盘有1024块。
好了,我们开始保存文件吧!
准备一份文件。
随便挑一块放进去,3号块!
胜利!首战告捷!
2
再存一个文件!
啊?这项发明有一个问题。如果这个文件也存储在Block 3中,不是覆盖了原文件吗?不,必须有一个地方来记录现在可以应用哪些块,就像这样。
0:未应用
1:不适用
2:不适用
第3块:已应用
4:不适用
...
第1023项:不适用
让我们用块0来记录所有块的应用!怎么录?
位图!
让我们给块0一个名字,块位图。之后这个block 0专用于记录所有block的应用,不再用来存储特定的文件。
当我们保存一个新文件时,只需要在块位图中找到第一位0,就可以找到第一个没有应用的块,保存文件。同时,不要忘记在块位图中设置相应的位置1。
完美!
三
接下来,我们尝试读取刚才的文件。
哎?我又有问题了。我怎么才能找到刚才的文件?根据街区号?太蠢了,就像你去书店找书,店员让你提供书号而不是书名,这显然是不合理的。
所以我们给每个文件一个名字,文件名,并用它来查找这个文件。
必须有一个地方记录文件名和块号的对应关系,像这样。
向日葵收藏. txt: Block txt:3
数学期末复习资料。MP4:第五街区
低并发编程的保密性。PDF: Block 10
...
别急,既然要选择一个地方记录文件名,不妨多记录一些我们关心的信息,比如文件大小、文件创建时间、文件权限等等。
自然,这些东西也要保存在硬盘上。我们选择一个固定大小的空房间来表示这些信息。空房间有多大?28字节。
为什么是128字节?我很乐意。
我们称这个128字节的结构为inode。
之后我们每保存一个新文件,不仅要占用一个块来存储文件本身,还要占用一个inode来存储文件的元信息,inode的block number的字段指向文件的块号。
如果一个索引节点是128字节,那么一个块可以容纳8个索引节点,我们可以对这些索引节点进行编号。
如果你觉得inode的数量不够,也可以用两个或者更多的块来存储inode信息,但是这样一来,存储数据的技术资源块就少了,这个要看你自己的平衡了。
同样,像块位图管理块的应用一样,我们也需要一个inode位图来管理inode的应用。让我们将索引节点位图放在块1中!
同时,我们把inode信息放在block 2中,8个inode共存,这样我们的block 2就叫做inode表。
现在,我们的文件系统结构变成了这样。
注意:块位图用于管理可用的块,每个位代表一个块是否被应用。索引节点位图逐个管理索引节点,而不是索引节点所占用的块。例如,如果上图中有8个inode,那么inode位图中将有8位来管理它们的应用程序。
四
现在,我们的文件很小,一个街区就能装下。
但是如果我们需要两个街区,三个街区和四个街区呢?
很简单,我们只需要采用连续存储的方法,而inode只记录文件的第一块,以及后面需要多少块。
这种方法的缺陷是容易留下空大小,新文档到达后很难找到合适的空白块,会浪费空。
这个方法好像行不通。我们做什么呢
既然inode中记录了文件所在的块号,为什么不扩展一下,记录更多的块呢?
最初,inode中只记录了一个块号。现在展开它,记录8个块号!这些街区不一定要持续。
嗯,这是一个可行的办法!
但这只能代表8块,能记录的最大文件是8K(记住,一块是1K)。现在文件很容易超过这个限制。我该怎么办?
简而言之,我们可以将其中一个区块作为间接索引。
这样,263块(再多256 -1块)瞬间可用。这种指标称为一级间接指标。
如果不够,再为一级间接索引或者二级间接索引获取一个块(二级间接索引可以是256 * 256-1多块)。
我们的文件系统,暂时只是得到一个一级间接索引。硬盘只有1024块,一个文件263块就够大了。再大也这么任性,爱不爱。
好了,现在我们可以保留非常大的文件了,可以通过文件名和文件大小准确的读出来了!
五
但是我们必须不断进步。我们再来思考一下这个文档系统的缺点。
例如,我们如何知道inode的数量何时不够?您必须查看inode位图吗?找不到,就知道不够。
同理,当块数不够时也是如此。
如果有个全球的地方把这一切都记录下来就好了,方便随时调整,比如这个。
信息节点号
空空闲信息节点的数量
块数
空空闲块数
那我们再占用一块来存储数据吧!因为他们似乎是从上帝的角度来描述这个文件系统,所以我们把它放在初始块上,称之为超级块。现在布局如下。
我们不断进步。
现在,块位图、索引节点位图和索引节点表都占据了块1、块2和块3这三个位置。
如果inode数量太大,以至于inode表或者inode位图需要占用多个块怎么办?
或者,如果块数增加(硬盘本身变大,或者每个块变小),块位图需要占用多个块。我该怎么办?
程序已经死了。如果你不告诉它哪个方块代表什么,它就不会自己去猜。
很简单,就像超级块记录信息一样,这个信息是记录在块里的,所以我不怕。然后,让我们选择超级块旁边的块1来记录这些信息,并将其称为块描述符。
当然,这些块号只记录起始块号,块位图、inode位图、inode表分隔都可以占用多个块。
好了,你完了!
六
现在,让我们再次尝试存放一批文档。
葵花宝典.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的next-to-next结构,比如这样。
这样,首先,通过这个目录文件找到数据块。然后,根据这个数据块中带有inode信息的构造,找到这个目录中的所有文件。
完美!
七
在这种情况下,考虑一下。如果要查看女婿目录下的所有文件(比如ll命令),并显示文件名和文件类型怎么办?
需要从inode表中取出每个构造函数指向的inode,然后再取出文件名和文件类型,很浪费时间。
让用户看到一个目录中的所有文件是一个极其常见的操作。
因此,最好将构造函数中的文件名、文件类型等常用信息放在数据块中。
同时,inode结构中的文件名似乎也没什么用。这种变长的东西在这种定长结构里很讨厌,早就想去掉了。而且还可以为其他信息节省空空间,比如文件所在块的数组,还可以有更多。
太好了,摆脱它!
o技术资源网k,大功告成。现在我们可以把文件分类到不同的目录下,在目录下创建目录,无限娃娃!
八
现在的文件系统已经相当完美了,但是还是有点不太舒服。
当我们访问一个目录时,我们可以很容易地看到目录中的文件,然后根据名称访问目录中的文件或目录。整个过程都是套路。
但是,顶层目录(即根目录)中的所有文件仍然需要通过遍历所有inode来获取。可以和上面的套路统一吗?
答案很简单。我们规定inode表中的0号inode代表根目录,所有访问都从这个根目录开始!
嗯,这次没有了!
最后,让我们看看我们的文件系统架构。
你觉得没什么大不了的。但是这个愚蠢的东西,叫做文件系统。
附言
这个文件系统和linux上的经典文件系统ext2基本相同。
下面是我画的ext2文件系统的结构(字段部分只画了核心字段)
看不清楚。让我告诉你重要的相同点和不同点:
1.超级块前面是启动块,是PC联盟为硬盘指定的1KB独占空空间,任何文件系统都不能使用。
2.ext2文件系统首先把所有硬盘分成很多块组,但如果只有一个块组,那就和我们文件系统的整体结构一样。分离是超级块、块描述符、块位图、索引节点位图、索引节点表和数据块。
3.ext2文件系统的inode表中有15个块用来定位文件,其中第13个块是一级间接索引,14个块是二级间接索引,15个块是三级间接索引。
4.ext2文件系统的文件类型比较多,常见的有块设备文件、字符设备文件、管道文件、套接字文件等。
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