linux操作系统 第07章 磁盘管理

                                                                                     第7章   文件管理    


7.1  文件管理概述
7.1.1  文件与文件系统
  
1. 文件
  文件是具有名字的一组相关信息的有序集合,存放在外部存储器中。文件的名字称为文件名,它是文件的标识。文件的信息可以是各种各样的,一个程序、一批数据、一张图片、一段视频等都可以作为文件的内容。文件的存储空间是具有长久记忆特性的外部存储器(如磁盘、磁带等),因而文件是可以长久保存的信息形式。所有需要在系统关机后仍能保留的信息都应以文件的形式存在。

  2. 文件系统
  文件系统是操作系统的一个重要组成部分,它负责管理系统中的文件,为用户提供使用文件的操作接口。文件系统由实施文件管理的软件和被管理的文件组成。文件系统软件属于系统内核代码,文件则按特定的格式存放在磁盘分区中。文件系统通常以磁盘分区划分,每个分区对应一个独立的文件系统。
  归纳起来,文件系统的功能包括以下几项:
  ● 实现文件的“按名存取”,包括按名建立、读/写、检索、修改、删除文件等操作。
  ● 管理分区存储空间,实施存储空间的分配、回收与重组。
  ● 实现对文件的共享、保密和保护措施。
  ● 提供文件访问接口。

  3. 文件的描述
  为了实施和控制对文件的各种访问操作,文件系统为每个文件都建立了一个文件控制块(File Control BlockFCB)。文件的FCB的作用类似于进程的PCB,它记录了文件的使用者和管理者所关心的所有信息,包括文件名、属主、文件大小、物理存储位置、修改和访问时间、存取权限等。当用户创建一个新文件时,文件系统就为这个文件建立起一个FCB。随着文件的操作,FCB的内容也相应地变化。当文件被删除时,它的FCB也就消失了。

  4. 文件目录
  计算机系统中通常存有大量的文件,系统须采用某种有效的形式来组织和管理这些文件。由于文件与文件的FCB一一对应,因此,管理文件就是管理文件的FCB
  
文件系统采用目录来组织文件。目录是FCB的有序集合,通过目录将所有的FCB分层分类地组织在一起,方便了文件的检索操作。由于目录的信息是需要长久保存的,所以目录也需以文件的形式存在。为此,系统定义了一种特殊的文件——目录文件,其内容是一组FCB构成的文件列表,每个表项是一个文件的FCB,在目录里就称为目录项了。由于目录本身也是文件,因此目录的FCB也可以作为另一个目录中的目录项,从而构成目录的层次关系。

  目录的主要功能是实现文件的“按名存取”,即用户只需提供文件名就可以对文件进行各种操作。目录实现了文件名到文件物理存放位置的映射。
  目录的另一个功能是
合理地组织文件。现在,几乎所有的操作系统都采用树形目录结构,就是将文件分层分类地组织成一个树状结构,从根目录开始向下延伸。树形目录结构的特点是层次清楚,便于文件分类管理,可加快文件的检索速度。另外,树形目录还允许文件重名,即只要文件不在同一目录下便可以使用相同的名字。

  5. 文件的结构
  文件结构是文件内容的组织方式。从不同层面上看到的文件结构有所不同。图6-1所示是文件在三个不同抽象层次上的结构。

图6-1  文件的结构

  1) 文件的格式
  终端用户是通过应用程序来使用文件的,从他们的角度看到的是文件的应用结构,也就是文件的格式。文件的格式由处理文件的应用程序定义和使用,通常以后缀名相区分。如“.doc”文件是由Word程序使用的格式,“.bmp”是图片处理程序使用的格式。
  根据文件格式的结构类型,文件大致可分为
结构化文件(如列表文件、数据库文件等)半结构化文件(Web文档、图片、图像等)无结构文件(如纯文本文件等)。

  2) 文件的逻辑结构
  文件的逻辑结构是文件系统的直接用户(也就是应用程序)所看到的文件结构。文件的逻辑结构取决于文件系统接口的设计,它决定了文件存取的方式。应用程序按逻辑结构访问文件系统中的文件,并在此基础上构造出各种应用结构呈现给应用程序的用户。也就是说,应用程序负责文件的格式与逻辑结构之间的映射。
  文件的逻辑结构有
记录式文件流式文件两种,具体介绍见7.1.2小节。

  3) 文件的物理结构
  文件的物理结构又称为存储结构,是指文件在外存上的存储组织形式。文件系统负责文件的逻辑结构与物理结构之间的映射。
  文件的物理结构分为
连续文件链接文件索引文件3种,具体介绍见7.1.3小节。
  操作系统所关心的是文件的逻辑结构与物理结构。逻辑结构是供文件系统的用户使用的,物理结构是文件系统内部使用的。将逻辑结构与物理结构相区分,是为了向用户屏蔽有关文件存储的细节,使用户可以只凭简单的逻辑结构来使用文件。

7.1.2  文件的逻辑结构与存取方式
  1. 文件的逻辑结构
  文件的逻辑结构是从文件的使用者角度所看到的文件信息的组织形式,它独立于文件的物理存储特性。
  文件的逻辑结构主要分为两种类型:一种是
记录式文件,另一种是流式文件

  1) 记录式文件
  记录式文件由若干记录组成,记录具有固定的长度和一致的内部结构,其中有一个用于标识记录的记录号字段。用户程序预先定义好文件记录的格式,文件系统就按此格式创建文件。访问文件时要向文件系统提供记录号,文件系统则以记录为单位进行文件的定位和读/写。
  记录式文件是结构化的文件,它就像一张表格,用户程序要按预先规定的格式填写数据和读取数据,使用起来不够灵活,也不便于构造不规则的应用格式。另外,记录的大小与存储块的大小难以匹配,读/写操作的复杂度较高。由于这些原因,记录式文件已渐被淘汰。

  2) 流式文件
  流式文件是由字节序列组成的文件,是无结构的文件。用户程序访问文件时只要指定文件的偏移位置和要读/写的字节数,文件系统即可方便地存取指定部分的文件内容。
  流式文件就像一张白纸,没有任何格式上的限制。用户程序可任意地在字节流上构造自己的应用格式。写文件时,用户程序按自己定义的结构来组织数据,然后把它们作为字节流写入文件;读文件时,将读出的字节流再解释成自己使用的结构。因此说,无结构实际上就是不限制结构的意思,这为应用程序提供了很大的灵活性,同时又简化了文件系统的操作。所以现代流行的操作系统,如
