前言
进程加工处理的数据就是进程的劳动成果,如何将这个“劳动成果”表示和组织,存放在哪里?
一、什么是文件系统?
文件系统解决的就是如何把许多文件存储在某一储存设备上,方便进程对各种文件执行打开、关闭、读写、增加和删除等操作。操作系统会专门分出一个子系统专门处理这些问题,这个系统就叫文件系统。 文件系统在上层为用户或者进程提供了一个逻辑视图,也就是目录结构。从下图中,可以看出目录也是文件的一部分,他也扮演了“组织仓库管理员”的角色,可以对文件进行分层分类,以便用户对众多文件进行管理。
二、文件系统设计
1.从三个问题出发对文件系统设计方面的思考
1.文件系统为什么可以是一个设备,以及它在整个Cosmos内核中的位置格局? 2.文件数据的格式以及存储介质的最小单位是什么? 3.如何组织越来越多的文件。
2.文件系统只是一个设备
HD机械硬盘、SSD固态硬盘、U盘等都属于存储设备,这些设备上的文件存储格式都不相同,甚至同一个硬盘上不同的分区的存储格式也不同。这个储存格式就是相应文件系统在储存设备上组织储存文件的方式。 例如,我们经常见到的:FAT32、Ext4等,这些都是不同文件系统建立的文件系统格式。 1.文件系统组件是独立的与内核分开的。 2.操作系统需要动态加载和删除不同文件系统组件,这样就可以适应复杂的情况了。例如,硬盘上不同的分区有不同的文件系统格式,还可以拔插U盘等。 果文件系统也是 Cosmos 内核下的一个设备,那就好办多了,因为不同的设备驱动程序可以动态加载,而且可以建立多个文件系统设备,而对各个文件系统设备驱动程序的实现,就是各个文件系统的实现。
2.文件格式与储存块
在逻辑上认为一个文件就是一个可以动态增加、减少的线性字节数组,即文件数据的每一个字节都一一对应到这个线性数组中的每个元素。 图中的文件数据字节数组,终究是逻辑上的,如何映射代具体的储存设备上呢?现在的机械硬盘、SSD固态硬盘、TF卡,它们都是以储存块为单位储存数据的,一个储存块的大小可以是512、1024、2048、4096字节,访问这些储存设备的最小单位也是一个储存块,不像内存设备可以最少访问一个字节。 文件系统把文件数据定义成一个动态的线性字节数组,可是一开始我们不知道这个数组是多大,需要分配多少个物理储存块,最好是把这个动态的线性字节数组分成一个个数据块。 不同的储存设备的物理储存块的大小不同,有的是512字节,有的是4096字节,我们为了文件系统能工作在不同的储存设备上,所以我们把这里的数据块定义为文件系统的逻辑块,其大小为4096字节,最后把这个逻辑块映射到一个或者多个物理储存块。 从这幅图里,我们可以看到从文件这个抽象概念,它是如何一步步从文件字节数组,整合形成文件数据逻辑块,最后映射到储存介质上的物理储存块。
3.如何组织文件
需要一个叫文件目录或者文件夹的东西,习惯称之为目录。这样我们就可以用不同的目录来归纳不同的文件,同时,目录还可以创建目录,这样就建立了非常好的层次关系。 你可能经常在 LINUX 系统中看到如:“/dev/kvm,/user/bin/gcc”之类的东西,其中 dev、user、bin 它们就是目录,kvm、gcc 它们就是文件,“/”符号就是文件路径分隔符,它们合起来就是文件路径名。
二、文件系统数据结构
1.设计超级块
一个文件系统有很多重要的信息,例如文件系统标识、版本、状态、储存介质大小,文件系统逻辑储存块大小,位图所在的储存块,所有包含这些信息的数据结构,就叫做文件熊的超级块或者文件系统的描述块。 我们文件系统的超级块,保存在储存设备的第一个4KB大小的逻辑储存块中,但是它本身的大小没有4KB,多余的空间用于以后扩展。rfsdir_t数据结构是一个目录数据结构。当然把根目录数据结构直接放在超级块中,目前也是可行的,毕竟超级块中有多余的空间。
2.位图
我们将储存设备分成一个个逻辑储存块(4KB),当储存一个文件数据时,就按逻辑储存块进行分配,如何标识哪些逻辑块是空闲的,哪些逻辑块是已经分配的呢? 我们可以用位图来解决这个问题,这里的位图,就是利用一块储存空间中所有为的状态,达到映射逻辑储存块状态(是否已经分配)的目的。 一个字节是8个位,那么4KB的储存空间中,就有(4096*8)个位,这每个位映射到一个逻辑储存块,其中一个位的值为0,就表示该位对应的逻辑储存块是空闲的,反之就表示对应的逻辑储存块是占用的。 位图不需要定义实际的数据结构,在实际操作时,把位图这个储存块当成一个字节数组就行,这里 我们用了一块4MB的内存空间模拟储存设备,所以一共只有1024个4KB大小的逻辑储存块。由于数量少,所以位图完全可以用一个字节表示一个逻辑储存块是否空闲还是占用。
3.文件目录
为了方便用户查找和归纳越来越多的文件,才产生了目录。从本质上来说,目录也是一种数据,这种数据包含了目录类型、状态、指向文件数据管理头的块号、名称等信息(rfdir_t)。rfsdir_t数据结构最多只有128字节大小,由于存储设备不能用字节地址访问,它只能一块一块的访问,所以rfsdir_t结构中有个域,指向文件数据管理头的块号。 为什么rfsdir_t结构中会有很多类型呢?目录也是一种特殊的文件,它里面就是保存着一系列rfsdir_t结构的实例变量,这些rfsdir_t结构再次表明它代表的是一个文件还是一个目录。 从上图中可以看到,超级块中的rfsdir_t结构保存了根目录的名称和指向管理根目录数据的文件管理头的块号。而实际的目录数据保存在逻辑储存块中,这表明目录也是一种数据。通过一系列的rfsdir_t结构就能找到根目录下的其他文件和目录了。
4.文件管理头
文件系统最重要的是管理和存放文件。 一个文件的信息包括状态、类型、创建时间、访问时间、大小,更为重要的是该文件使用了哪些逻辑储存块即fimgrhd_t结构。fimgrhd_t 结构中,其它的信息都比较易懂,关键是 fmd_fleblk 数组,它里面的每个元素都保存一片连续的逻辑储存块。 比如一个文件占用:48、1015、30~40 的逻辑储存块,那么就在 fmd_fleblk[0]中保存 4 和 4,在 fmd_fleblk[1]中保存 10 和 5,在 fmd_fleblk[2]中保存 30 和 10。 但是我们想了一个办法,在 fmd_fleblk 数组元素用完时,就再分配一个逻辑储存块,在里面再次存放同一个文件的 fimgrhd_t 结构,让上一个 fimgrhd_t 结构中的 fmd_linknblk 域指向这个逻辑储存块,再让这个逻辑储存块中 fimgrhd_t 结构中的 fmd_linkpblk 域,指向上一个 fimgrhd_t 结构所在的逻辑储存块。 从这张图中,我们可以看到 fimgrhd_t 结构如何管理一个文件占有的所有逻辑储存块,并且可以通过类似链表的形式动态增加 fimgrhd_t 结构,实际上就是在动态增加文件的逻辑储存块。同时我们不难发现,文件的第一个逻辑储存块的首个 512 字节空间中,存放的就是 fimgrhd_t 数据结构。
|