第11章 文件系统实现

第11章 文件系统实现

11.1 文件系统结构

磁盘可提供大多数外存,以维护文件系统。为实现这个目的,磁盘具有两个优势:

  • 磁盘可以原地重写。
  • 可以直接访问它包含信息的任何块。

为了提高 I/O 效率,内存和磁盘之间的 I/O 传输以块(block)为单位执行。每个块具有一个或多个扇区。文件系统本身由许多不同的层组成:

  • 应用程序
  • 逻辑文件系统
  • 文件组织模块
  • 基本文件系统
  • I/O 控制
  • 设备

I/O 控制(I/O control)层包括设备驱动程序和中断处理程序,以在主内存和磁盘系统之间传输信息。
基本文件系统(basic file system)只需向适当设备驱动程序发送通用命令,以读取和写入磁盘的物理块。
文件组织模块(file-organization module)知道文件及其逻辑块以及物理块。
逻辑文件系统(logic file system)管理元数据信息(包括文件系统的所有结构,而不包括实际数据(或文件内容))。

11.2 文件系统实现

11.2.1 概述

在磁盘上,文件系统可能包含如下信息:如何启动存储在那里的操作系统、总的块数、空闲块的数量和位置、目录结构以及各个具体文件等。这里简述如下:

  • (每个卷的)引导控制块(boot control block)可以包含从该卷引导操作系统的所需信息,如果磁盘不包含操作系统,则这块的内容为空。
  • (每个卷的)卷控制块(volume control block)包括卷(或分区)的详细信息,如分区的块的数量、块的大小、空闲块的数量和指针、空闲的 FCB 数量和 FCB 指针等。
  • (每个文件系统的)目录结构,用于组织文件。
  • 每个文件的 FCB 包括该文件的许多详细信息。它有一个唯一的标识号,以便与目录条目相关联。

内存中的信息用于管理文件系统并通过缓存来提高性能。这些数据在安装文件系统时被加载, 在文件系统操作期间被更新,再卸载时被丢弃。这些结构的类型可能包括:

  • 内存中的安装表(mount table)包含每个安装卷的有关信息。
  • 内存中的目录结构的缓存含有最近访问目录的信息。
  • 整个系统的打开文件表(system-wide open-file table)包括每个打开文件的 FCB 的副本以及其他信息。
  • 每个进程的打开文件表(per-process open-file table)包括一个指向整个系统的打开文件表中的适当条目的指针,以及其它信息。
  • 当对磁盘读出或写入时,缓冲区保存文件系统的块。

系统调用 open() 首先会去整个系统的打开文件表中搜索对应文件名,如果存在,则在单个进程的打开文件表创建一个条目,并让其指向现有整个系统的打开文件表;如果不存在则根据给定文件名搜索目录结构(通常在缓存中),找到文件后,将它的 FCB 复制到内存的整个系统的打开文件表,并在单个进程的打开文件表中创建一个条目,指向整个系统的打开文件表的对应位置。调用 open() 返回单个进程的打开文件表的适当条目的一个指针,以后,所有文件操作通过这个指针执行。

11.2.2 分区与安装

磁盘布局有多种,具体取决于操作系统。一个磁盘可以分成多个分区,或者一个卷可以跨越多个磁盘的多个分区。引导信息可以存储在各自分区中。根分区(root partition),包括操作系统内核和其他系统文件,在启动时安装。其他卷可以在引导时自动安装或以后手动安装。

11.2.3 虚拟文件系统

现代操作系统必须同时支持多种类型的文件系统,但是操作系统如何才能将多个类型的文件系统集成到目录结构中?一种明显但欠佳的方法是为每种类型编写目录和文件程序。取而代之的是,大多数操作系统,包括 UNIX 采用面向对象的技术来简化、组织和模块化实现。采用这种方法允许不同文件系统类型可通过同样结构来实现,这也包括网络文件系统类型,如 NFS。数据结构和程序用于隔离进本系统调用的功能与实现细节。文件系统的实现由三个主要层组成。

  • 第一层为文件系统接口,基于 open()、read()、write() 和 close() 调用及文件描述符。
  • 第二次称为虚拟文件系统(Virtual File System,VFS)层。VFS 层提供两个重要功能:通过定义一个清晰的 VFS 接口,将文件系统的通用操作和实现分开。它提供了一种机制,以唯一表示网络上的文件。因此 VFS 区分本地文件和远程文件,根据文件系统类型进一步区分本地文件。VFS 根据文件系统类型调用特定文件类型的操作以便处理本地请求,通过调用 NFS 协议程序来处理远程请求。