UnixLinuxWindows、OS/2等均采用流式文件作为文件的逻辑结构。

  2. 文件的操作
  对文件的操作主要有建立/删除、打开/关闭、读/写、修改属性等。
  建立文件时用户要为文件指定一个文件名,文件系统以文件名为标识建立文件的
FCB,并为文件分配存储空间等资源。删除文件的操作与此相反,用户指定要删除的文件名,文件系统删除该文件的FCB,并释放其占用的存储空间等资源。
  对文件的读
/写操作都要经过文件的FCB来进行。由于FCB存放在外存空间中,如果每次读/写文件都要访问外存FCB的话,存取速度将很低。因此在对文件进行任何读/写操作前,需要先打开文件。打开文件就是在内存中生成文件的FCB,并返回一个标识其内存FCB的文件标识符,随后的读/写操作将通过此文件标识符进行。所有读/写完成后应关闭文件。关闭文件操作将内存FCB的内容写回外存FCB,回收文件描述符,并删除内存中的文件FCB。

  3. 文件的存取方式
  不论是记录式文件还是流式文件,其逻辑结构都是一维的,但存取方式有所不同。这里针对流式文件的存取方式介绍如何根据逻辑结构存取文件。
  存取文件指的是对文件的读
/写操作。每个打开的文件都有一个指示读/写位置的指针offset,如图6-2所示。文件刚打开时,读/写位置位于文件头0字节处。每次读/写文件时(比如用C函数read()write()),根据给定的长度参数读/count个字节,完成后位置指针会自动移到读/写完的位置之后,这样下次读/写就接着本次的位置顺序地进行下去。必要时,也可以通过设置读/写位置指针来改变读/写的次序。例如,需要追加写入时,需先将位置指针定位到文件尾。
  应用程序对流式文件的存取方式有两种,即
顺序存取随机存取

图6‑2  流式文件的存取

  1) 顺序存取
  顺序存取就是从文件头开始顺序地访问文件的每一段信息,直到文件尾。应用程序在加载、保存、传输文件时,或对文件做某些过滤性处理时,都要对文件进行顺序存取操作。
  顺序存取的通常做法是在一个循环中调用文件读
/写函数,直到遇到文件结束符(EOF)。

  2) 随机存取
  随机存取也称为直接存取,就是从文件的指定位置开始存取一段数据。很多应用场合需要随机存取,例如,数据库管理程序从数据库表文件中读取或修改一个记录就是一种随机存取。
  随机存取的方法是:先将读
/写指针定位到文件的指定位移处(比如用C函数lseek()等),然后从此位置开始存取指定字节数的一段数据。

7.1.3  文件的物理结构与存储方式
  文件的物理结构是文件在外存中的组织和存放形式,是文件系统底层所使用的文件结构。文件的物理结构与存储介质的物理特性有关。在介绍文件的物理结构之前有必要了解一些存储设备的知识和存储空间的结构。
  文件的存储设备包括磁带、磁盘、闪存、光盘等,典型的存储设备是磁盘。下面简单介绍磁盘的物理结构及磁盘空间的逻辑结构。

  1. 磁盘的物理结构
  磁盘的结构如图6-3所示。磁盘由一组盘片组成,每个盘片有两个盘面,在对磁盘进行物理格式化时,在盘面上划分出多个同心圆,称为磁道(track)。所有盘面的相同位置的磁道组成的圆柱体,称为柱面(cylinder)。每个磁道又划分为多个弧段,称为扇区(sector),通常的大小是512字节。扇区是磁盘的物理块,是磁盘上可寻址的最小存储单位。文件的数据就存储在一系列扇区中。

图6-3  磁盘结构示意图(上为俯视图,下为侧视图)

  磁盘在启动后高速旋转。每个磁面上有一个磁头,可以在不同磁道之间来回移动。扇区的定位参数有三个,即柱面号、磁头号和扇区号。访问磁盘时,先将磁头移动到指定的柱面上,等待要访问的扇区转到磁头下,然后指定的磁头开始读/写数据。

  2. 磁盘空间的逻辑结构
  由于磁盘是高速设备,一次读/写操作可以同时访问多个相邻的扇区(通常是在同一柱面上)。因此,文件系统在读/写磁盘时不是以扇区为单位,而是以块为单位的。(block)由若干个相邻的扇区组成,它是对存储空间的逻辑划分。块的大小依赖于文件系统的设置和磁盘容量,但必须是扇区大小的2的整数倍,并且要小于内存页帧的大小。通常块的大小是512 B1 KB4 KB
  在文件系统看来,磁盘的存储空间是由许多在逻辑上连续的块组成的,它们从
0n编号,如图6-4所示。文件系统以块为单位保存文件数据,也以块为单位传输数据。所以称这类存储设备为块设备。访问文件时,只要指定块号即可,不必关心它对应的扇区的位置,磁盘驱动程序会进行逻辑块到物理块(扇区)的转换。

图6-4  磁盘存储空间的逻辑结构

  3. 文件的物理结构
  文件的物理结构主要有3种:连续文件链接文件索引文件
  
1) 连续文件
  连续文件的存储方案是将文件的内容按逻辑顺序存放在连续的存储块中,这是最简单的存储分配方案,如图6-5所示。假设磁盘空间采用4K大小的块,文件A的大小为25K,系统为它分配了连续的7块。文件B的大小为10K,系统为它分配了连续的3块。它们的存储空间是连续的,起始块号和占用的块数都记录在它们各自的目录项中。

图6-5  连续文件的存储结构示意图

  连续存储方案的优点是简单、存取速度快。由于文件内容是连续存放的,访问时磁头移动较少,因而无论顺序存取还是随机存取,其性能都很好。它的缺点之一是限制了文件的动态增长。另一个缺点是磁盘碎片问题,即经过一系列的文件空间分配和回收操作后,空闲空间逐渐变得支离破碎,无法容纳新文件。磁盘碎片降低了外存空间的利用率,需要经常进行磁盘压缩整理。由于这些缺点,连续文件不适合用于磁盘等直接存取设备。它主要用于在顺序存取设备(如磁带)或只读存储设备(如只读光盘)上存储文件。

  2) 链接文件
  链接文件的存储思想是:文件内容可以存放在彼此不连续的存储块中,用指针拉链的方式表示文件内容的逻辑顺序。做法是:每个块留出一个空间来存放指向下一块地址的指针。在目录项中记录了文件首块的磁盘地址,从首块出发可以依次找到其他各块,如图6-6所示。图中,文件A占用了4个存储块,依次是1→2→9→11;文件B占用了5个存储块,依次是5→6→3→15→18。

  与连续存储方案相比,链接存储中不再有磁盘碎片问题,因为每个块都可以被利用。然而,链接文件的主要缺点是存取效率问题。由于不是连续存放,造成访问时磁头移动次数较多,顺序存取还算方便,但直接存取就相当缓慢了。另外,由于指针占去了一些字节,每个块的字节数不再是2的幂,增加了读/写操作的复杂度。因为大多数程序都是以2的幂为长度来读/写块的。

