首页 > 代码库 > 操作系统概念 文件系统实现

操作系统概念 文件系统实现

磁盘提供大量的外存空间来维持文件系统。磁盘的下述两个特点使得其成为存储多个文件的方便介质。

  • ①可以原地重写;
  • ②可以直接访问磁盘上的任意一块信息。

为了提供对磁盘的高效且便捷的访问,操作系统通过文件系统来轻松地存储、定位、提取数据。文件系统有两个设计问题。

  • ①定义文件系统对用户的接口
  • ②创建数据结构和算法来将逻辑文件系统映射到物理外存设备上。

文件系统本身通常由不同的层组成。如下图所示的是一个分层设计的简单例子。

 

技术分享

 

  • I/O控制 
    • 由设备驱动程序和中断处理程序组成,实现内存与磁盘之间的信息传递
  • 基本文件系统 
    • 向合适的设备驱动程序发送一般命令就可对磁盘上的物理块进行读写
  • 文件组织模块 
    • 知道文件及其逻辑块和物理块。
    • 空闲空间管理器
  • 逻辑文件系统 
    • 管理元数据:文件系统的所有结构数据,而不包括实际数据(或文件内容)
    • 根据给定符号文件名来管理目录结构
    • 逻辑文件系统通过文件控制块(FCB)来维护文件结构

FCB的典型结构如下图所示 

技术分享

 

文件系统实现(File System Implementation )

实现文件系统要使用多个磁盘和内存结构。虽然这些结构赢操作系统和文件系统而异,但是还是有其规律性的。

实现文件系统的结构和操作如下:

  • 磁盘结构;
  • 内存中的文件系统结构;
  • 分区与安装
  • 虚拟文件系统

磁盘结构

  • 引导控制块(卷)(boot control block\Volume) 
    • 包含启动OS的控制信息
    • UFS 中称为引导块(boot block ) 
      • 通常为分区的第一块。如果该分区没有OS,则为空
    • NTFS中称为分区引导扇区(partition boot sector)
  • 卷控制块(卷)( Volume control block (/volume))

    • 包含卷的详细信息,包括 
      • 块数和块的大小;
      • 空闲块的数量和指针;
      • 空闲FCB的数量和指针。
    • UFS称为超级块 Superblock , NTFS 称为 主控文件表master file table 。
  • 目录结构

    • 用来组织文件
    • UFS ,包括文件名和关联的inode 号
    • NTFS,主控文件表(master file table );
  • 文件控制块(FCB):包括很多文件信息,如文件许可、拥有者、大小和数据块的位置等,详情见上文示例。 
    • UFS中, 索引节点( inode) ;
    • NTFS中,主控文件表; 
      • 采用关系数据库结构, 记录/文件

内存中的文件系统结构

  • 安装表 
    • 包含所有安装分区的信息
  • 目录结构快表 
    • 保存近来访问过的目录信息(对安装分区的目录,可以包括一个指向分区表的指针)
  • 系统范围的打开文件表 
    • 包括每个打开文件的FCB拷贝和其他信息
  • 单个进程的打开文件表 
    • 包括一个指向系统范围内已打开文件表中合适条目和其他信息的指针 
      • 文件描述符(file descriptor, Linux/UNIX)
      • 文件句柄(file handle, Windows)

下图总结了文件系统实现的 操作结构。 

技术分享

 

分区与安装

磁盘布局赢操作系统而异。一个磁盘可分成多个分区,或者一个卷可以跨越多个磁盘上的数个分区。

分区可以是“生的”(raw),即没有文件系统,或是“熟的”(cooked)即含有文件系统。生的分区用于没有合适文件系统的地方。如:Unix中的交换区,因为它不使用文件系统而是使用自己的磁盘格式。

引导信息能存在各个分区中,并且有自己的格式。因为在引导时,系统并没有文件系统设配驱动程序,所以不能解释文件系统格式。它通常为一组有序块并且作为二进制镜像文件读入内存。引导信息除了包括如何启动一个特定操作系统外,还可以有其他指令。(如BootManager bootstar 8.3,Linux GRUB, GRUB - GRand Unified Bootloader)