实现文件系统类型或远程文件系统协议的层属于架构的第三层。

11.3 目录实现

目录分配和目录管理的算法显著影响文件系统的效率、性能和可靠性。

11.3.1 线性列表

实现最简单的方法是,采用文件名称和数据块指针的线性列表。这种方法编程简单,但执行费时。目录条目的线性列表的真正缺点是,查找文件需要线性搜索。

11.3.2 哈希表

哈希表根据文件名称获得一个值,并返回线性列表内的一个元素指针。它大大减少了目录搜索的时间,但必须做出一些规定来避免碰撞。

11.4 分配方法

磁盘空间分配的主要常用方法有三个:连续、链接和索引。虽然有些系统对这三种方法都支持,但更为常见的是,一个系统只对同一文件系统类型的所有文件采用一种方法。

11.4.1 连续分配

连续分配(contiguous allocation)方法要求,每个文件在磁盘上占有一组连续的块。用于访问连续分配文件的所需寻道数最小;在确实需要寻道时所需的寻道时间也最小。文件的连续分配可以用首块的磁盘地址和连续的块数来定义。每个文件的目录条目包括起始块的地址和该文件所分配区域的长度。连续分配支持顺序访问和直接访问。连续分配存在的问题是为新文件找到空间。然后还存在着外部碎片的问题。为了防止外部碎片引起的大量磁盘空间的浪费,将整个文件系统复制到另一个磁盘。原来的磁盘变成空的。从而创建了一个大的连续空闲空间,然后通过这个大的连续空闲空间采用连续分配方法,将这些文件复制回来。这种方案将所有空闲空间有效合并(compact)起来,这种合并的代价是时间。连续分配的另一个问题是确定一个文件需要多少空间。当创建一个文件时,需要找到并分配它所需空间的总数。一般来说,输出文件的大小可能难以估计。如果分配空间太小,文件无法扩展,如果分配太大,会造成相当大的空间浪费。为了最小化这些缺点,有些操作系统使用连续分配的修正方案,当一开始分配的空间不够时,会添加另一块连续空间(称为扩展(extent))。然后文件块的位置就记录为:地址、块数、下一扩展的首块的地址。

11.4.2 链接分配

链接分配(linked allocation)解决了连续分配的所有问题。采用链接分配,每个文件是磁盘块的链表;磁盘块可能会散布在磁盘的任何地方。目录包括文件第一块和最后一块的指针。要创建一个新文件,只需在目录中增添一个新的条目。每个目录条目都会有文件首个磁盘块的一个指针。

链接分配的缺点是,只能有效用于顺序访问文件。另一个缺点是指针所需的空间。这个问题的通常解决方案是,将多个块组成(cluster),并按簇而不是按块分配。这样指针所占的磁盘空间的百分比就要小得多。这种方法的代价增加了内部碎片,如果一个簇而不是块没有完全使用,则会浪费更多的空间。

还存在可靠性的问题。文件时通过散布在磁盘上的指针链接起来的,如果指针丢失或损坏那么文件将会错误。一个不完全的解决方案是使用双向链表;另一个是,每块存储文件名称和相对块号。但这些方案为每个文件增加了更多额外开销。

链接分配的一个重要变种是文件分配表(File_File-Allocation Table,FAT)的使用。

11.4.3 索引分配

链接分配解决了连续分配的外部碎片和大小声明的问题,然而,在没有 FAT 时,链接分配不能支持高效的直接访问(???)。 索引分配(indexed allocation)通过将所有指针放在一起,即索引块(index block),解决了这个问题。每个文件都有自己的索引块,这是一个磁盘块地址的数组。索引块的第 i 个条目指向文件的第 i 块。创建文件时,索引块的所有指针都设为 null。当首次写入第 i 块时,先从空闲空间管理器中获得一块,再将其地址写到索引块的第 i 个条目。每次必须分配一个完整的索引块,因此索引块指针的开销通常大于链表分配的指针开销。这样的话,索引块应为多大?每个文件必须有一个索引块,因此需要索引块尽可能小,但如果太小,它不能为大的文件存储足够多的指针。可采用如下机制解决此问题:

  • 链接方案:一个索引块通常为一个磁盘块,为了支持大的文件,可以将多个索引块链接起来。
  • 多级索引:通过第一级索引块指向一组第二级索引块,再采用这个块查找所需的数据块。这种做法可以持续到第三级或第四级。
  • 组合方案:基于 UNIX 文件系统,将索引块的前几个(如15)指针存在文件的 inode 中,这些文件的前12个指向直接块(direct block)(包含存储文件数据的块的地址),因此,不超过12个块的文件不需要单独的索引块。接下来的三个指针,分别指向一级间接块(single indirect block)、二级间接块、三级间接块。

