4.3 文件系统
4.3.1 文件系统结构
文件系统(File system)提供高效和便捷的磁盘访问,以便允许存储、定位、提取数据。
用一个例子来辅助记忆文件系统的层次结构:
假设某用户请求删除文件"D:/工作目录/学生信息.xIsx"的最后100条记录。
- 用户需要通过操作系统提供的接口发出上述请求一一用户接口
- 由于用户提供的是文件的存放路径,因此需要操作系统一层一层地查找目录,找到对应的目录项一一文件目录系统
- 不同的用户对文件有不同的操作权限,因此为了保证安全,需要检查用户是否有访问权限一一存取控制模块(存取控制验证层)
- 验证了用户的访问权限之后,需要把用户提供的“记录号”转变为对应的逻辑地址一一逻辑文件系统与文件信息缓冲区
- 知道了标记录对应的逻辑地址后,还需要转换成实际的物理地址一一物理文件系统
- 要删除这条记录,必定要对磁盘设备发出请求一一设备管理程序模块
- 删除这些记录后,会有一些盘块空闲,因此要将这些空闲盘块回收一一辅助分配模块
4.3.2 文件系统布局
-
文件系统在磁盘中的结构
文件系统存放在磁盘上,多数磁盘划分为一个或多个分区,每个分区中有一个独立的文件系统。文件系统可能包括如下信息:启动存储在那里的操作系统的方式、总的块数、空闲块的数量和位置、目录结构以及各个具体文件等。如下图所示。
-
主引导记录(MasterBootRecord,MBR),位于磁盘的0号扇区,用来引导计算机,MBR后面是分区表,该表给出每个分区的起始和结束地址。表中的一个分区被标记为活动分区,当计算机启动时,BIOS读入并执行MBR。MBR做的第一件事是确定活动分区,读入它的第一块,即引导块。
-
引导块(bootblock),MBR执行引导块中的程序后,该程序负责启动该分区中的操作系统。为统一起见,每个分区都从一个引导块开始,即使它不含有一个可启动的操作系统,也不排除以后会在该分区安装一个操作系统。Windows系统称之为分区引导扇区。
除了从引导块开始,磁盘分区的布局是随着文件系统的不同而变化的。文件系统经常包含有如上图所列的一些项目。
-
超级块(superblock),包含文件系统的所有关键信息,在计算机启动时,或者在该文件系统首次使用时,超级块会被读入内存。超级块中的典型信息包括分区的块的数量、块的大小、空闲块的数量和指针、空闲的FCB数量和FCB指针等。
-
文件系统中空闲块的信息,可以使用位示图或指针链接的形式给出。
-
i 结点。索引结点,连续存放,每个文件对应一个结点,可以把 i 结点区看成一个大数组;
-
根目录,它存放文件系统目录树的根部。
-
其他部分,存放了其他所有的目录和文件。
-
-
文件系统在内存中的结构
内存中的信息用于管理文件系统并通过缓存来提高性能。这些数据在安装文件系统时被加载,在文件系统操作期间被更新,在卸载时被丢弃。这些结构的类型可能包括:
- 内存中的安装表(mount table),包含每个己安装文件系统分区的有关信息。
- 内存中的目录结构的缓存,包含最近访问目录的信息。对安装分区的目录,它可以包括一个指向分区表的指针。
- 整个系统的打开文件表,包含每个打开文件的FCB副本及其他信息。
- 每个进程的打开文件表,包含一个指向整个系统的打开文件表中的适当条目的指针,以及其他信息。
进程创建:
为了创建新的文件,应用程序调用逻辑文件系统。逻辑文件系统知道目录结构的格式,它将为文件分配一个新的FCB。然后,系统将相应的目录读入内存,使用新的文件名和FCB进行更新,并将它写回磁盘。
一旦文件被创建,它就能用于I/O,不过,首先要打开文件。系统调用open()将文件名传递给逻辑文件系统。
-
调用open()首先
搜索整个系统的打开文件表
,以确定这个文件是否已被其他进程使用。
- 如果已被使用,则在单个进程的打开文件表中创建一个条目,让其指向现有整个系统的打开文件表的相应条目。该算法在文件已打开时,能节省大量开销。
- 如果这个文件尚未打开,则根据给定文件名来搜索目录结构。部分目录结构通常缓存在内存中,以加快目录操作。
-
找到文件后,它的FCB会复制到整个系统的打开文件表中;该表不但存储FCB,而且跟踪打开该文件的进程的数量。
-
然后,在单个进程的打开文件表中创建一个条目,并且通过指针将整个系统打开文件表的条目与其他域(如文件当前位置的指针和文件访问模式等)相连。
-
调用open()返回的是一个指向单个进程的打开文件表中的适当条自的指针。以后,所有文件操作都通过该指针执行。
-
一旦文件被打开,内核就不再使用文件名来访问文件,而使用文件描述符(Windows称之为文件句柄)
进程关闭:
当进程关闭一个文件时,就会删除单个进程打开文件表中的相应条目,整个系统的打开文件表的文件打开数量也会递减。当所有打开某个文件的用户都关闭该文件后,任何更新的元数据将复制到磁盘的目录结构中,并且整个系统的打开文件表的对应条目也会被删除。
4.3.3 外存空闲空间管理
一个存储设备可以按整体用于文件系统,也可以细分。例如,一个磁盘可以划分为4个分区,每个分区都可以有单独的文件系统。包含文件系统的分区通常称为卷(volumme)。卷可以是磁盘的一部分,也可以是整个磁盘,还可以是多个磁盘组成RAID集,如图所示。
在一个卷中,存放文件数据的空间(文件区)和FCB的空间(目录区)是分离的。
文件存储设备分成许多大小相同的物理块,并以块为单位交换信息,因此,文件存储设备的管理实质上是对空闲块的组织和管理,它包括空闲块的组织、分配与回收等问题。
-
空闲表法
空闲表法属于连续分配方式,它与内存的动态分配方式类似,为每个文件分配一块连续的存储空间。
-
盘块的分配
与内存管理中的动态分区分配很类似,为一个文件分配连续的存储空间。
同样可采用首次适应、最佳适应、最坏适应等算法来决定要为文件分配哪个区间。
-
盘块的回收
与内存管理中的动态分区分配很类似,当回收某个存储区时需要有四种情况:
- ①回收区的前后都没有相邻空闲区
- ②回收区的前后都是空闲区
- ③回收区前面是空闲区
- ④回收区后面是空闲区
总之,回收时需要注意表项的合并问题
-
-
空闲链表法
将所有空闲盘区拉成一条空闲链。根据构成链所用基本元素的不同,分为两种形式:
操作系统保存着链头、链尾指针。
- 如何分配:若某文件申请K个盘块,则从链头开始依次摘下K个盘块分配,并修改空闲链的链头指针。
- 如何回收:回收的盘块依次挂到链尾,并修改空闲链的链尾指针。
适用于离散分配的物理结构。为文件分配多个盘块时可能要重复多次操作
-
空闲盘区链:将磁盘上的所有空闲盘区(每个盘区可包含若干个盘块)拉成一条链。
操作系统保存着链头、链尾指针。
-
如何分配:
若某文件申请K个盘块,则可以采用首次适应、最佳适应等算法,从链头开始检索,按照算法规则找到一个大小符合要求的空闲盘区,分配给文件。
若没有合适的连续空闲块,也可以将不同盘区的盘块同时分配给一个文件,注意分配后可能要修改相应的链指针、盘区大小等数据。
-
如何回收:若回收区和某个空闲盘区相邻,则需要将回收区合并到空闲盘区中。若回收区没有和任何空闲区相邻,将回收区作为单独的一个空闲盘区挂到链尾。
离散分配、连续分配都适用。为一个文件分配多个盘块时效率更高。
-
-
位示图法
位示图是利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上所有的盘块都有一个二进制位与之对应。当其值为“0”时,表示对应的盘块空闲;为“1”时,表示已分配。
这样,一个m×n位组成的位示图就可用来表示m×n个盘块的使用情况,如图所示。行为位号,列为字号
注意:盘块号、字号、位号到底是从0开始,还是从1开始。两者计算盘块号方式不同。
-
盘块的分配
-
顺序扫描位示图,从中找出一个或一组其值为“0”的二进制位。
-
将找到的一个或一组二进制位,转换成与之对应的盘块号。若找到的其值为“0”的二进制位位于位示图的第i行、第j列,则其相应的盘块号应按下式计算(n为每行位数):
{ b = n ( i − 1 ) + j , 字、位、盘块号从1开始 b = n i + j 字、位、盘块号从0开始 \begin{cases}b=n(i-1)+j, & \text{字、位、盘块号从1开始}\ b=ni+j& \text{字、位、盘块号从0开始}\end{cases} {b=n(i−1)+j,字、位、盘块号从1开始 b=ni+j字、位、盘块号从0开始 -
修改位示图,令 m a p [ i , j ] = 1 map[i,j]=1 map[i,j]=1
-
-
盘块的回收
-
将回收盘块的盘块号转换成位示图中的行号和列号。转换公式为
KaTeX parse error: Expected & or \\ or \cr or \end at end of input: …开始}\end{cases} -
修改位示图,令 m a p [ i , j ] = 0 map[i,j]=0 map[i,j]=0。
-
空闲表法和空闲链表法都不适用于大型文件系统,因为这会使空闲表或空闲链表太大。
-
-
成组链接法
在UNIX系统中采用的是成组链接法,这种方法结合了空闲表和空闲链表两种方法,它具有上述两种方法的优点,克服了两种方法均有的表太长的缺点。
文件卷的目录区中专门用一个磁盘块作为“超级块”,当系统启动时需要将超级块读入内存。并且要保
证内存与外存中的“超级块”数据一致。用来存放一组空闲盘块号(空闲盘块的块号)的盘块称为成组链块。
-
成组链接思想:把顺序的n个空闲盘块号保存在第一个成组链块中,其最后一个空闲盘块(作为成组链块)则用于保存另一组空闲盘块号,如此继续,直至所有空闲盘块均予以链接。
-
盘块的分配
分配1个空闲块:
- ①检查第一个分组的块数是否足够。1<100,是足够的。
- ②分配第一个分组中的1个空闲块,并修改相应数据
分配100个空闲块:
- ①检查第一个分组的块数是否足够。100=100,是足够的。
- ②分配第一个分组中的100个空闲块。但是由于300号块内存放了再下一组的信息,因此300号块的数据需要复制到超级块中
-
盘块的回收
需要将超级块中的数据复制到新回收的块中,并修改超级块的内容,让新回收的块成为第一个分组。
-
4.3.4 虚拟文件系统
虚拟文件系统(VFS)为用户程序提供了文件系统操作的统一接口,屏蔽了不同文件系统的差异和操作细节。
-
普通文件系统
下图普通的文件系统,不同的外部存储设备,它的文件系统可能是不相同的,对于同一个操作的函数方法定义也许也各不相同;
-
虚拟文件系统
下图为虚拟文件系统,用户程序可以通过VFS提供的统一调用函数(如open()等)来操作不同文件系统的文件,而无须考虑具体的文件系统和实际的存储介质。
虚拟文件系统采用了面向对象的思想,它抽象出一个通用的文件系统模型,定义了通用文件系统都支持的接口。新的文件系统只要支持并实现这些接口,即可安装和使用。
为了实现VFS,Linux主要抽象了四种对象类型。每个VFS对象都存放在一个适当的数据结构中,其中包括对象的属性和指向对象方法(函数)表的指针。
-
虚拟文件系统VFS所定义的对象类型
(1)超级块对象:表示一个已安装(或称挂载)的特定文件系统。超级块对象对应于磁盘上特定扇区的文件系统超级块,用于存储已安装文件系统的元信息。其操作方法包含一系列可在超级块对象上调用的操作函数,主要有分配inode、销毁inode、读inode、写inode等。
(2)索引节点对象:表示一个特定的文件。索引节点和文件是一对一的关系。只有当文件被访问时,才在内存中创建索引节点对象,每个索引节点对象都会复制磁盘索引节点包含的一些数据。索引节点对象还提供许多操作函数,如创建新索引节点、创建硬链接、创建新目录等。
(3)目录项对象:表示一个特定的目录项。目录项对象是一个路径的组成部分,它包含指向关联索引节点的指针,还包含指向父目录和指向子目录的指针。不同于前面两个对象,目录项对象在磁盘上没有对应的数据结构,而是VFS在遍历路径的过程中,将它们逐个解析成目录项对象的。(4)文件对象:表示一个与进程相关的已打开文件。可以通过调用openO打开一个文件,通过调用closeO关闭一个文件。文件对象和物理文件的关系类似于进程和程序的关系。文件对象仅是进程视角上代表已打开的文件,它反过来指向其索引节点。文件对象包含与该文件相关联的目录项对象,包含该文件的文件系统、文件指针等,还包含在该文件对象上的一系列操作函数。当进程发起一个面向文件的系统调用时,内核调用VFS中的一个函数,该函数调用目标文件系统中的相应函数,将文件系统请求转换到面向设备的指令。以在用户空间调用writeO为例,它在VFS中通过sys_writeO函数处理,sys_writeO找到具体文件系统提供的写方法,将控制权交给该文件系统,最后由该文件系统与物理介质交互并写入数据。
进程与VFS对象之间的交互如下图所示。
三个不同的进程已打开了同一个文件,其中两个进程使用同一个硬链接。
在这种情况下,每个进程都使用自己的文件对象,但只需要两个目录项对象,每个硬链接对应一个目录项对象。这两个目录项对象指向同一个索引结点对象, 这个索引结点对象标识的是超级块对象及随后的普通磁盘文件。
-
对于不同文件系统的数据结构,VFS 在每打开一个文件,就在主存建立一个vnode,用统一的数据结构表示文件;
打开文件后,创建vnode,并将文件信息复制到vnode中,vnode的功能指针指向具体文件系统的函数功能
ufs是unix文件系统
vnode只存在于主存中,而inode既会被调入主存,也会在外存中存储
特点:
- ①向上层用户进程提供统一标准的系统调用接口,屏蔽底层具体文件系统的实现差异
- ②VFS要求下层的文件系统必须实现某些规定的函数功能,如:open/read/write。一个新的文件系统想要在某操作系统上被使用,就必须满足该操作系统VFS的要求
- ③每打开一个文件,VFS就在主存中新建一个vnode,用统一的数据结构表示文件,无论该文件存储在哪个文件系统
VFS在系统启动时建立,在系统关闭时消亡
4.3.5 分区和安装
-
分区
-
物理格式化(低级格式化):划分扇区、检测坏扇区、用备用扇区替换坏扇区;当要访问某一块坏扇区时,会使用备用扇区,默默完成替换工作;
-
逻辑格式化(高级格式化):磁盘分区;每个区的大小、地址范围等信息,会使用 分区表 来记录;
在每个区里可以建立各自独立的文件系统 ,例如在C盘里建立UNIZX文件系统;
分区的第一部分是引导块,里面存储着引导信息,它有自身的格式,因为在引导时系统并未 加载文件系统代码,因此不能解释文件系统的格式。下图为一个典型的Linux分区。
-
-
安装
文件系统在进程使用前必须先安装,也称挂载,任务是将一个文件系统挂载到操作系统中。
功能:
- ①在VFS中注册新挂载的文件系统。内存中的挂载表(mount table)包含每个文件系统的相关信息,包括文件系统类型、容量大小等。
- ②新挂载的文件系统,要向VFS提供一个函数地址列表
- ③将新文件系统加到挂载点(mountpoint),也就是将新文件系统挂载在某个父目录下
UNIX本身是一个固定的目录树,只要安装就有,但是如果不给它分配存储空间,就不能对它进行操作,所以首先要给根目录分配空间,这样才能操作这个目录树。
4.4 本章疑难点
1、文件的物理分配方式的比较
2、文件打开的过程描述
检索目录,要求打开的文件应该是已经创建的文件,它应登记在文件目录中,否则会出错。在检索到指定文件后,就将其磁盘iNode复制到活动iNode表中。
将参数mode所给出的打开方式与活动iNode中在创建文件时所记录的文件访问权限相比较,如果合法,则此次打开操作成功。
当打开合法时,为文件分配用户打开文件表表项和系统打开文件表表项,并为后者设置初值,通过指针建立表项