根分区(root partition)包括操作系统内核或其他系统文件,在引导时装入内存。其他分区根据不同操作系统可以在引导时自动装入或在此之后手动装入。

  • /root, /boot
  • 文件系统安装表(file system mount table)

虚拟文件系统

  • 虚拟文件系统(VFS)提供了一种面向对象的方法来实现文件系统
  • VFS功能 
    • 通过定义VFS 接口将一般文件系统操作与实现分离;
    • 为网络中唯一表示一个文件提供一种机制(by vnode)
  • VFS允许在不同类型的文件系统上采用同样的系统调用接口(API)
  • API是针对VFS的接口,而非对任何特定类型的文件系统

 

技术分享

 

第一层为文件系统接口,包括,open()、read()、write()和close()调用以及文件描述符。

第二层称为虚拟文件系统(VFS)层,它有两个目的:

  • VFS层通过定义一个清晰的VFS接口,以将文件系统的通用操作和具体实现分开。多个VFS接口的实现可以共存在同一台机器上,它允许访问已经装再本地的多个类型的文件系统
  • VFS提供了在网络上唯一标示一个文件的机制。

目录实现(Directory Implementation)

目录分配和目录管理算法的选择对文件系统的效率、性能和可靠性有很大的影响。

线性列表

最为简单的目录实现方法是使用存储文件名和数据块指针(数组、链表等)的线性列表,这种方法编程简单但是运行时较为费时。

目录条目的线性列表的真正缺点是采用线性搜索来查找特定条目。 
事实上,许多操作系统采用软件缓存来存储最近访问过的目录信息。缓存命中避免了不断地从磁盘读取信息,排序列表可以使用二分搜索,并减少平均搜索时间。

Hash表

采用Hash数据结构的线性表

  • 减少了目录搜索时间,插入和删除也较为简单。
  • 不过需要一些机制来避免碰撞(两个文件名哈希到相同的位置) 
    哈希表的最大困难是:其固定的大小和哈希函数对大小的依赖性

分配方法(Allocation Methods)

  • 目标 
    • 有效使用磁盘空间;
    • 快速访问文件。
  • 常用的分配方法有以下三类 
    • 连续分配
    • 链接分配
    • 索引分配

连续分配 (contiguous allocation)

连续分配方法要求每个文件占据磁盘上的一组连续的块。

特点:

  • 简单 - 只需要记录文件的起始位置(块号)及长度。
  • 访问文件很容易,所需的寻道时间也最少 
    • 顺序访问;
    • 直接访问。
  • 存在的问题 
    • 为新文件找空间比较困难 
      • 首次,最佳,最差
    • 文件很难增长

 

技术分享

 

逻辑地址到物理地址的映射方法如下:

  • 逻辑地址 / 块大小 = 商, 余数 
    LA512=Q??????R

访问的块 = Q + 起始地址(base) 
块中的位置 = R

基于扩展的连续分配方法:

  • 许多新的文件系统采用一种修正的连续分配方法
  • 扩展是一个连续的磁盘块 
    • 文件分配时,将扩展分配给文件
    • 另一个大的连续空间
    • 一个文件包括一个或多个扩展
    • 需要一个指向下一个扩展的指针
  • 文件块的位置就成为开始地址、块数、加上一个指向下一扩展的指针。
  • 分配磁盘块时,在扩展中进行

链接分配 (linked allocation)

链接分配解决了连续分配的所有问题。

采用链接分配,每个文件是磁盘块的链表:

  • 磁盘块分布在磁盘的任何角落。
  • 每个目录条目都有一个指向文件第一块的指针。
  • 该指针初始化为 nil (表尾指针的值)以标识空文件。

 

技术分享

 

  • 优点: 
    • 简单 - 只需起始位置
    • 文件创建与增长容易
  • 缺点: 
    • 不能随机访问
    • 块与块之间的链接指针需要占用空间 
      • 簇:将多个连续块组成簇,磁盘以簇为单位进行分配
    • 存在可靠性问题

 

技术分享

 

文件分配表(FAT)

每个分区的开始部分用于存储该FAT表。

每个磁盘块在该表中有一项,该表可以通过块号来索引。

目录条目中含有文件首块的块号码。根据块号码索引的FAT条目包含文件下一块的地号码。这种链会一直继续到最后一块,该块对应FAT条目的值为文件结束值。未使用的块用0值来表示。