图6-6  链接文件的存储结构示意图

  目前,实际使用的链接文件是针对以上问题进行了改进的方案。改进的思想是将指针部分从存储块中提出来,单独存放在一个链接表中。链接表的每一项对应一个存储块,其内容是该块所链接的下一个块的块号。图6-7所示是文件分配链接表方案的示意图。图中描述了与图的分配情形相同的两条块号链,一条是文件A的链,从表项1开始;另一条是文件B的链,从表项5开始。

图6-7  文件分配链接表示意图

  链接表占用的空间小,可以放在内存中。当需要访问文件时,只要在表中顺着链进行查找即可,不需要访问磁盘,因而提高了文件定位的速度。Windows的FAT文件系统采用的就是这种改进的链接文件结构。
  链接文件的
优点是允许文件长度动态变化,外存空间利用率高;缺点是存取效率(尤其是直接存取的效率)较连续文件低。对小文件来说没有问题,但文件越大存取效率就越低。因此,链接文件更适合于小型文件系统。

  虽然在建立文件时文件系统会尽量为文件分配连续的区域,但经过一段时间的文件动态增长或缩减操作后,文件的各存储块可能会变得过度分散,各文件的块链穿插交错,使存取效率大大降低。为解决这个问题,Windows的FAT文件系统采用了磁盘整理的方法。当文件访问效率下降时,通过磁盘整理来重新调整文件在存储空间中的分布,使其尽可能连续。

  3) 索引文件
  索引文件的存储方案也是允许将文件内容存放在不连续的存储块中,但它是用索引表来建立文件内容与存储块之间的联系的。索引文件的分配思想与页式内存分配很相似,索引表就如同页表的作用。图6-8所示为索引文件的存储结构示意图,文件A占用了4块,依次是第709、14块。通过文件的索引表可以直接找到各块。

图6-8  索引文件的存储结构示意图

  索引文件具有链接文件的优点,文件定位速度更快,顺序存取和随机存取效率都比较高。索引文件的缺点是占用的存储空间较多,因为索引表本身需占用一定的存储空间。对于只有12块的小文件来说,虽然其索引表很小,但也要占用同样的存储空间。因此,对于小文件较多的系统来说,空间的浪费比较明显,索引表的查找速度优势也并不明显。总的说来,索引文件更适合于追求性能的大中型文件系统,如UnixLinux的文件系统都采用了一种多重索引的文件结构,具体介绍见7.3.1小节。

7.1.4  文件的共享与保护
  1. 文件共享

  在多用户系统中,有时会有多个用户需要使用同一个文件的情况,比如一个项目组成员都要用到某些项目文件。如果每个用户都保存一个文件副本则会浪费很多的存储空间。文件共享是指允许一个文件被多个用户或进程共同使用。这样可以节省存储空间和传输时间,并可避免因存在多个文件副本而可能发生的不一致的现像。

  实现文件共享的方法是链接法。当需要共享某个已存在的文件时,可以建立一个特殊的文件,称为链接文件。这个文件有独立的文件名,但并无实际的文件内容,它的作用是建立一条到共享文件的通路。因此,链接文件名可以看做原共享文件的别名,它们都指向相同的文件内容,访问链接文件就是在访问共享文件本身。在Linux系统中,链接文件被作为一种特殊的文件类型来对待,关于链接法的更详细的介绍见7.3.1小节。
  对于共享文件,可能会发生多个进程同时存取同一文件的情况,文件系统必须提供同步控制机制,以保证文件内容的完整性。

  2. 文件的保护
  文件保护的目的是防止文件被未授权的用户访问,造成泄密或意外的破坏。在多用户系统环境下,文件保护特重要。
  
保护文件的主要手段是控制用户对文件的存取权限。文件的存取权限包括读、写和执行权。适当地设置存取权限可以防止文件泄密、毁坏和被非法使用。
  不同的用户对文件的权限要求也是不同的,因此在权限分配时要根据用户的性质、职能、需求等对用户进行分类,对不同种类的用户分别授权。当用户进行文件操作时,系统根据用户的身份和文件的权限设置判断用户是否有权执行这个操作。符合存取权限的操作将被执行,违反权限的操作系统将拒绝执行。

  通常有两种用户分类方法:一是将用户分为系统管理员和普通用户两类,所有普通用户具有相同的访问权限。这是一种比较粗糙的分类,一般用于个人操作系统。另一种是Unix/Linux采用的分类方法,将用户分为超级用户、文件属主、组用户和其他用户4类。可以为每类用户设置不同的访问权限,从而实现了细粒度的权限控制。

7.1.5  文件存储空间的管理
  文件系统要对文件的存储空间进行管理,管理工作包括:建立文件时为文件分配存储空间;删除文件时回收文件占用的存储空间;修改文件时动态地分配和回收文件的存储空间。不同的文件系统对文件存储空间的管理方案也不同,常用的管理方案有以下3种:

  1. 位示图
  位示图是由若干个字节组成的一张表,如图6-9所示。每个字节的每一位对应一个存储块的状态,为“1”表示该块已被占用,“0”表示该块空闲。
  
位示图法适合于索引文件。分配时,先扫描位示图,找到足够的空闲块(对应位为“0”),分配给文件,并将对应的位改为“1”;回收时,将对应的位改为“0”即可。
  由于位示图的体积较小,可以全部或部分保存的内存中,因此可实现高速的分配算法。

图6-9  位示图

  2. 空闲区表
  空闲区表是记录连续的空闲区域的表格,表格中的每一项记录一个空闲区的起始块号和块数,如图6-10所示。
  
