现代操作系统之文件系统(中)

来源:互联网 发布:淘宝汽车超人假机油 编辑:程序博客网 时间:2024/05/20 19:29

文件系统的实现

文件系统布局

文件系统存放在磁盘上,多数磁盘划分为一个或多个分区,每个分区中有一个独立的文件系统。磁盘的0号山区成为主引导记录(MBR),用来引导计算机。在MBR的结尾是分区表,该表给出了每个分区的起始和结束地址。表中的一个问去被标记为活动分区。在计算机被引导式,BIOS读入并指向MBr,MBR做的第一件事就是确定活动分区,读入它的第一个块,成为引导块,并执行之。引导块中的程序将装载该分区的操作系统。为统一起见,每个分区都从一个启动块开始,即使它不含有一个可启动的操作系统。

超级块(引导块之后)包含文件系统的所有关键参数,在计算机启动时,或者在该文件系统首次被使用时,把超级块读入内存。超级块中典型信息包括:确定问价系统类型的魔数\文件系统中数据块的输了以及其它重要的管理信息。

P153

文件的实现

连续分配

连续分配有两大优势,首先,实现简单,记录每个文件用到的磁盘块简化为朱旭记住两个数字即可——第一块的磁盘地址和文件的块数。

其次操作性能较好,因为在单个操作中就可以从磁盘上读出整个文件。只需要一次寻找。之后不再需要寻道和旋转延迟,所有,数据以磁盘全带宽的速率输入。可见连续分配实现简单而且具有较高的性能。

但是连续分配方案随着时间推移磁盘会变得零碎。

压缩磁盘代价高昂。

在CD-ROM中,连续分配方案是可行的,因为所有文件大小都事先知道大小,并且后续不发生变化。


链表分配

为每个文件构造磁盘块链表。每个块的第一个字作为指向下一块的指针,块的其他部分存放数据。

其优势在于不会因为磁盘碎片浪费存储空间(最后一块除外)

但是,尽管顺序访问非常方便,但是随机读取会很缓慢。

此外,每个磁盘块存储数据的字节数不再是2的整数次幂,因此降低了系统的运行效率,因为很多程序是以2的整数次幂来读写磁盘块的。


在内存中采用表的链表分配

如果取出每个磁盘块的指针字,把它放在内存的一个表中,就可以解决上述链表的不足。
内存中这样一个表格被称为文件分配表。(FAT)

按这类方式组织,整个块都可以存放数据。今儿,随机存取也容易得多。(依旧是链的方法,但是整个链表都在内存中,无需再进行磁盘操作)
无论文件有多大,在目录项中只要记载一个起始块号就可以找到文件全部的块。

其缺点主要说必须把整张表都存放在内存中。
FAT显然对于打磁盘来说不大合适。

i节点

给每个文件赋予一个叫i节点的数据结构,其中列出了文件属性和文件块的地址。

i节点机制需要在内存中存在一个数组,其大小正比于可能要同时打开的最大文件个数。

当文件大小超过i节点可容纳的数目后,则可以让最后一个磁盘地址不指向数据块,而是指向一个包含磁盘块的地址。
更高级的方法为可以有两个或更多更包含地址块的块,或者指向其他存放地址的磁盘块的磁盘块


目录的实现

在读文件前,必须先打开文件。打开文件时,操作系统利用用户给出的路径名找到相应目录项,目录项中提供了查找文件磁盘块所需要的信息。
目录系统的主要功能是把ASCII文件名映射成定位文件数据所需的信息。


文件属性可以直接存储在目录项中,在这种设计中,目录中有一个固定大小的目录项列表,每个文件对应一项,其中包含一个(固定长度)文件名,一个文件属性以及用以说明磁盘快位置的一个或多个磁盘地址(至某个最大值)


在采用i节点的系统,可以把文件属性存放在i节点中而不是目录项中。在这种情形下,目录项会更短:只有文件名和i节点号。

以上两种方法分别对应windows和UNIX


另一种替代方案是放弃所有目录大小都一样的想法,在这种方法中,每个目录项有一个固定部分,这个固定部分通常以目录项长度开始,后面是固定格式的数据,通常包括所有者等属性。
该方法的缺点是,当移走文件后,就引入了一个长度可变的空隙,而下一个进来的文件不一定正好适合这个空隙。

处理可变长度文件名字的另一种方法是,使目录项自身都有固定长度,而将文件名防止在目录项后面的堆中。
在处理文件名时页面故障仍旧会发生,另一个小优点是文件名不再需要从字的边界开始。


加快目录查找速度的一个方法是给每个目录中使用散列表。
使用散列表的有点是查找非常迅速,其缺点是需要复杂的管理。只有在预计系统中的目录经常会有成百上千个文件时,才把散列方案真正作为备用方案考虑。

