Linux 虚拟系统文件交换器剖析
网络整理 - 06-28
Linux ® 的最显著特征是灵活性和扩展性,例如它的虚拟文件系统交换器(VFS)。您可以在各种设备上建立 文件系统,包括传统的硬盘 、USB flash 驱动、内存以及其他储存设备。您还可以在另一个文件系统环境中嵌入文件系统。探索导致 VFS 如此强大的因素,并了解 VFS 的主要接口和进程。
Linux 文件系统的灵活性和扩展性支持直接源于一组抽象接口。这组接口的核心就是虚拟文件系统交换器(VFS)。
VFS 为上层运用 程序提供一组标准接口,用于对不同的文件系统执行文件 I/O。这组接口在一个或多个底层设备上支持多个并发文件系统。另外,这些文件系统可以不是静态的,可以根据储存设备而变化。
VF 与 VFS
您还可以看到 VFS 还被定义为虚拟文件系统(virtual file system),但定义为虚拟文件系统转换器(virtual file system switch)更能说明其作用,因为虚拟层跨多个文件系统转换(即多路复用)请求。/proc 文件系统在这里带来很多的混淆,因为它通常也被称为虚拟文件系统。
例如,一个典型的 Linux 桌面在可用硬盘上支持 ext3 文件系统,并且在可用的 CD-ROM(或者称为 CD-ROM 文件系统 或 CDFS)上支持 ISO 9660 文件系统。因为 CD-ROM 是可以插入和移除的,所以 Linux 内核必须适应这些包含不同内容和结构的新文件系统。可以通过网络文件系统(Network File System,NFS)访问远程文件系统。在此时,Linux 还可以挂载来自本地硬盘的 Windows®/Linux 双引导系统的 NT File System (NTFS) 分区,并且能够向其读写数据。
最后,可移除的 USB flash 启动(UFD)是可以热插拔的,它构成另一个文件系统。概而言之,可以在这些设备中运用 同一组文件 I/O 接口,从而允许底层的文件系统和物理设备能够从用户中抽象出来(见图 1)。
图 1. 在不同文件系统和储存设备之间提供统一接口的抽象层
分层抽象
现在,我们向 Linux VFS 提供的抽象特征 添加一些具体的架构。图 2 从 VFS 的角度显示 Linux 结构的高级视图。在 VFS 之上的是标准的内核系统调用接口(SCI)。这个接口允许用户空间发出要求转换到内核的调用(在不同地址空间中)。在这个域中,调用 POSIX open 调用的用户空间运用 程序经过 GNU C 库(glibc)进入内核和系统调用去多元化(de-multiplexing)。最后,运用 sys_open 调用 VFS。
图 2. VFS 的分层架构
早期的 VFS 实现
Linux 并不是第一个包含虚拟层以支持通用文件模型的操作系统。早期的 VFS 实现包括 Sun 的 VFS(SunOS version 2.0,大约出现在 1985 年),以及 IBM 和 Microsoft® 的 “Installable File System” for IBM OS/2。这些虚拟化文件系统层的要领 为 Linux VFS 铺平了道路。
VFS 提供抽象层,从而将 POSIX API 与特定文件系统如何 实现该行为的细节分离开来。这里的关键之处是,不管底层文件系统是 ext3 还是 Btrfs,Open、Read、Write 或 Close API 系统调用都能正常工作。VFS 提供一个由底层文件系统(它们必须为各种 POSIX API 函数实现行为)继承的通用文件模型。另一个在 VFS 范围之外的深层抽象潜藏 了底层物理设备(可能是硬盘 、硬盘 分区、网络储存实体、内存或其他能够储存信息的媒介 —— 即使是暂时性的)。
除了从底层文件系统抽象文件操作的细节之外,VFS 还将底层块设备绑定到可用的文件系统。让我们看看 VFS 的内部结构及其工作原理。
VFS 的内部结构
在查看 VFS 子系统的总体架构之前,我们先看看所运用 的主要对象。这个小节探索了超块(superblock)、索引节点(或 inode)、目录条目(或 dentry)和文件对象。在这里,其他一些组成部分也很主要 ,比如缓存。不过我将在后面的总体架构中讨论它们。
超块
超块(superblock)是关于文件系统的高级元数据的容器。超块是存在于硬盘 上(实际上位于硬盘 的多个位置上,以提供冗余)的结构。它是处理硬盘 上的文件系统的基础,因为它定义文件系统的管理参数(例如,块的总数、空闲块和根索引节点)。
在硬盘 上,超块向内核提供关于硬盘 上的文件系统的结构的信息。在内存中,超块为管理活动的(已挂载)文件系统提供必要的信息和状态。因为 Linux 支持同时挂载多个并发文件系统,所以在一个列表中维护每个 super_block 结构(super_blocks 在 ./linux/fs/super.c 中定义,结构在 /linux/include/fs/fs.h 中定义)。
图 3 提供了超块及其元素的简化视图。super_block 结构是指封装了其他信息的许多其他结构。例如,file_system_type 结构维护文件系统的名称(比如 ext3)以及各种锁和函数,以获取和删除 super_block。file_system_type 对象由多见 的 register_file system 和 unregister_file system 函数管理(见 ./linux/fs/file systems.c)。super_operations 结构为读写节点和高级操作(比如重新挂载)定义大量函数。根目录条目(dentry)对象也缓存在这里,因为它是文件系统所在的块设备。最后,提供许多用于管理节点的列表,包括 s_inodes(列出所有节点的列表)、s_dirty(列出所有脏节点的列表)、s_io 和 s_more_io 以及 s_files(列出特定文件系统的所有打开文件的列表)。
图 3. super_block 结构及其元素的简化视图
留心 ,在内核内部,另一个称为 vfsmount 的管理对象提供关于已挂载的文件系统的信息。这些对象的列表引用超块,并定义挂载点、文件系统所在的 /dev 设备的名称以及其他高级附加信息。
索引节点(inode)
Linux 通过一个称为 inode(index node 的缩写)的对象管理文件系统中的所有对象。一个 inode 可以引用一个文件、目录或另一个对象的符号链接。留心 ,因为文件用于表示其他类型的对象(比如设备或内存),所以也运用 inode 来表示它们。
我在这里所指的 inode 是 VFS 层 inode(常驻 inode)。每个文件系统也包含一个位于硬盘 上的 inode,并且提供关于特定文件系统的特定对象的细节。
VFS inode 运用 slab 分配器执行 分配
。inode 由描述 inode、inode 内容和可能在 inode 上发生的各种操作的数据和操作组成。图 4 基本 展示了一个 VFS inode,该 inode 包含许多列表,其中一个列表指向引用该 inode 的 dentry。这里还包含对象级别的元数据,包括熟悉的操作时间(建立 时间、访问时间和修改时间)和所有者和权限数据(组 ID、用户 ID 和权限)。inode 引用它所允许的文件操作,大部分这些操作直接映射到系统调用接口(例如,open、read、write 和 flush)。inode 还引用特定于 inode 的操作(create、lookup、link 和 mkdir 等等)。最后,对于由地址空间对象表示的对象的数据,有一个管理结构。地址空间对象 是为 inode 管理页缓存中的各种页的对象。地址空间对象用于为文件管理页,也用于将文件部分映射到独立的进程地址空间。地址空间对象有自己的操作集(writepage、readpage 和 releasepage 等等)。
图 4. VFS inode 的简化图示
留心 ,可以在 ./linux/include/linux/fs.h 中找到所有这些信息。
目录条目(dentry)
文件系统的层次结构由 VFS 中的另一个称为 dentry 的对象管理。文件系统有一个根 dentry(在超块中引用),这是唯一没有父对象的 dentry。所有其他 dentry 都有父对象,并且一部分 dentry 有子对象。例如,如果打开一个由 /home/user/name 组成的文件,那么将建立 4 个 dentry 对象:一个针对根 /、一个针对根目录 home 的条目、一个针对 user 目录的 name 条目,以及一个针对 user 目录的 name 条目。通过这种方式,dentry 简洁地映射到现在运用 的文件系统。
dentry 对象由 dentry 结构定义(在 ./linux/include/fs/dcache.h 中)。它由许多元素组成,这些元素在文件系统和物理数据中跟踪条目之间的联系 (比如文件名)。图 5 展示了 dentry 对象的简化图示。dentry 引用 super_block,super_block 定义包含该对象的特定文件系统实例。接下来是该对象的父 dentry(父目录),其后是包含在一个列表中的子 dentry(如果该对象刚好是一个目录的话)。然后,为 dentry 定义操作(比如 hash、compare、delete 和 release 等等)。接着定义对象的名称,在这里名称保存在 dentry 中而不是 inode 中。最后,提供一个到 VFS inode 的引用。
图 5. dentry 对象的简化表示
留心 ,dentry 对象仅存在文件系统内存中,而不能储存在硬盘 上。仅长久 储存文件系统 inode,dentry 对象的目的是改善性能。您可以在 ./linux/include/dcache.h 中看到 dentry 的完整描述。
文件对象
在 Linux 系统中打开的每个文件都都存在一个 file 对象。这个对象为特定用户提供打开的实例的信息。图 6 提供了文件对象的简化视图。在图中可以看到,path 结构提供到 dentry 和 vfsmount 的引用。为每个文件定义了一组文件操作,多见 的文件操作包括 open、close、read、write 和 flush 等。接着定义一组标志和权限(包括组和所有者)。最后,为特定文件实例定义状态数据,比如文件的当前偏移量。
图 6. 文件对象的简化表示
对象联系
我们已经查看了 VFS 层中的各种主要 对象,现在我们通过一个图表展示它们之间的联系 。到目前为止,我都是以一种自下而上的方式探索对象,现在我们采用自上而下方式,从用户透视图中考察对象(见 图 7)。
在顶层是打开的 file 对象,它由进程的文件描述符列表引用。file 对象引用 dentry 对象,后者引用 inode。inode 和 dentry 对象都引用底层的 super_block 对象。可能有多个文件对象引用同一个 dentry(当两个用户共享同一个文件时)。留心 ,在图 7 中一个 dentry 对象还引用另一个 dentry 对象。在这里,目录引用文件,而文件反过来引用特定文件的 inode。
图 7. VFS 中的主要对象之间的联系
VFS 架构
VFS 的内部架构由一个调度层(提供文件系统抽象)和许多缓存(用于改善文件系统操作的性能)组成。这个小节探索内部架构和主要对象之间的交互(见图 8)。
图 8. VFS 层的高级视图
在 VFS 中动态管理的两个主要对象是 dentry 和 inode 对象。缓存这两个对象,以改善访问底层文件系统的性能。当打开一个文件时,dentry 缓存将被表示目录级别(目录级别表示路径)的条目填充。此外,还为该对象建立 一个表示文件的 inode。运用 散列表建立 dentry 缓存,并且根据对象名分配缓存。dentry 缓存的条目从 dentry_cache slab 分配器分配,并且在缓存存在压力时运用 最近不运用 (least-recently-used,LRU)算法删除条目。您可以在 ./linux/fs/dcache.c 和 ./linux/include/linux/dcache.h 中找到与 dentry 缓存有关 的函数。
为了实现更快的查找速度,inode 缓存被实现为两个列表和一个散列表。第一个列表定义当前运用 的 inode;第二个列表定义未运用 的 inode。正在运用 的 inode 还储存在散列表中。从 inode_cache slab 分配器分配单个 inode 缓存对象。您可以在 ./linux/fs/inode.c 和 ./linux/include/fs.h 中找到与 inode 缓存有关 的函数。在现在的实现中,dentry 缓存支配着 inode 缓存。如果存在一个 dentry 对象,那么 inode 缓存中也将存在一个 inode 对象。查找是在 dentry 缓存中执行的,这将导致 inode 缓存中出现一个对象。
结束语
本文探索了 VFS 的基础概念,以及为访问不同文件系统提供统一接口的对象。Linux 具有很大的可伸缩性和灵活性,并且可以从子系统执行 扩展。
标签: 操作系统 Unix
1 2
本文标题:Linux 虚拟系统文件交换器剖析
本文链接:
更多>> Linux学院:Unix教程 栏目最近更新
更多>> Linux系统下载:Unix教程下载 栏目最近更新
主编推荐
更多>>热门试卷
更多>>最新视频
更多>>热门阅读
更多>>最新问题
全局导航
IT认证学院 IT英语 程序开发学院 等考学院 建造师学院 基础学院 软件工程学院 软考学院 通信学院 网络工程学院 项目管理学院 新手教程 信息化学院 职称考试学院 职业规划学院 研究生院 信息安全实验室 媒体设计学院 网站建设学院 物联网学院 IT生活 Java学院 Linux学院 Windows学院 商学院 常用工具 数据库学院SQL Server数据库数据仓库Informix数据库
网站首页 关于希赛 工作机会 服务协议 免责声明 联系希赛
希赛网 版权所有 © 2001-2015 湘ICP备10026015号 湘教QS2-201008-001164 增值电信业务经营许可证湘B2-20070093