空闲块表法适合于连续文件。分配时,依次扫描空闲区表,查找大小合适的空闲区,分配给文件。如果空闲区大小正好是文件需要的块数,则删去该表项;否则修改该表项,扣除被文件占用的区域。回收时,将文件释放的区域填入空闲区表。如果与其他空闲区发生邻接,则将邻接区域的表项合并。

图6-10  空闲块表

  3. 空闲块链表
  将所有空闲块的块号用链表形式链在一起就形成了一个空闲块链表,如图6-11所示。
  
空闲块链表法适合于链式文件。分配时,从链表头取下若干链表节点,将对应的空闲块分配给文件使用;回收时,将文件释放的空闲块的块号链入链表中。

图6-11  空闲块链表

      7.2  Linux文件系统
7.2.1  Linux文件系统的特点
  Linux继承了Unix文件系统的优秀设计,并结合了一些现代文件系统的先进技术,在开放性、可扩展性和性能方面都十分出色。以下介绍Linux文件系统的几个主要特征。

  1. 支持多种文件系统
  许多操作系统(DOSWindows)只支持一种或几种专用的文件系统,而Linux系统则可以支持几乎所有流行的文件系统。这使得Linux可以和许多其他操作系统共存,允许用户访问其他操作系统分区中的文件。用户可以使用标准的系统调用操作各个文件系统中的文件,并可在它们之间自由地复制和移动文件。这种兼容性带来的另一个好处是Linux用户可以根据应用需要选择最适合的文件系统,并可体验众多文件系统新产品的先进特色。

  2. 树型可挂装目录结构
  Linux系统采用了树型目录分区挂装的概念,系统分区上的文件系统称为根文件系统,其他所有分区的文件系统都要挂装(mount)到根文件系统下的某个目录下,然后通过根目录来访问。因此,与Windows系统将每个分区独立为一棵树不同,Linux文件系统总是只有一棵树,不管挂入的是本地磁盘分区还是网络上的文件系统,它们都与根文件系统无缝结合,用户访问这些分区就如同访问根文件系统所在分区一样。另外,Linux支持动态地挂装和卸载文件系统,允许用户灵活地组织和扩充存储空间。

  3. 文件、设备统一管理
  Linux将设备也抽象为文件来处理,使用户可以像读/写文件一样地操作设备进行I/O操作。这样做既简化了系统结构和代码,又方便了用户对设备的使用。在第7章中将介绍Linux如何通过文件系统来管理设备。

7.2.2  Linux文件系统的结构
  Linux文件系统采用了分层结构的设计,如图6-12所示。
  Linux文件系统由以下几个主要部分组成:

图6-12  Linux文件系统的结构

  1. 设备驱动程序
  文件系统需要利用存储设备来存储文件,因此,存储设备是文件系统的物质基础。除此之外,Linux系统中的其他设备也是作为文件由文件系统统一管理的。所有这些设备都由特定的设备驱动程序直接控制,它们负责设备的启动、数据传输控制和中断处理等工作。
  
Linux的各种设备驱动程序都通过统一的接口与文件系统连接。文件系统向用户提供使用文件的接口,设备驱动程序则控制设备实现具体的文件I/O操作。

  2. 实际文件系统
  文件系统是以磁盘分区来划分的,每个磁盘分区由一个具体的文件系统管理,不同分区的文件系统可以不同。Linux系统支持多种不同格式的文件系统,除了专为Linux设计的Ext2/Ext3JFSXFSReiserFSNFS之外,还支持Unix系统的sysvufsbfsMinix系统的minxXIAWindows系统的FAT32NTFSDOS系统的FAT16,以及OS/2系统的hpfs等。这些文件系统都可以在Linux系统中工作。Linux默认使用的文件系统是Ext2/Ext3

  3. 虚拟文件系统
  实际文件系统通常是为不同的操作系统设计和使用的,它们具有不同的组织结构和文件操作接口函数,相互之间往往差别很大。为了屏蔽各个文件系统之间的差异,为用户提供访问文件的统一接口,Linux在具体的文件系统上增加了一个称为虚拟文件系统(Virtual File SystemVFS)的抽象层。
  虚拟文件系统运行在最上层,它采用一致的文件描述结构和文件操作函数,使得不同的文件系统按照同样的模式呈现在用户面前。有了VFS,用户觉察不到文件系统之间的差异,可以使用同样的命令和系统调用来操作不同文件系统,并可以在它们之间自由地复制文件。

  4. 缓存机制
  文件系统和存储设备进行数据传输时采用了缓存技术来提高外存数据的访问效率。缓存区是在内存中划分的特定区域。每次从外设读取的数据都暂时存放在这里。下次读取数据时,首先搜索缓存区,如果有需要的数据,则直接从这里读取;如果缓存区中没有,则再启动设备读取相应的数据。对于写入磁盘的数据,也先放入到缓存区中,然后再分批写出到磁盘中。使用缓存技术使得大多数数据传输都直接在进程的内存空间和缓存区之间进行,减少了外部设备的访问次数,提高了系统的整体性能。
  
VFS文件系统使用了缓冲区缓存、目录项缓存以及i节点缓存等技术,使得整个文件系统具有相当高的效率。

        7.3  Ext2文件系统
  Ext2(Extended-2)文件系统是专为Linux系统设计的一种文件系统。它采用的是Unix文件系统的设计思想,运行稳定,存取效率也很高,可支持最大4 TB(1T=1024G)的磁盘分区。2000年以前,它一直是几乎所有的Linux发行版的默认的文件系统。
  
Ext2的弱点在于它是一个非日志文件系统。日志文件系统可以在系统发生断电或者其他系统故障时保证文件数据的完整性,这对关键行业的应用是十分重要的。近年来Ext2已逐渐被它的升级版Ext3取代。Ext3是一个基于Ext2开发的日志文件系统。它具有健全的日志功能,可靠性很高。在非正常关机后,文件系统可在数十秒钟内自行修复。另外,Ext3文件系统的容量有了很大的提高,可以支持最大32 TB的文件系统和最大2 TB的文件。目前Ext3已被许多Linux发行版作为默认安装的文件系统。

  目前,第4代Ext文件系统Ext4正处于试用阶段。Ext4最为显著的改进是文件和文件系统的大小。Ext4文件系统的容量达到1024 PB(1P=1024T),而文件大小则可达到16 TB
  本节对
Ext2文件系统进行分析和介绍,其基本结构和操作同样也适用于Ext3和Ext4。