一种完全不同的加快大型目录查找速度的方法是,将查找结果存入高速缓存。



共享文件

让一个文件出现在多个目录下有两种方法

第一种是磁盘块不列入目录,而是列入一个与文件本身关联的小型数据结构中。目录将指向这个小型数据结构,这个UNIX中这个小型数据结构是i节点。

第二种解决方案是通过然系统建立一个类型为LINK的新闻界,并把该文件与之前的文件链接,新文件中只包含他所连接的文件的路径名。这种方法成为符号链接。

每种方法都有缺陷,第一种,如果删除文件并清楚i节点,则另一目录有一个文件指向一个无效的i节点。如果该i节点分配给新的文件,则链接会指向一个错误的文件。
系统可以通过i节点的计数知道该文件依旧被引用,但是没有办法找到指向该文件的全部目录项以删除他们。指向目录的指针不能存于i节点,原因是可能有无数个目录,
所以唯一能做的就是删除文件,并将i节点计数减一。只有当技术变为0的时刻,才会删除这个变量。

对于符号连接,以上问题不会发生,引文只有真正的文件所有者才有一个指向i节点的指针。当文件所有者删除文件时,该文件被销毁,以后若通过符号连接访问则会失败,因为系统找不到该文件。

符号链接的问题是需要欸外的开销,必须读取包含路径的文件,然后要一层一层扫描路径。

还有一个链接带来的问题,上述两种方法都有:查找一指定目录及其子目录的全部文件的程序将多次定位到被连接的文件。


日志结构文件系统

如果写操作之前司机,则可能在文件系统中造成严重的不一致。正因为如此,i节点的写操作一般是立即完成的。

所以有一种思路是将整个磁盘结构化为一个日志。每个一段时间,或是有特殊需要时,被缓冲在内存中的所有未决的写操作都被放到一个单独的段中,作为在日志末尾的一个邻接段写入磁盘。

总而言之,所有的写操作最初都被缓冲在内存中,然后周期性地吧所有已缓冲的血作为一个单独的段,在日志的末尾处写入磁盘。要打开一个文件,则首先要从i节点图中找到文件的i节点。一旦i节点定位只有就可以找到相应的块的地址。所有的块都放在段中,在日志的某个地方。

lFS有一个清理线程,会周期性扫描日志并进行磁盘压缩。

日志的管理并不简单,因为当一个文件跨ibei协会到一个新段的时候,该文件的节点(在日志的某个地方)必须首先定位,更新,然后放到内存中准备协会到下一个段中,i节点必须更新向新的位置。


日志文件系统

基本思想是保存一个用于记录系统下一步要做什么的日志。这样当系统在完成它们即将完成的任务前崩溃时,重新启动后,可以通过查看日志,获取崩溃前计划完成的任务,并完成它们,这样的文件系统被成为i日志文件系统。

当释放i节点而没有成功删除文件时,这个i节点可能很快被分配到新的文件,这样可能有两个或更多的文件分享同样的磁盘块。

为了让日志文件系统工作,被写入日志的操作必须是幂等的,他意味着只要有必要,他们可以被执行很多次,并不会带来破坏。

日志文件系统必须安排他们的数据结构和可写入日志的操作以让他们都是幂等的。在这些条件下,崩溃操作可以被快速安全地试试。

一个文件系统可以引入u数据库原子事务的概念。

NTFS有一个扩展的日志文件系统,并且它的结果几乎不会因系统崩溃而受到破坏。


虚拟文件系统

即使同一台计算机上同一个操作系统下,也会使用许多不同的文件系统。

从用户的观点来看,那只有一个文件系统层级。而事实上可以有多种(不相容的)文件系统,对于用户和进程是不可见的。

虚拟文件系统(VFS)的关键的思想是抽象出所有文件系统部都共有的文风,并且将这部分代码放在单独的一层,该层调用底层的世纪文景系统来具体管理数据。

VFS有两个不同的接口:上岑给用户进程的接口和下层给实际文件系统的接口。

VFS设计是只要实际的文件系统提供VFS需要的功能,即使他们用C语言而不是C++编写。

当系统启动时,当装在其它文件系统时,不管在启动时还是在操作过程中,他们也必须在VFS中注册,当一个文件系统注册时,他做的最基本的工作就是提供一个包含VFS搜需要的函数地址的列表,可以是一个长的调用矢量(表),或者是许多这样的矢量(如果VFS需要),每个VFS对线一个。因此,当一个文件系统在VFS注册,VFS就知道如何从它哪里杜宇一个块——它也知道从文件系统提供的每一个其它功能。


当进程用文件描述符进行一个读操作,VFS通过进程表和文件描述符确定vijed的位置,并跟随指针指向功能表(所有这些都是请求文件所在的世纪文件系统中的地址)
原创粉丝点击