为文件分配一个新的块只要简单地找到第一个值为0的FAT条目,用新块的地址替换前面文件结束值,用文件结束值替代0。

如果不对FAT采用缓存,FAT分配方案可能导致大量的磁头寻道时间。但通过读入FAT信息,磁盘能找到任何块的位置,从而实现随机访问。

 

技术分享

 

索引分配(indexed allocation)

  • 将所有的数据块指针集中到索引块中 
    • 索引块中的第i个条目指向文件的第i块。
    • 目录条目包括索引块的地址

 

技术分享

 

  • 每个文件都有索引块; 
    • 磁盘块地址的数组
  • 索引分配支持直接访问,且没有外部碎片问题
  • 索引块本身可能会浪费空间 
    • 链接方案:一个索引块通常为一个磁盘块。对于大文件,可以将多个索引块链接起来。
    • 多层索引:类似于内存的间接寻址方式(一级、二级间接…)

 

技术分享

 

 

技术分享

 

空闲空间管理(Free-Space Management )

位向量(Bit vector)(n块)

 

技术分享

 

  • bit[i] = 1  block[i]空闲
  • bit[i] = 0  block[i]被占用

第一个空闲块号: 

×01

 

  • 位向量需要额外的空间 
    • 设块大小为212 字节
    • 磁盘大小为230字节 (1GB)
    • N = 230/212=218 (即32K bytes)
  • 容易得到连续的文件
  • 分配与回收过程 
    • 分配过程
    • 回收过程

空闲表法

 

技术分享

 

链表(空闲链表)

将所有空闲磁盘块用链表连接起来,并将指向第一空闲块的指针保存在磁盘的特殊位置,同时也缓存在内存中。

不易得到连续空间

没有空间浪费

 

技术分享

 

分组(成组链接)

  • 将n个空闲块的地址存在第一个空闲块中;
  • 最后一块包含另外n个空闲块的地址。

成组链接图如下所示 

技术分享

 

  • 分组(成组链接) 
    • 分配与回收过程
    • 分配过程
  • 回收过程 
    • 所需的保护
    • 指向空闲表的指针

所需的保护

  • 位映射 
    • 必须保存在磁盘上
    • 内存中的副本可能与磁盘上不相同;
    • 对于 block[i]不允许出现的情形:在内存中 bit[i] = 1,而在磁盘上 bit[i] = 0 。
  • 解决方法 
    • 设置磁盘上bit[i] = 1
    • 分配block[i]
    • 设置内存中 bit[i] = 1

效率和性能(Efficiency and Performance)

效率

效率依赖于

  • 磁盘分配与目录算法 
    • 预分配,簇
  • 文件目录项中保存的数据的类型 
    • 最近写/访问日期
  • 指针大小 
    • 212,232,264,2128

性能

性能有如下几点:

  • 磁盘缓冲 - 将最近使用过的块放在内存的某个地方
  • 马上释放与预先读取 - 优化顺序访问
  • 留出一块内存作为虚拟磁盘(或RAM磁盘)来提高个人计算机的性能

页缓存(page cache)

  • 页缓存使用虚拟内存技术,以将文件数据作为页而不是面向文件系统的块来缓存。
  • 内存映射I/O使用了页缓存
  • I/O通过文件系统再使用缓冲缓存

无统一缓冲缓存的I/O如下图所示

 

技术分享

 

采用了统一缓冲缓存的I/O则变化如下 

技术分享

 

不同的磁盘缓存位置

 

技术分享

 

恢复(Recovery)

  • 一致性检查 - 比较目录中的数据与磁盘中的数据块,以消除不一致性
  • 使用系统程序将数据从磁盘备份到其他存储设备(如磁盘,磁带) 
    • 增量备份
  • 从备份上恢复数据以恢复丢失的文件或磁盘

结构化日志的文件系统(Log-Structured File Systems)

    • 每个更新作为事务记录;
    • 所有的事务写到日志中 
      • 一旦写到日志中,就认定为确认的提交;
      • 但是FS可以不更新。
    • 事务异步写到FS中 
      • 当FS修改后,事务从日志中删除
    • 如果FS崩溃,在日志中的所有事务都要执行

操作系统概念 文件系统实现