7.3.1  Ext2文件的结构
  Ext2文件的逻辑结构是无结构的流式文件。基于字节流的概念,使得Linux系统可以把目录、设备等都当作文件来统一对待。Ext2文件的物理结构采用易于扩展的多重索引方式,便于文件动态增长,同时也可以方便地实现顺序和随机访问。

  1. Ext2文件的描述
  Ext2文件系统采用了改进的FCB结构来描述文件
  
FCB要描述的信息比较多,所以一般要占较多的空间。当目录下的文件很多时,目录文件(其内容是目录项列表)就会很大,往往需要占用多个存储块,这将导致目录检索的效率下降。改进的方法是将FCB分解为两个部分:主部和次部FCB主部包含除文件名之外的全部信息,称为索引节点或i节点。次部只包含文件名和主部的标识号码(i节点号)。文件目录由各文件的FCB次部组成,主要实现按名检索的目的。由于目录项(FCB次部)很小, 目录文件也就很小, 按文件名检索的速度很快,检索到后就可以立即找到文件的i节点了。

  Ext2目录项(directory entry)主要包括文件名和i节点号两部分。i节点号用于指示i节点的存放位置,文件名用于文件检索。Ext2文件系统支持最长255个字符的长文件名。
  
Ext2文件系统采用索引节点(inode)方式来描述文件,系统中的所有文件(包括目录和设备)都对应一个唯一的i节点。i节点的内容包含文件说明信息和索引表两部分,文件说明信息部分包括模式(访问权限与类型)、所有者(属主和属组)、长度、时间戳、连接数等信息。索引表部分是指向文件存储块的索引指针。
  图
6-13是Ext2文件的目录项和索引节点的结构。

图6-13  Ext2文件的描述

  2.  Ext2索引结构
  Ext2文件采用了多重索引的物理结构,用i节点中的索引表描述,见图6-14
  索引表中前
12个表项是直接指针,直接指向文件的数据块。这些块称为直接块。第13个表项是一个一级间接指针,它指向一个索引块。索引块中存放的是间接索引表,通过间接索引表中的指针再指向数据块。这些由间接指针指向的块称为间接块。类似的,索引表的第14项和第15项提供了一个二次间接和一个三次间接指针,可提供对更多的间接块的索引。提供多级间接指针的目的是为了表达大型文件的结构。

图6-14  Ext2文件的多重索引结构

  Ext2文件系统的默认块大小是1 KB。对于12K以下的小文件,不需要使用间接索引,所有信息均在i节点中,因此访问的速度非常快。大一些的文件,需要用到一个间接索引块。
  一个间接索引表含有
256个间接指针(每个指针占4字节,则1K大的块可容纳256个指针),可以索引256个间接块。因此,大小在12K268K的文件需要一次间接,访问速度会有所降低。而对于大型的文件,可以使用二次间接甚至三次间接指针,得到最大约16 GB的文件。

  3. Ext2目录文件的描述
  目录文件的描述结构与普通文件一样,每个目录文件对应一个目录项(在其父目录中)以及一个i节点。不同之处在于目录文件的内容数据块中存放的是一个目录项列表,包含了该目录下的所有文件的目录项,头两个目录项是“.”和“..”Ext2目录结构如图6-15所示。

图6-15 Ext2目录结构

  目录文件A的内容是一个含有6个目录项的列表,其中“.”文件就是本文件的别名,它的i节点域指向了本文件的i节点,“..”文件是父目录文件的别名,它的i节点域指向了父目录文件的i节点(根目录的“..”就是其自身)。其余4个表项分别对应了目录A下的BCDE子文件,其中文件B是一个子目录,文件C是一个普通文件。文件D和E是一个共享文件。

  4.  Ext2文件的定位
  按名查找是文件系统要提供的一项重要功能。当用户需要打开某个文件时,只要指定文件的路径和名称即可。文件系统根据路径和文件名,从根目录开始逐级向下找到文件所在的目录,再找到文件的索引节点,然后就可以通过索引节点访问文件中的数据了。这个过程就是文件的定位。例如,要查找文件/home/zhuge/memo文件,定位过程如下:
  
(1) 在超级块中找到根目录“/”的索引节点(1i节点),通过它找到根目录文件的内容,即根目录项列表,如图6-16(a)所示。

  (2) 在根目录项列表中查找home目录文件的索引节点(6i节点),通过它找到/home目录的目录项列表,如图6-16(b)所示。
  
(3) /home目录项列表中查找zhuge目录文件的索引节点(17i节点),通过它找到/home/zhuge目录的目录项列表,如图6-16(c)所示。
  
(4) /home/zhuge目录项列表中查找memo文件的索引节点(60i节点),这就是目标文件的索引节点。通过它找到/home/zhuge/memo文件的内容,如图6-16(d)所示。
  随后的文件访问操作都将通过这个索引节点进行。

图6-16  文件的定位过程

  5. 文件的链接
  文件链接是实现文件共享的主要方式Linux系统提供了两种文件链接方式,即符号链接和硬链接,用link()系统调用实现。用户可以用ln命令建立文件链接。
  
符号链接(symbolic link)很像Windows系统中的快捷方式,即建立一个符号链接文件,其内容是到一个实际存在的文件的路径描述。访问符号链接文件时,系统将根据其记载的内容转去访问那个实际文件。符号链接文件与目标文件是两个独立的文件,有着各自的i节点和数据块。它们之间通过文件内容而逻辑地链接在一起。

  硬链接(hard link)则是将两个或多个文件通过i节点物理地链接在一起。硬链接的文件具有不同的文件名和同一个i节点,通过其中任何一个文件名访问得到的都是同一内容,这就如同是一个文件具有多个别名。图中的文件DE就是硬链接的一个例子。硬链接文件的目录项可以在同一目录下,也可以在不同的目录下,但不能跨越文件系统(即分区)。
  

       文件的i节点中记录了该文件的连接数,用ls -l命令可以显示出文件的连接数。连接数表示连接到该i节点的文件目录项的数目。新建的普通文件的连接数为1,每建立一个与它相连的硬链接文件时其连接数就增1。图中的文件C的连接数是1,文件DE的连接数都是2。删除一个文件时,实际是删除它的目录项并将其i节点的连接数减1,若连接数为0才真正释放文件的i节点和数据块。

符号链接示例:



