内核只认识VFS(虚拟文件系统),不同文件系统实现的都是和VFS的相互调用,进而通过VFS访问内核MTD
概述
- 文件和文件系统
文件系统提供了与辅助存储相关的资源的抽象。文件系统允许用户去创建称为文件的数据集合,它们拥有一些理想的属性:
- 长期存在
- 进程间可共享
- 结构
任何文件系统不但提供一种手段去存储数据(被组织为文件),而且提供一系列对文件进行操作的功能接口。典型的操作如下:
- 创建
- 删除
- 打开
- 关闭
- 读
写
文件结构
域:是基本数据单元。
记录:是一组相关的域的集合,它可以视为引用程序的一个单元。
文件:是一组相似记录的集合,它被用户和应用程序视为一个实体,并可以通过名字访问。文件有唯一的文件名,可以被创建或删除。
数据库:是一组相关的数据的集合,它的本质特征是数据元素间存在着明确的关系,并且可供不同的应用程序使用。
文件管理系统
文件管理是一组系统软件,为使用文件的用户和应用程序提供服务。文件管理系统是用户或应用程序访问文件的唯一方式。一个文件管理系统需要满足一下目标:
- 满足数据管理的要求和用户的需求,包括存储数据和执行上述操作的能力
- 最大限度地保证文件中的数据有效
- 优化性能,包括总体吞吐量(从系统的角度)和响应时间(从用户的角度)
- 为各种类型的存储设备提供I/O支持
- 减少或消除丢失或破坏数据的可能性
- 向用户进程提供标准I/O接口例程集
- 在多用户系统中为多个用户提供I/O支持
文件系统架构
设备驱动程序直接与外围设备通信,设备驱动程序负责启动该设备上的I/O操作,处理I/O请求的完成。通常是操作系统的一部分。
基本文件系统这是与计算机系统外部环境的基本接口。该层处理在磁盘间或磁带系统间交换的数据块,因此,它关注的是这些块在辅助存储和内存缓冲区中的位置。
基本I/O管理程序负责所有文件I/O的初始和终止。基本I/O管理程序根据所选择的文件来选择执行文件I/O的设备,为优化性能,它还参与调度对磁盘和磁带的访问。
逻辑I/O管理使用户和应用程序能够访问到记录。因此,基本文件系统处理的是数据块,而逻辑I/O模块处理的是文件记录。
文件管理功能
用户和应用程序通过使用创建文件、删除文件及执行文件操作的命令,与文件系统进行交互。在执行任何操作之前,文件系统必须确认和定位所选择的文件。这要求使用某种类型的目录来描述所有文件的位置和它们的属性。此外,大多数共享系统都实行用户访问控制:只有被授权用户才允许以特定的方式访问特定的文件。用户和应用程序可以在文件执行的基本操作是记录级上执行的。用户和应用程序把文件视为具有组织记录的某种结构,如顺序结构,因此为了把用户命令转换成特定的文件操作指令,必须采用适合于该文件结构的访问方法。
文件管理系统作为一个单独的系统实用程序,和操作系统关注的是不同方面的内容,它们的焦点是记录的处理。
文件组织和方法
文件组织是指文件中记录的逻辑结构,它由用户访问记录的方式确定。
选择文件组织时的原则:
- 访问快速
- 易于修改
- 节约存储空间
- 维护简单
- 可靠性
文件组织方式
- 堆:堆是最简单的文件组织形式。数据按它们到达的顺序被收集,每条记录由一串数据组成。由于堆没有结构,因而对记录的访问是通过穷举查找的方式进行的。
- 顺序文件:最常用的文件组织形式。在这类文件中,每条记录都使用一种固定的格式。所有的记录都具有相同的长度,并且由相同数目、长度固定的域按特定的顺序组成。关键域通常是每条记录的第一个域,唯一标识这条记录。
- 索引顺序文件:保留了顺序文件的关键特征:记录按照关键域的顺序组织起来。但它增加了两个特征:用于支持随机访问的文件索引和溢出文件。索引提供了快速接近目标记录的查找能力。溢出文件类似于顺序文件中使用的日志文件,但是溢出文件中的记录可以根据它前面记录的指针进行定位。
索引文件中的每条记录由两个域组成:关键域和指向主文件的指针,其中关键域和主文件中的关键域相同。为查找一个特定的域,首先查找索引,查找关键域值等于目标关键域值或者位于目标关键域值之前且最大的索引,然后在该索引的指针所指的主文件中的位置处开始查找。
主文件中的每条记录包含一个附加域。它是指向溢出文件的一个指针。当往文件中插入一条新纪录时,它被添加到溢出文件,然后修改主文件中逻辑顺序位于这条新纪录之前的记录,使其包含指向溢出文件中新纪录的指针。
- 索引文件:需要采用多索引的结构,每种可能成为查找条件的域都有一个索引。只能通过索引来访问记录,其结果对记录的放置位置不再有限制,只要至少有一个索引的指针指向这条记录即可。
- 直接或散列文件:开发直接访问磁盘中任何一个地址已知的块的能力。
文件目录
- 内容
与任何文件管理系统和文件集合相关联的是文件目录,目录包含关于文件的信息,这些信息包括属性、位置和所有权。目录本身是一个文件,并且可以被各种文件管理例程访问。尽管用户和应用程序也可以得到目录中的某些信息,但这通常是由系统例程间接提供的。
下表列出了目录通常为系统中每个文件保存的信息。
结构
最简单的目录结构形式是一个目录项列表,每个文件一个目录项。
可能在目录上执行的操作的类型:查找、创建文件、删除文件、显示目录、修改目录。
树形结构方法:有一个主目录,它的下面是许多用户目录,每个用户目录依次又有子目录项和文件的目录项,并且在任何一级都是这样。
命名
对用户而言,要求为文件提供一个唯一的名字是一个难以承受的负担,特别是在共享系统中。
使用树形结构目录降低了提供唯一名字这方面的困难性。系统中的任何文件可以按照从根目录或主目录向下到各个分支,最后直到该文件的路径来定位。
文件共享
在多用户系统中,几乎总是要求允许文件在多个用户间共享。这时就产生了两个问题:访问权限和对同时访问的管理。
- 访问权限
文件系统应该为多个用户间广泛地共享文件提供灵活的工具。具有代表性的访问权限:无、知道、执行、读、追加、更新、改变保护(用户可以改变授予其他用户的访问权限)、删除。
访问可以提供给不同类的用户:特定用户、用户组、全部
同时访问
一种蛮力的方法是当用户修改文件时,允许用户对整个文件加锁。比较好的控制力度是在修改时对单条记录加锁。在设计共享访问能力时必须解决互斥问题和死锁问题。
辅助存储管理
在辅助存储中,一个文件是由许多块组成的。操作系统或文件管理系统负责给文件分配块。两个管理问题:辅助存储中的空间必须分配给文件;必须知道哪些空间可以用来分配。
- 文件分配
文件分配涉及一下几个问题:
- 当创建一个新文件时,是否一次性地给它分配所需要的最大空间;
- 给文件分配的空间是一个或多个连续的单元,这些单元称为分区。分区是一组连续的已经分配了的块。
- 为跟踪分配给文件的分区,应该使用哪种数据结构或表?
预分配与动态分配:预分配策略要求在发出创建文件的请求时,声明该文件的最大大小。动态分配只有在需要时才给文件分配空间。
分区大小:分配给文件的分区大小。一种极端情况是,分配一个足够大的分区,可以保存整个文件;另一种是磁盘空间一次只分配一块。
- 可变的大规模连续分区:大小可变避免了浪费,并且使文件分配表比较小,但是这又导致空间很难再次利用。
- 块:小的固定分区提供了更大的灵活性,但是为了分配,它们可能需要较大的表或更复杂的结构。
对于可变大小的分区,我们需要考虑空闲空间的碎片问题。一些可能的选择策略:
- 首次适配:从空闲块列表中选择第一个未被使用且大小足够的连续的块组;
- 最佳适配:选择大小足够的未使用过的块中最小的一个
- 最近适配:选择与前面分配给该文件的块组最为邻近的组,其目的是提高局部性。
文件的分配方法:连续、链接和索引。
连续分配:是指在创建文件时,给文件分配一组连续的块。这是一种大小可变分区的预分配策略,在文件分配表中每个文件只需要一个表项,用于说明起始块和文件的长度。
链接分配:典型情况下,链接分配基于单个的块,链中的每一块都包含都包含指向下一块的指针。文件分配表中每个文件同样只需要一个表项,用于声明起始块和文件长度。链接分配的一个后果是局部性原理不再使用。
- 索引分配:每个文件在文件分配表中有一个一级索引。分配给该文件的每个分区的索引中都有一个表项。文件的索引保存在一个单独的块中,文件分配表中该文件的表项指向这一块。
空闲空间的管理
为实现前面描述的任何一种文件分配技术,必须首先知道磁盘中的哪些块是可用的。除了文件分配表以外,还需要一个磁盘分配表。
位表:使用一个向量,向量的每一位对应于磁盘中的每一块。0表示一个空闲块,1表示一个已使用的块。
链接空闲区:通过使用指向每个空闲区的指针和它们的长度值,空闲区可以被链接在一起。由于不需要磁盘分配表,仅需要一个指向链的开始处的指针和第一个分区的长度。
索引:把空闲空间视为一个文件,并使用一个在文件分配时介绍过的索引表。
空闲块列表:每块都指定一个顺序号,所有空闲块的顺序号保存在磁盘上的一个保留区中。
卷:一组在辅助存储上可寻址的扇区的集合,操作系统或应用程序用卷来进行数据存储。一个卷中的扇区在物理存储设备上不需要是连续的;相反,只需要对于操作系统或应用程序来讲是连续的。一个卷可能是更小的卷合并或组合后的结果。
当请求一个文件分配时,需要执行以下步骤:
- 在磁盘中对磁盘分配表加锁,防止在分配完成以前另一个用户修改这个表。
- 查找磁盘分配表,查找可用空间
- 分配空间,更新磁盘分配表,更新磁盘。
- 更新文件分配表和更新磁盘
- 对磁盘分配表解锁
文件系统安全
只有在登录成功以后,用户才会被赋予权限访问一个或多个主机和应用程序,这样对于数据库中有敏感数据的系统来说是不够的。系统中会有一个与每个用户相关的配置文件,用来指定用户操作和访问文件的权限。操作系统基于用户配置文件夹实施权限控制规则。数据库管理系统必须控制特定的记录或一部分记录。
经常运用在文件或者数据库管理系统的访问控制模块称为访问矩阵。
模型的基本元素如下:
- 主体:有能力访问对象的实体。
- 对象:可以被访问和控制的任何实体,譬如文件、程序及软件中的对象。
- 访问权限:主体访问对象的方式,譬如读、写、执行及使用软件对象的功能。
Linux虚拟文件系统
Linux包含一个通用的、强有力的文件处理机制,该机制利用虚拟文件系统(VFS)来支持大量的文件管理系统和文件结构。VFS向用户进程提供了一个简单、统一的文件系统接口。对于任何特定的文件系统,需要一个映射模块来转换实际文件系统的特征到虚拟文件系统所期望的特征。
Linux文件系统策略的关键要素。
VFS在Linux内核中所扮演的作用如下:
当进程发起一个面向文件的系统调用时,内核调用VFS中的一个函数。该函数处理完与具体文件系统无关的操作后,调用目标文件系统中的相应函数。这个调用通过一个转换VFS的调用到目标文件系统调用的映射函数来实现。VFS独立于任何具体文件系统。因此映射函数的实现是文件系统在Linux上的实现的一部分。目标文件系统转换文件系统请求到面向设备的指令。
VFS是一个面向对象的方案。VFS是是用C语言来实现的,因此VFS的对象简单为C语言的结构。每一个对象包含数据和函数指针。这些函数指针指向操作这些数据的文件系统的实现函数。VFS的四个主要对象:
- 超级块对象:代表一个特定的已挂载的文件系统
- 索引节点对象:代表一个特定的文件
- 目录项对象:代表一个特定的目录项
- 文件对象:代表一个与进程相关的打开的文件
超级块对象
超级块存储了描述特定文件系统的信息。通常,超级块对象对应了位于磁盘上特定扇区的文件系统超级块。
超级块对象由许多数据项组成,典型的数据项如下:
- 该文件系统所挂载的设备
- 文件系统的基本块大小
- 脏标志:表示超级块已经修改过,但还未写回磁盘
- 文件系统类型
- 标志:如只读标志
- 指向文件系统根目录的指针
- 打开文件链表
- 控制访问该文件系统的信号量
- 操作超级块的函数指针数组的指针
最后一项是一个包含在超级块对象中的操作对象。该操作对象定义了内核可在超级块对象上调用的对象方法(函数)。为超级块对象定义的方法包括:
- read_inode:从一个已挂载的文件系统上读一个特定的索引节点
- wire_inode:把给定的索引节点写回磁盘
- put_inode:释放索引节点
- delete_inode:从磁盘上删除索引节点
- notify_change:当索引节点的属性发生变化时调用
- put_super:当VFS卸载一个给定的超级块时调用
- write_super:当VFS决定把超级块写回磁盘时调用
- statfs:获取文件系统的统计信息
- remount_fs:当文件系统重新挂载时调用
- clear_inode:释放索引节点,同时清除任何包含相关数据的页。
索引节点对象
一个索引节点与一个文件相关联。索引节点对象包含一个命名文件的除了该文件的文件名和该文件的实际数据内容外的所有信息。索引节点中包含所有者、组、权限、文件的访问时间、数据长度和链接等信息。
索引节点对象包含一个描述VFS能在该索引节点上调用的文件系统的实现函数的索引节点操作对象。索引节点操作对象中定义了如下函数:
- create:为某一目录下的目录项对象相关联的普通文件创建一个新的索引节点
- lookup:为对应于一个文件名的索引节点查找一个目录
- mkdir:为与某一目录下的目录项对象相关联的一个目录创建一个新的索引节点。
目录项对象
目录项对象是一个路径上的特定组成。该组成或者是一个目录名,或者是一个文件名。目录项对象访问文件和目录提供弄了方便。目录项对象包括一个指向索引节点的指针和超级块。它还包括一个指向父目录的指针和指向子目录的指针。
文件对象
文件对象代表一个进程所打开的一个文件。文件对象在系统调用open()时创建,在系统调用close()时销毁。文件对象包含如下数据项:
- 与该文件相关联的目录项对象
- 包含该文件的文件系统
- 文件对象使用计数
- 用户ID
- 用户组ID
- 文件指针:指向下一个文件操作所要作用到的位置
文件对象包含一个描述VFS能在该文件对象上调用的文件系统的实现函数的文件操作对象。该对象包含的函数有read、write、open、release和lock。
Windows文件系统
Window NT的开发者设计了一个新的文件系统——NTFS,用于满足工作站和服务器中的高端需求:
- 客户/服务器应用程序,如文件服务器、计算服务器和数据库服务器
- 资源密集型工程和科学应用
- 大型系统的网络应用程序
NTFS的重要特征
- 可恢复性:具备从系统崩溃和磁盘故障中恢复数据的能力。当发生这类故障时,NTFS能够重建文件卷,并使它们返回到一个一致的状态。
- 安全性:NTFS使用Windows对象模型来实施安全机制。一个打开的文件作为一个文件对象来实现,并且有一个定义它的安全属性的安全描述符。安全描述符作为文件的一个属性被保存在磁盘上。
- 大磁盘和大文件
- 多数据流:文件的实际内容被当做字节流处理。
- 日志:NTFS维护了一条记录所有对于卷上的文件进行的修改的日志
- 压缩和加密
- 硬链接和符号链接:硬链接:允许同一个卷上的多个路径名访问单个文件。符号链接:允许多个路径名访问一个文件或目录,即使路径名在不同的卷上。
NTFS卷和文件结构
NTFS使用下列磁盘存储概念:
- 扇区:磁盘中最小的物理存储单元。一个扇区中能存储的数据量字节数总是2的幂,并且通常为512B。
- 簇:一个或多个连续的扇区。一个簇中扇区的数目也为2的幂
- 卷:磁盘上的逻辑分区。由一个或多个簇组成,供文件系统分配空间时使用。
NTFS并不识别扇区,簇时最基本的分配单位。使用簇进行分配使得NTFS不依赖于物理扇区的大小。
NTFS卷布局:NTFS使用一种简单但功能强大的方法组织磁盘卷中的信息。卷中的每个元素都是一个文件,并且每个文件包含一组属性,文件的数据内容也视为一个属性。
- 分区引导扇区:包含卷的布局信息、文件系统的结构及引导启动信息和代码。
- 主文件表(MFT):包含在这个NTFS卷中所有文件和文件夹(目录)的信息,以及关于可用的未分配空间的信息。
- 系统文件:MFT2、日志文件、簇的位图和属性定义表。
MFT是Windows文件系统的核心。MFT被组织成一个由长度为1024B的行组成的表,每行称为一条记录。每一行描述了该卷中的一个文件或文件夹,包括MFT自身,MFT也被视为一个文件。
可恢复性
系统崩溃或磁盘失效后,NTFS可以把文件系统恢复到一致的状态。支持可恢复性的重要组件:
- I/O管理程序:包括NTFS驱动程序,用于处理NTFS中基本的打开、关闭、读、写功能。
- 日志文件服务器:维护一个关于磁盘上文件系统元数据的改变的日志。
- 高速缓存管理器:负责对文件的读写进行高速缓存,以提高性能。
- 虚存管理程序:NTFS通过把对文件引用映射到虚存引用以及读写虚存,来访问被缓存的文件。
值得注意的是,NTFS使用的恢复过程是为恢复文件系统的数据而设计的,不是用于恢复文件的内容。
一般来说,为保证可恢复性,需要以下4个步骤:
- NTFS首先调用日志文件系统,在缓存中的日志文件里记录任何会修改卷结构的事务。
- NTFS修改这个卷(在高速缓存中)
- 高速缓存管理器调用日志文件系统,提示它刷新磁盘中的日志文件
- 如果日志文件在磁盘上的更新是安全地,高速缓存管理器把该卷的变化刷新到磁盘中。
小结
文件管理系统是一组系统软件,为使用文件的用户和应用程序提供服务,包括文件访问、目录维护和访问控制。