哈喽,我是子牙,一个很卷的硬核男人。立志做那些大家想学没地方学的课程:手写JVM、手写OS、手写MySQL、手写编程语言、黑客…
最近小show了一下我写的文件系统,就有小伙伴跑来问我:我也想手写一个文件系统,该怎么一步一步去做呢?问的人还蛮多的,为了避免重复劳动,写篇文章分享一下吧
首先我给大家看一下一个文件系统自上而下的完整结构,上图
是不是惊了!^-^
可以理解。因为大家更多做的是应用层的业务开发,接触不到这么底层。而且语言层面跟操作系统层面已经做了大量封装,你只要调用如fopen、fclose、read、write等类似的API就可以实现对目录或文件的控制,也不需要自己去实现一个文件系统,也就没有研究得这么深了
那我们为什么要写一个文件系统呢?为了知其所以然,这样才能解决工作中或生活中遇到的疑难杂症:文件删除了如何恢复、增删改查文件或目录底层实现细节是怎样的、硬盘损坏原因排查与数据修复、文件损坏如何排查与修复……
我先给大家解释一下上面那张图,然后告诉大家每一层如何去实现
文件系统
什么是文件系统?就是一套管理文件或目录的软件系统。不同文件系统的区别只是算法的不同。那文件系统算法有哪些呢?
目前操作系统主要是两套内核:Windows内核、Unix内核,算上分布式文件系统,再算上历史,文件系统大概就这些了。其中EXT是Linux系统的文件系统类型,EXT算法已经迭代到第4代,不论是性能还是稳定性、安全性,都已经非常成熟。Windows早期的文件系统用的是FAT,现在主流的是NTFS
我写的文件系统就是仿EXT文件系统结构。EXT文件系统结构大纲长这样,我来解释一下
Linux EXT文件系统结构
这一PA有点长,但是是最重要的,耐心看完,切忌胡思乱想
我先拿Windows来举例吧,大家更容易理解:当我们拿到一块硬盘,我们要做的第一件事情就是分区,比如Windows的C盘、D盘,就是分区的结果
分区以后还不能马上使用,我们要对硬盘进行格式化。格式化是干什么呢?不是大多数人理解的把盘清空,而是将文件系统算法写入。为什么要写入文件系统算法呢?
比如你要在这个731G的盘上创建一个文件,你的文件放哪里?不要小看这个问题,这个问题的答案就是不同文件系统结构与算法不同的本质。那EXT文件系统是如何解决的呢?
还是这张图,我们换个例子,比如我现在要创建根目录。根目录有哪些东西呢:1、根目录名称,在Linux下就是【/】;2、根目录的数据区。我们在一个目录下创建文件或目录,在文件系统看来,就是这个目录的数据
图中有一块区域叫:根目录,这个区域就是用来存储根目录的信息。存储哪些信息呢?我们拿linux举例:目录名称、inode节点的索引号
终于把文件系统一个很重要的东西引出来了:inode。在EXT中,所有的文件或目录都对应一个inode节点。可以这样说,inode节点是在写入文件系统的那一刻,根据分区容量计算好的。inode节点的数量,就是你这个文件系统的上限。举个例子,比如这个731G的盘,如果在写入EXT算法的时候,inode数组只能容纳10个inode节点,那这个大的盘,就只能创建10个文件或目录
那EXT文件系统是如何管理inode数组的呢?通过位图。通过位图可以准确标识哪些inode节点已被占用,哪些是空闲可用的。位图就是长这样,通过1位来映射一个inode节点。比如inode数组中index为3的位置已被占用,那反应到位图中,第一个字节的第四位就是1
位图在很多很多地方都有用到,比如垃圾收集算法中用于映射dirty zone…强烈建议大家有空撸一个。用哪个语言无所谓,C语言、C++、Java都可以,主要是理解思想,你不写一遍,你就是没概念……计算机是一门要动手的学科,而不是一门理解的学科,更不是一门嘴炮的学科。有没有货,show me your code…
上面的图,我已经解释了三个区域:根目录、inode位图、inode数组。还是回到创建目录,根目录的目录名称存储在根目录区域,inode节点存储在inode数组区域,此时inode数组哪个位置可以用,就需要问inode位图。那根目录的数据存储在哪?就需要问空闲块位图了。
731G的硬盘,一个扇区512B,大家算一下有多少扇区。这么多扇区,我怎么知道哪些扇区已被占用,哪些是空闲的呢?这就是数据块位图存在的意义
接下来说超级块,给大家看张图,我相信你就懂了
再说下第一个区域:操作系统引导块。0柱面0磁道1扇区,从很久很久以前都是作为MBR使用。MBR是什么,简单理解就是引导启动操作系统的一小段代码,所以MBR只有在装了操作系统的分区才有意义,那为什么所有分区都有这个区域呢?为了保持统一。因为保留了这个传统,才得以实现一台电脑装多个操作系统…是不是很炫!
理解了EXT文件系统的结构,你就可以动手写了
深浅实现
深浅,借用于深浅拷贝。深的意思是1:1实现,浅的意思是外面看着一模一样,内部却差异巨大
先说浅实现吧,就是说你不用去实现驱动层,也不需要去了解硬盘,只需要调用操作系统提供的文件IO,或者Java IO、PHP IO等去实现文件系统算法即可。这样实现的好处是你不用去研究硬盘、软盘等硬件要如何编程控制,降低了学习门槛。坏处是你在工作或生活中遇到的大多数问题的解决方案都在硬件层、驱动层
总结来说就是浅实现,你可以学到文件系统算法是如何实现的,但是学不到硬盘是如何工作的、如何通过编程控制硬盘、驱动层是如何提供同步、异步硬盘控制的如read、write、check、reset、状态获取与判断…
深实现就是要把上图中提到的每一层都实现出来,好处是写完后深刻理解所有持久化存储的表象及本质,坏处是实现起来有一定难度:首先你得有一个操作系统作为底层支撑,因为文件系统需要依托于操作系统才能运行;其次你得学习硬盘的工作原理及操控方式;最后再以汇编+C语言的方式实现出来
书籍推荐看《操作系统真相还原》,如果你没有一定的功底,可能看起来会比较吃力。关注公众号【硬核子牙】回复【操作系统真相还原】获取电子书
如果看书学习或者看视频学习,让你觉得很痛苦,遇到问题也没人指点,也没有小伙伴陪伴着一起学习…可以考虑加入我的手写操作系统小班
如果你想手写操作系统、手写文件系统,我的公众号【硬核子牙】有环境搭建教程,更有一条龙环境免费获得