再看看硬链接:

  新建目录的连接数为2,对应了两个文件名,即本目录名与“.”。每当在其下建立一个子目录时,它的连接数就增1,因为它在子目录下又有了它的另一个文件名,即“..”。例如,图中的目录a的连接数为3,目录b的连接数为2。 

 

  7.3.2  Ext2文件系统的格式
  Ext2文件系统在格式化时把它所占用的磁盘分区分为一个引导块和若干个块组。每一个块组都由超级块、组描述符表、块位图、i节点位图、i节点区和数据块区组成,如图6-17所示。

图6-17  Ext2文件系统的物理布局

  1. 引导块与块组
  引导块位于磁盘主分区的头部,一般占用一个扇区,用来存放引导程序。引导程序负责加载操作系统,它不是文件系统的组成部分。
  除引导块外,分区的其他存储空间以
存储块为单位划分。Ext2文件系统的存储块大小可以是1 KB2 KB4 KB,在创建文件系统的时候指定。块大小的选取要合适,过大会降低存储空间的利用率,过小则会降低文件系统的时间效率,默认值是 1KB

  大型磁盘分区包含的存储块数量众多,为便于管理,Ext2文件系统它们划分为若干个块组(block group),每个块组中包含一定数量的连续的存储块。块组的大小取决于磁盘分区的大小。在软盘等一些小容量分区里一般只使用一个块组,它包含了文件系统里所有的块。而在大磁盘分区里通常会划分出许多个块组。
  每个块组中有一部分块是用来保存该块组的
管理信息的,包括超级块、组描述符、块位图和i节点位图。其余的块是用于保存文件的,包括i节点区和数据块区。

  2. 超级块和组描述符
超级块(super block)  
它占用一个存储块,位于每个块组的最前面,每个块组包含超级块的内容是相同的(超级块在每个块组的开头都有一份拷贝)
 ♠描述整个文件系统的基本管理信息
 系统运行期间,把超级块复制到系统缓冲区内,只需把块组0的超级块读入内存,其它块组的超级块做为备份
 ♠若超级块损坏则整个分区的文件系统不再可用。

  块组描述符(Group Descriptor ):
 ♠用来记录该块组的使用信息,包括块组中的块位图、i节点位图和i节点区的位置、块组内存储块的分配情况等。整个分区分成多少个块组就对应有多少个块组描述符。
 ♠所有块组的组描述符集中在一起就形成了组描述符表,它是文件系统管理和访问各块组的依据。
 ♠组描述符表位于超级块之后,可能占用多个存储块。

  

  5. 位示图
  Ext2系统采用位示图方式来管理空闲空间,一个位示图用于记录数据块的分配情况,称为“块位图”;另一个位示图用于记录i节点的分配情况,称为“i节点位图”。它们各占用1个存储块。位示图中每一位代表一个块的使用情况,为“0”表示相应的块或i节点空闲,为“1”则表示已经分配。
      块位图和 i节点位图各占一个存储块。

  3. i节点区
  块组中所有可用的i节点都集中存放在一起,形成i节点区,或称为索引节点表。块组中的每个文件都在此表中占有一个i节点,通过i节点号检索。索引节点表要占用多个连续的存储块。
  
4. 数据块区
  数据块区包含了大量的存储块,用于存放文件的内容以及各级间接索引表。每个文件根据大小不同在数据块区占有1至多个存储块。

7.3.3  Ext2文件存储分配策略
  当建立一个新的文件时,文件系统要为它分配一个i节点和一定数目的数据块。当该文件被删除时,文件系统将回收其占有的i节点和数据块。当文件在读/写过程中扩充或缩减了内容时,文件系统也需要动态地为它分配或回收数据块。
  分配时根据位示图的记录为文件分配
i节点和数据块。分配策略在一定程度上决定着文件系统的整体效率。系统会尽可能把同一个文件所使用的块、同一个目录所关联的i节点存放在相邻的单元中,至少是在同一个块组内,以提高文件的访问效率。

  另外,Ext2文件系统还采用称为预分配的机制来保证文件内容扩展时块的分配效率和效果。在文件建立的时候,如果有足够的空闲块,就在相邻的位置为文件分配多于当前使用的块,称为预分配块。当文件内容扩展时,优先使用这些块,可以提高分配效率,也可以保证这些块具有连续关系。如果预分配的块用完或者是根本没有启动预分配机制,分配新块时也要尽可能保证与原有块相邻。

      7.4  虚拟文件系统
  

描述:
VFS不是实际的文件系统
VFS只存在于内存中
引入VFS的目的是为了屏蔽各种文件系统的差异。

  虚拟文件系统之所以称为虚拟,是因为它只存在于内存中,在系统启动时建立起来,在系统关闭时消失。VFS不能直接操作文件,所有对文件的实际操作都要通过实际存在于磁盘分区的文件系统来完成。因此,虚拟文件系统必须和某个或某些实际的文件系统一起才能实现完整的文件管理功能。
  
引入虚拟文件系统的目的是为了屏蔽各种文件系统的差异。它对实际文件系统进行抽像,采用统一的数据结构在内存中描述所有实际的文件系统,向用户提供一组标准的文件操作函数。VFS负责将标准文件操作映射到实际文件系统的操作。正是这种抽像和映射,保证了Linux系统可以支持多种不同的文件系统,使所有文件系统都具有基本相同的外部表现。

7.4.1  VFS的文件对象
  VFS虽然是用C语言写成的,但它其实是采用了面向对象的设计思想。VFS使用一族数据结构来描述通用的文件对象,这些结构体除了包含有一些数据外还包含了操作这些数据的函数指针。构成VFS文件系统的基本对象有以下4类:
   VFS超级块(super block),描述一个文件系统;
   VFS目录项(dentry),描述一个文件的逻辑属性;
   VFS索引节点(inode),描述一个文件的物理属性;
   VFS文件(file),描述一个文件的当前使用信息。

  VFS的对象存在于内存。它们在适当的时候被建立起来。建立时,结构体的数据由实际文件系统的相应的数据来填充,操作函数由实际的文件系统实现。VFS依据这些对象提供的信息和操作函数来完成将用户的文件请求映射到实际文件系统的操作。
  
