【现代操作系统】之文件系统的实现

什么是文件系统的实现

上一节中,我们从用户角度观察了文件系统,这一节中我们要从实现者的角度考虑问题。用户关心文件是怎样命名的,可以进行什么操作、目录树是什么样的以及类似的界面的问题。而实现者感兴趣的是文件和目录是怎样存储的、磁盘空间是怎样管理的以及怎样使系统有效而可靠地工作等问题。

文件系统布局

文件系统存放在磁盘上,多数磁盘划分为一个或多个分区。每个分区中有一个独立的文件系统。在这里插入图片描述
如图中所示,磁盘的0号扇区称为主引导记录用来引导计算机(MBR),在MBR的结尾是分区表,该表给出了每个分区的起始和结束地址。表中的第一个分区被标记为活动分区。计算机被引导时,BIOS读入MBR并执行,MBR确定活动分区,它会读入这个活动分区的第一个块,这个块称作引导块,引导块中的程序将装载该分区中的操作系统。引导块之后是超级块,超级块中包含文件系统中所有的关键参数,如确定文件系统类型的魔数,文件系统中数据块的数量以及其它重要的管理信息。超级块之后有空闲空间管理,i节点,根目录,文件和目录。
下图是MBR中的结构
在这里插入图片描述
主引导记录最开头是第一阶段引导代码。其中的硬盘引导程序的主要作用是检查分区表是否正确并且在系统硬件完成自检以后将控制权交给硬盘上的引导程序(分区中引导操作系统的程序)
下面是分区表中一个16字节记录的内容
80 01 01 00 0B FE BF FC 3F 00 00 00 7E 86 BB 00
则我们可以看到,最前面的"80"是一个分区的激活标志,表示系统可引导;"01 01 00"表示分区开始的磁头号为1,开始的扇区号为1,开始的柱面号为0;"0B"表示分区的系统类型是FAT32,其他比较常用的有04(FAT16)、07(NTFS);"FE BF FC"表示分区结束的磁头号为254,分区结束的扇区号为63、分区结束的柱面号为764;"3F 00 00 00"表示首扇区的相对扇区号为63(小端序);"7E 86 BB 00"表示总扇区数为12289662(小端序)。

文件的实现

文件存储的实现的关键问题是记录各个文件分别用到了哪些磁盘块,不同操作系统采用不同的方法。
1、连续分配
这是一种简单高效的方法。
实现机制:为文件连续分配内存块,例如一个内存块大小为1K,一个50K的文件就需要占用连续50个内存块,如果最后一个文件块没有被占满,那么它将会被浪费。
优点:实现简单,只需要记住一个文件的用到的磁盘块的起始地址和用到的磁盘块的数目。读性能好,找到之后就全带宽输出。所以连续分配具有实现简单高性能的优点
存在问题:随着时间推移,磁盘会变得零碎。当一个文件被删除时,就会出现一个空洞,磁盘不会挤压这个空洞来进行磁盘紧缩,因为这样会涉及到很多文件的移动。最终,磁盘上会出现很多空洞。移动紧缩是行不通的,还有一种方法,操作系统维护着一个空洞链表来管理空洞,当创建一个新的文件时,就会挑选一个合适大小的空洞来存入文件。但是这样设计有另一个问题,那就是必须要预先知道存入文件的大小,但是这是用户不友好的,想象一下,你在用word的时候能预先知道你需要多少空间吗?或者是你在写代码的时候,你能知道你的代码将来会扩展到多大吗?
由于上述问题,连续分配在存储内容经常变动的存储场景下是行不通的,但是在一些存储内容预先设置好之后就不在变动的场合下,它又是可行且高效的。所以研究那些具有清晰和简洁概念的老式系统和思想是很重要的,因为它们有可能以一种十分实用的方式在未来的系统中获得应用
2、链表分配
这种方法是通过为每个文件构造磁盘链表,每个块的第一个字作为指向下一个块的指针,块的其它部分存放数据。这样只要存放第一块的磁盘地址在目录项中,其它块就可以依照这个地址索引到。
但是这种方法也存在一些问题,比如,随机读文件相当缓慢(因为要按照链表挨个索引),同时,由于指针占用了一些字节,每个磁盘块存储数据的字节数不再是2的整数倍,许多程序都是以2的整次幂来读写数据的,在这种情况下,就不得不将一部分数据放到另一个块中,从而在读取数据的时候需要拼接操作,这的确降低了系统的效率。
3、在内存中采用表的链表分配
实现机制:取出每个磁盘块的指针字,在磁盘中构建成一个表,具体的构建方式见下图,当系统运行时,把它放在内存空间中,这样当需要读取某个文件的时候就可以快速地直接定位磁盘块,而不需要进行链表的磁盘级索引。
在这里插入图片描述
但是这种方法也有缺点,当磁盘很大的时候,例如200GB的磁盘1KB的块,一张表需要两亿项(209715200),每项占3到4个字节,这样一张表加载到内存需要600M到800M内存,这是十分不合适的,所以FAT不适合大磁盘。
4、i节点
i节点:这是一种数据结构,里面包含了一个文件的属性和所占用的磁盘块的地址。
实现机制:有了i节点后,在内存中只需要预留一块空间给i节点就可以了,而i节点只会在对应的文件被打开的时候被加载到内存。这种方法在大磁盘的情况下可以节省很多空间,或者这样说,FAT占用的内存空间与磁盘大小线性相关,而i节点占用的空间与磁盘大小无关,与可能同时打开的文件个数有关。
但是这种方法也存在一些问题,如果i节点只能存放固定数目的磁盘地址,那么当一个文件很大的时候怎么办呢?书中说了两种方法,第一种:i节点的最后 一个磁盘地址不指向数据块,而是指向另一个包含磁盘块地址的块的地址。第二种:可以有两个或多个包含磁盘地址的块。后面讨论。