11.4.4 性能

上面的分配方法在存储效率和数据块访问时间上有所不同。这两者在操作系统选择合适的方法来实现时都是重要的依据。连续分配支持直接访问的文件,链接分配支持顺序访问的文件。索引分配更加复杂,如果索引块不在内存,需要先读取索引块,再读取所需的数据块。对于两级索引,可能需要读两次索引块;对于极大的文件,需要读取完所有的索引块,最后才能读入所需的数据块。有的系统将连续分配和索引分配组合起来:对于小文件(只有3块或4块的)采用连续分配;当文件增大时,自动切换到索引分配。

11.5 空闲空间管理

11.5.1 位向量

通常,空闲空间列表按位图(bit map)或位向量(bit vector)来实现。每块用一个位来表示,如果这块是空闲的,位为1;如果已经分配,位为0。这种方法的主要优点是,在查找磁盘上的第一个空闲块和 n 个连续的空闲块时相对简单和高效。不过除非整个位向量都保存在内存中(并时而写入磁盘以便恢复),否则位向量就低效。

11.5.2 链表

空闲空间管理的另一种方法是,将所有空闲磁盘块用链表链接起来,将指向第一空闲块的指针保存在磁盘的特殊位置上,同时也将其缓存在内存中。这个第一个块包含下一个空闲磁盘块的指针。这种方法低效;在遍历整个列表时,需要读入每块,从而需要大量的 I/O 时间。

11.5.3 组

空闲列表方法的一个改进是,在第一个空闲块中存储 n 个空闲块的地址。这些块的前 n-1 个确实为空,最后一块包含另外 n 个空闲块的地址,如此继续。大量空闲块的地址可以很快找到,这一点有别于标准链表方法。

11.5.4 计数

这种方法利用率这样一个事实:通常,多个连续块可能需要同时分配或释放,尤其是采用连续区域分配算法或采用簇来分配空间更是如此。因此不是记录 n 个空闲块的磁盘地址,而是记录第一块的地址和紧跟第一块的连续空闲块的数量 n。这样空闲空间列表的每个条目包括磁盘地址和数量。虽然每个条目会比原来需要更多空间,但是表的总长度会更短,只要连续块的数量通常大于1。这些条目可以存储在平衡树而不是链表中,以便于高效查找、插入和删除。

11.5.5 空间图

实质上,日志加平衡树就是空闲列表。

11.6 效率和性能

由于磁盘是计算机主要部件中最慢的,磁盘往往成为系统性能的主要瓶颈。(这一部分没看太懂??????????)

11.7 恢复

系统崩溃可能导致磁盘文件系统数据结构(如目录结构、空闲块指针喝空闲 FCB 指针)的不一致;除了崩溃,文件系统实现的错误、磁盘控制器,甚至用户应用程序都能损坏文件系统。下面讨论文件系统不同的处理损坏的方法,它取决于文件系统的数据结构和算法。

11.7.1 一致性检查

一致性检查程序(consistency checker),如 UNIX 的系统程序 fsck,比较目录结构的数据和磁盘的数据块,并试图修复发现的不一致。分配和空闲空间管理的算法决定了检查程序能够发现什么类型等问题,及其如何成功修复问题。例如,如果采用链接分配,从任何块到其下一块有链接,则从数据块来重建整个文件,并且重建目录结构。

11.7.2 基于日志的文件系统

11.7.3 备份和恢复

可采用系统程序将磁盘数据备份(backup)到另一存储设备,单个文件或整个磁盘的恢复,只需要从备份中恢复(restore)数据就可以了。一个典型的备份计划可能如下:

  • 第1天:将所有磁盘文件复制到备份介质,这称为完全备份(full backup)。
  • 第2天:将所有从第1天起更改的文件复制到备份介质。这称为增量备份(incremental backup)。
  • 。。。
  • 第 N 天:将所有从第 N-1 天起更改的文件复制到备份介质。再返回到第1天。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值