Unix/Linux风格的文件系统与VFS文件系统有着相同的概念和很好的对应关系,可以直接从它们的对应结构中构造出VFS文件系统的对象。但像FATNTFS这样的非Unix风格的文件系统则必须经过封装,使其符合Unix文件系统的概念结构并满足VFS的要求,这样它们就可以像Ext2文件系统那样和VFS一起工作了,只是在性能上多少会受些影响。

  1.  VFS超级块
  VFS超级块对应实际文件系统的超级块,它代表一个实际的文件系统VFS超级块的内容包括:设备标识符、文件系统标志、数据块大小、文件系统的特殊信息、文件系统的使用信息以及超级块操作集等。设备标识符用来标识一个文件系统;文件系统类型和数据块大小用来描述这个文件系统的基本特征;文件系统的特殊信息对应着该文件系统的实际超级块,在挂装时被复制过来;文件系统的使用信息描述文件系统的当前状态和缓冲区指针等;超级块操作集由一组函数指针组成,主要实现对文件系统和i节点的各种管理操作。

  VFS为每个已挂装的文件系统建立一个VFS超级块,通过它来访问和管理实际文件系统。VFS超级块在挂装文件系统时建立,在文件系统卸载后撤销。在此期间,由于文件操作会修改VFS超级块的内容,造成与磁盘上的超级块内容不一致,VFS通过周期性地将所有发生改变的超级块写回磁盘来实现超级块的同步更新。

  2.  VFS索引节点
  VFS i节点对应于实际文件系统中的i节点,它代表虚拟文件系统中的一个具体的文件VFS i节点的内容包括了实际的磁盘i节点的信息,如i节点号(i_no)、访问权限(i_mode)等,另外还包括了当前文件打开状态(i_state)以及i节点操作集指针(i_op)等信息。i节点操作集用inode_operations结构描述,它由一组函数指针组成,包含了针对具体文件的各种操作,如建立和打开文件(create)、链接文件(link)等。

  系统为每个打开的文件都建立一个VFS i节点。在一个文件被打开时,VFS读入该文件的磁盘i节点的信息,为它在内存建立一个VFS i节点,并通过它来访问这个文件。文件关闭后它的VFS i节点被撤销。与超级块相同,i节点也存在同步更新的问题,所以,VFS也会周期性地将所有发生改变的i节点写回磁盘。

  3.  VFS目录项
  从图6-16所示例子可以看出,在定位一个文件时需要沿该文件的路径逐级访问路径中的各个目录。如果每次都要从磁盘读取目录文件的话,访问文件的效率就会很低。为了方便查找操作,VFS引入了目录项(dentry)的概念。目录项代表的是一个路径分量。路径由一系列的分量组成,每个分量都是一个目录或文件。例如,路径名/home/zhuge/memo中包含了“/”、“home”、“zhuge”和“memo”4个分量。当VFS首次解析一个路径名时,它依次读取路径中的每个目录或文件,为它建立一个dentry结构,每个dentry结构都与一个VFS i节点相连。VFS将这些已建立的dentry结构按目录关系链接在一起,在后续的文件查找操作中,VFS只需沿dentry的链接结构进行查找,可以很快地找到目标文件的dentry结构,然后得到它的VFS i节点。

  dentry的内容包含目录项的文件名(d_name)以及构成结构关系的各种指针,还有指向i节点的指针(d_inode)和目录项操作集的指针(d_op)等。目录项操作集用dentry_operations结构描述,它包含了对目录项的各种操作,如文件名比较(d_compare)、删除(d_delete)、释放(d_release)等。
  概括地讲,目录项是对文件的逻辑描述,它描述的是文件的逻辑标识
(文件名)以及该文件与其他文件的逻辑关系(其在目录树中的位置),而关于该文件的物理描述则包含在它所指向的VFS i节点中。目录项与VFS i节点合起来才能完整地表示一个文件。目录项可以看作是访问一个文件的入口,查找文件就是在目录项链表中沿路径找到目标目录项的过程。
  
目录项并不对应实际文件系统中的任何成分,因此也不存在同步更新的问题。

  4.  VFS文件
  从用户(也就是进程)的角度来看,它们直接处理的是文件,它们关心的是文件的访问模式、读/写位置等属性以及读、写等操作,而不是超级块和i节点。VFSfile对象来描述进程所关心的文件,每当进程打开一个文件,VFS都将为它建立一个file结构。file结构的内容包括文件打开模式(f_mode)、读/写位置指针(f_pos)、文件访问计数(f_count)、文件的目录项指针(f_dentry)和文件操作集指针(f_op)等。打开模式、读/写位置和访问记数描述了文件的当前使用状态,目录项指针用于连接文件的目录项。文件操作集用file_operations结构描述,它由一组对文件内容进行操作的函数指针组成,包含了标准系统调用的那些函数,如read()wirte()lseek()等。
  
VFSi节点、目录项和文件对象的结构关系如图6-18所示。

图6-18  VFS文件的描述结构

  图中3个对象完整地表示了一个进程可用的文件。各个对象都带有自己的操作集,它们的作用是将对该文件执行的标准操作映射到实际文件系统的具体操作函数上。这也是VFS实现标准接口功能的关键。

7.4.2  VFS缓存
  为了提高文件访问的速度,VFS使用了一些复杂的缓存技术。VFS系统设置了目录项缓存(dcache)i节点缓存(icache)和缓冲区缓存(buffer cache),见图。这些缓存都是由VFS管理的。设置缓存的目的是为了减少访问磁盘的次数,提高文件的查找和读/写效率。
  文件系统经常会访问某些常用的文件和目录
(比如/usr目录等),为避免重复创建i节点和目录项的操作,VFS设置了i节点缓存和目录项缓存,用于保留已创建的VFS i节点和dentry结构。每当需要访问一个i节点时,系统先在i节点缓存区中找,如果找到就直接使用,否则再从磁盘读入i节点并构造VFS i节点。同样,每当需要访问一个目录项时,VFS先在目录项缓存中查找,如果有就直接使用,没有时再去创建它的dentry结构。

  文件内容的读/写是一件耗时的操作。为减少实际访问磁盘的次数,VFS设置了缓冲区缓存。当文件系统与磁盘设备交换文件数据时,它们通过缓冲区缓存对I/O操作进行缓冲,同时将传输的数据缓存起来。当下一次读/写文件时,VFS先在缓存区中查找,若命中则直接使用,否则再启动设备传输数据。有关缓冲与缓存技术的进一步介绍见7.2.2小节。

7.4.3  VFS与进程的接口
  VFS为进程提供了访问文件系统的统一接口。接口由fs_structfile_struct结构构成。
  