目录的实现

目录系统的主要功能是把ASCII文件名映射成定位文件数据所需的信息。
文件属性存放在目录项中,这是一个固定大小的目录项列表,每个文件在其中拥有一项,其中包含一个文件名、一个文件属性结构以及用以说明磁盘块位置的一个或多个磁盘地址。
对于采用i节点的系统,还存在另一种方法,把文件属性放在i节点中而不是目录项中,在这种情况下,目录项会更短,Unix就是采用这种方法,Windows采用上一种方法。
现代操作系统都支持可变长度的文件名,那么这是如何实现的呢,一种最简单的方法,用一个固定的大一点的空间来存放文件名,这可以实现,但是很明显这太浪费空间了。另一种方法是把目录项分成三个部分,以目录项长度开始,然后是固定格式的文件属性数据,接着就是具体的文件名。这个文件名部分的长度是动态的,但是必须是字对齐的。这种方法有一个缺点,文件项被移除后就会留下许多长度不一的间隙,而新添加的文件不一定正好适合这个间隙。还有一种方法是目录项自身有固定长度,文件名放置在后面的堆中,将指向文件名的指针存放在对应的目录项中,每当有文件添加或删除时只需要调整堆就可以了。
下面一个问题就是关于通过给定文件名查找目录项的方法。线性查找太慢,散列表很快,缓存也是一个很好的方案。

共享文件

用户之间常常需要共享文件夹来进行合作,将B的一个文件的目录项复制到A的目录下,这样A和B就可以共享文件夹了,但是如果A向这个共享文件中添加了内容,占用了新的磁盘块,这种变化只会反应到A下面的目录项中,而B并不知道,这就违背了共享的目的。有两种解决方案。在第一种解决方案中,一个文件用到的磁盘块的地址不列入目录项中,而是存在一个小型的数据结构中,目录中有一个指针指向这个小型的数据结构,在UNIX中,这个小型数据结构就是i节点。第二种方法是通过建立一个link文件,这个文件里面包含了它所连接的文件的路径名。
两种方法都有问题。
对于i节点法,C作为文件的所有者,B作为文件的另一个共享者,只有C可以删除文件,如果C删除了文件,那么其i节点将变成一个无效节点(或者在以后被重新分配),虽然C的目录项删除了,但是B的目录项还存在,所以B将有一个目录项指向一个错误的文件,有人可能会说,在i节点中保存一系列指针用来指向目录项,当文件被删除时,就通过这些指针来把这些目录也删除,但是,这是行不通的,因为i节点可能和无数个文件关联。唯一能做的就是将C目录项删除,并将i节点中的连接数计数器置为1,直到计数器变成0(没有目录项与之关联了)时,这个i节点才会被重新分配。
对于符号链接,这种方法需要额外的开销,必须读取包含路径的文件,然后进行扫描直到找到i节点。必须占用额外的i节点与磁盘块来存储链接路径(优化考虑,短路径可以存放在i节点中),
共有的缺点,如果一个文件有两个或多个路径,那么在复制的时候,如果复制的内容包含了多个指向同一文件的目录项,那么文件就会被复制多次。

日志结构文件系统

随着科技的发展,CPU的速度越来越快,RAM容量越来越大,磁盘高速缓存迅速增加,访问磁盘的操作很大一部分直接是用在了高速缓存上,所以花在磁盘写操作上的时间将是重头。而且写一次磁盘将会有诸如寻道、旋转延迟等十分耗时的操作。
基于以上事实,LFS的设计者实现了一种新的文件系统,其基本思想是将磁盘结构抽象为一个日志,每隔一段时间,或是有特殊的需要时,被缓存在内存中的所有未决的写操作都被放到一个单独的段中,将来一次性写入磁盘,这就是相当于将同步的小量数据操作变为异步的大量数据操作。
在LFS设计中也有i节点这种数据结构,但是在这里,i节点是分散在磁盘各处的。这里有一张i节点图,通过这张图可以定位到对应的i节点,这张图保存在磁盘中,但运行时,这张图的常用不分也存在于内存中。
为了进行管理,LFS有一个清理线程,该文件周期性地扫描日志进行磁盘压缩,该线程首先读日志中的第一段的摘要,检查有哪些i节点和文件,然后该节点查看当前i节点图,判断该i节点是否有效,以及文件块是否在使用中,如果没有使用,则该信息被丢弃,如果仍然在使用,那么i节点和块就进入内存等待被写回下一个段,接着原来的段被标记为空闲,以便日志可以用它来存放新的数据。用这种方法,清理线程遍历日志,整理磁盘,保证日志中文件的更新与不重复。
这种管理方式的复杂性挺大,因为要及时定位与更新,这是一个很复杂的工作。

日志文件系统

日志结构文件系统虽然很好,但是由于它与现有系统不兼容,所以它的推广受到阻碍,但是它的内在的一个思想,即面对出错的鲁棒性,却可以被其它文件系统所借鉴。当计算机在完成一些无法间断(间断会有一些破坏性的后果)的操作的时候却由于系统崩溃而无法完成时,系统中有一个日志用来记录接下来要做什么,这个日志存在磁盘中,也就是说,系统的操作总是在磁盘中有预先记录的,要不然它不会进行。重启后,计算机会执行上次由于崩溃而没有完成地操作,这个操作可以重复进行多次。Windows的NTFS,Linux的ext3,都利用了这种日志思想。

虚拟文件系统

多个文件系统并存,统一提供一个上层调用接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值