fs_struct结构描述进程与文件系统的关系,主要内容包括进程使用的创建文件掩码(umask)、根目录的目录项指针(root)和当前目录的目录项指针(pwd)等。
  
file_struct结构体包含了该进程已经打开的所有文件的信息,主要是一个fd数组,数组的每一项fd[i]是一个指向一个file结构的指针。fd[i]的下标i称为文件描述符。进程初启时,自动打开stdinstdoutstderr三个文件,文件描述符分别为012。以后每当进程打开一个新文件,系统就在fd数组中选定第一个空闲的单元来存放指向该文件的file结构的指针,并返回对应的数组下标作为文件描述符。

  图描述了进程和文件系统的接口结构。进程控制块task_struct中包括两个指针,一个是fs,指向进程的fs_struct;另一个是files,指向进程的file_struct。进程通过这两个指针得到有关文件系统和打开文件的信息,再通过它们获得文件的目录项、i节点以及它们的操作集。
  图
6-19中右侧3列是VFS系统部分,包括系统打开文件表、目录项表和i节点表。它们分别是由系统中所有打开文件的file结构、dentry结构和inode结构形成的链表。最左侧是进程PCB。中间的fs_struct结构和file_struct结构起到进程与VFS接口的作用。
  
fd[0]fd[1]fd[2]所连接的file结构是系统为进程自动打开的文件,通常是终端设备的file结构。如果进程的I/O环境被重定向,则相应的fd项就改为连接其他文件的file结构。

图6-19  进程与FVS文件系统的接口

7.4.4  文件系统的注册、挂装与卸载
 注册: 
      为了使VFS能够支持某种类型的文件系统,文件系统必须向VFS注册Linux内核内在地支持一些类型的文件系统,这些文件系统在系统启动时自动地注册到VFS中。其他类型的文件系统可以以内核可加载模块的形式动态地挂装到系统上,在模块安装时进行注册。
  
VFSfile_system_type结构来描述每个已注册的文件系统,该结构记录了文件系统类型名(ext2proc等)和超级块读取函数等。

挂装:  
        一个文件系统必须先挂装才能使用。挂装的主要工作就是建立它的VFS超级块。系统在初始化时首先挂装上根文件系统“/”,其余的文件系统都挂装在根文件系统的某个目录下。在文件系统挂装时,VFS将根据文件系统的类型找到对应的注册结构,然后调用其中的超级块读取函数来为它建立VFS超级块。
  
VFSvfsmount结构描述每个已挂装的文件系统,该结构记录了文件系统所在的设备名、挂装点的目录名、超级块指针等信息。VFS通过vfsmount结构找到文件系统的VFS超级块,然后就可以对该文件系统进行操作了。
  

卸载:
        当文件系统不再使用时可以将它卸载。卸载时将释放它的VFS超级块和vfsmount结构。

7.4.5  文件系统的操作
  用户进程使用VFS提供的一组系统调用来进行文件操作,VFS负责将这一组系统调用映射到实际文件系统的文件操作函数上。这是通过在VFS的超级块、目录项、i节点和文件结构中的操作集来实现的。这些操作集统一地定义了对超级块、目录项、i节点和文件的所有操作的接口,它们通过函数指针连接到文件系统的某个操作函数上,完成具体的文件操作。以下介绍文件系统的几个主要系统调用函数。

  1. 文件的打开与关闭
  打开一个文件的系统调用是open(),它带有两个参数,一个是文件的路径名pathname,另一个为打开模式flag。调用成功后返回给进程一个文件描述符fd
  所谓打开文件实质上就是在内存中构建起该文件的
VFS对象,在其与进程之间建立起一个连接,并用文件描述符来标识这个连接。打开文件的具体动作是:根据文件的路径名找到或建立该文件的dentryinodefile对象,在进程的file_struct结构中找到一个空闲的fd数组项,将file对象连到该表项中,返回该表项的下标,这个下标就是该打开文件的文件描述符。

  若打开一个已经打开的文件(通常是被其他进程打开的),则其file结构已经存在。此时只需找到该文件的file结构,将其连到本进程的file_struct中的一个fd数组项上,并将file结构中的引用计数f_count1,返回fd数组项的下标即可。
  关闭一个文件的系统调用是
close(),参数是文件描述符fd。所谓关闭文件就是断开进程与该文件之间的连接。具体的动作是释放该文件的file结构在file_struct表中占用的fd,将file结构中的引用计数f_count1,如果引用计数为0了还要释放这个file结构。

  2. 文件的读与写
  读/写文件的系统调用是read()write()。它们都带3个参数:文件描述符fd、内存区地址buf,以及要传送的字节数count。文件在读/写前必须是已经打开的,系统通过fd的值在进程的file_struct中检索fd数组,得到文件的file结构和i节点,根据file结构中的f_modei节点中的i_mode检查文件的访问权限,然后通过file结构的f_op找到read()write()操作函数,用这个函数完成数据的读/写。读/写操作的起始位置是file结构中的当前文件位置标志f_pos。打开之初,f_pos的值为0。读/写操作结束后f_pos会相应地更新。读/写操作前可以先用lseek()设置f_pos的值。

        习    题
  6-1  什么是文件?什么是文件系统?文件系统的功能是什么?
  
6-2  什么是文件的逻辑结构和物理结构?
  
6-3  文件的物理结构主要有哪几种?它们有什么特点?
  
6-4  什么是目录?目录的作用是什么?
  
6-5  Linux文件系统采用了什么样的逻辑结构和物理结构?
  
6-6  Linux采用什么样的目录结构?这种目录结构有什么特点?
  6-7  Linux的目录文件与普通文件有何区别?

  6-8  什么是符号链接和硬链接?两者有什么区别?
  
6-9  Ext2文件系统中,超级块、组描述符、i节点指的是什么?它们的作用是什么?
  
6-10  什么是虚拟文件系统?它的作用是什么?它与实际文件系统有何关系?
  
6-11  VFS中有哪些主要对象?它们各自描述什么信息?
  
6-12  VFS的超级块与Ext2的超级块之间有什么关系?VFSi节点与Ext2i节点之间有什么关系?
  6-13  打开文件的操作主要是什么?文件描述符是什么?它有什么作用?
     

猜你喜欢

转载自blog.csdn.net/weixin_41939983/article/details/107484998
今日推荐