第 6 章 文件系统
DESCRIPTION
第 6 章 文件系统. 6.1 文件系统概述 6.2 文件管理 6.3 目录 6.4 逻辑文件系统 ——Ext2 6.5 虚拟文件系统 ——VFS 6.6 小结 习题. 数据处理是计算机的主要功能之一,与数据处理相关的数据管理和数据保存是必不可少甚至是较为重要的环节。在计算机中,大量的数据和信息是通过文件存储和管理的。文件系统负责管理文件和逻辑文件系统,提供管理设备、屏蔽设备复杂性的手段,为系统内核其他部分、用户命令和系统函数调用提供统一的服务接口。 - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/1.jpg)
第 6 章 文件系统6.1 文件系统概述6.2 文件管理6.3 目录6.4 逻辑文件系统—— Ext26.5 虚拟文件系统—— VFS6.6 小结习题
![Page 2: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/2.jpg)
数据处理是计算机的主要功能之一,与数据处理相关的数据管理和数据保存是必不可少甚至是较为重要的环节。在计算机中,大量的数据和信息是通过文件存储和管理的。文件系统负责管理文件和逻辑文件系统,提供管理设备、屏蔽设备复杂性的手段,为系统内核其他部分、用户命令和系统函数调用提供统一的服务接口。本章主要讨论 Linux 系统中文件的概念、 目录结构及访问权限, Linux 的逻辑文件系统 Ext2 , 虚拟文件系统 VFS , 文件系统管理及缓冲区管理等内容。管道( FIFO )文件是利用文件系统作为接口实现进程间的通信,本章不再介绍,具体原理请参见 2.2.6“ 进程通信”部分。
![Page 3: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/3.jpg)
6.1 文件系统概述通常我们把与管理文件有关的软件和数据,统称为文件系统。它方便地组织管理计算机中的所有文件,为用户提供文件的操作手段和存取控制。同时,文件系统隐藏了系统中最为纷繁复杂的硬件设备特征,为用户以及操作系统的其他子系统提供一个统一、简洁的接口,通过文件系统,使得用户方便地使用计算机的存储、输入 / 输出等设备。
![Page 4: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/4.jpg)
在学习 Linux 进程管理时,我们也许注意到,系统惟一感知和控制进程的关键数据——进程控制块中,除了 CPU 和内存资源之外,只包含了文件系统信息和文件信息,而没有设备的任何信息,这就是文件系统所起的作用。 Linux 系统中把 CPU 、内存之外所有其他设备都抽象为文件来处理。进程只和文件系统打交道,具体的细节,由设备管理部分具体实现并为文件系统提供尽可能简洁统一的接口。因此,文件系统还同时充当着设备管理接口的角色,用户进程使用和操作具体的设备,都必须通过文件系统进行。文件系统是操作系统中与管理文件有关的所有软件和数据的集合。
![Page 5: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/5.jpg)
不同的操作系统可能采用不同的文件系统。支持多种不同类型的文件系统是 Linux 操作系统的主要特色之一。 Linux 系统自身的文件系称为 ext2 ,它也是 Linux 默认的文件系统。我们把 ext2 以及 Linux支持的文件系统称为逻辑文件系统, 通常每一种逻辑文件系统服务于一种特定的操作系统,具有不同的组织结构和文件操作函数,相互之间差别很大。Linux 在传统的逻辑文件系统的基础上,增加了一个称为虚拟文件系统( VFS )的接口层,如图 6.1所示。
![Page 6: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/6.jpg)
图 6.1 Linux 文件系统层次结构示意图
![Page 7: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/7.jpg)
系统中所有的设备,包括字符设备、块设备和网络设备,都按照某种方式由逻辑文件系统统一管理,逻辑文件系统为它们提供访问接口。虚拟文件系统在最上层,管理各种逻辑文件系统,屏蔽了它们之间的差异,为用户命令、函数调用和内核其他部分提供访问文件和设备的统一接口, 使得不同的逻辑文件系统按照同样的模式呈现在使用者面前,对于普通用户来讲,觉察不到逻辑文件系统之间的差异,可以使用同样的命令来操作不同逻辑文件系统所管理的文件,可以在它们之间自由地复制文件。
![Page 8: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/8.jpg)
6.2 文件管理6.2.1 文件文件可以简单地理解为一段程序或数据的集合。在操作系统中,文件被定义为一个命名的相关字符流的集合,或者一个具有符号名的相关记录的集合。符号名用来惟一地标识一个文件,也就是文件名。 Li
nux 系统中,文件名最大长度由 NR-NAME-LEN控制,默认值为 255 个字符。文件定义中所指出的不同基本组成单位表示了两种形式的文件。相关字符流组成的文件是一种无结构文件或流式文件。相关记录组成的文件称为记录式文件。记录式文件通常主要用于信息管理。
![Page 9: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/9.jpg)
在 UNIX 、 Linux 等操作系统中,把包括硬件设备在内的能够进行流式字符操作的内容都定义为文件。 Linux 系统中文件的类型包括:普通文件,目录文件,连接文件,管道( FIFO )文件、设备文件(块设备、字符设备)和套接字。
Linux 系统把文件按照其性质、用途等标准划分为不同的类别。操作系统根据文件的类型处理文件。按照用途,文件可以分为:系统文件、库文件和用户文件。系统文件直接和操作系统本身有关,包括操作系统核心和各种系统应用程序和数据;库文件通常指系统提供给用户调用的各种标准过程、函数和应用程序;用户文件是用户委托计算机文件系统管理的文件。
![Page 10: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/10.jpg)
当然,这只是一种相对的标准,对于 Linux 系统,根据自己的实际需要,具有特殊权限的用户(系统管理员)可以重新修改并编译升级整个内核,这个过程将会修改大部分系统文件,同时库文件也可以按照自己的需要添加和修改。根据文件中数据的表示形式,可以把文件划分为 AS
CII码文件和二进制文件。按照文件操作过程中的保护级别,文件可以划分为只读文件、读写文件、可执行文件, Linux 操作系统通过这样的方式来控制文件的访问权限。按照文件中信息流向还可以把文件分为输入文件、输出文件和输入 / 输出文件。按照文件在系统中的存在时间,可以把文件分为临时文件和永久文件。
![Page 11: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/11.jpg)
6.2.2 文件结构系统使用者关心的只是如何方便地组织和使用文件,即文件的逻辑结构,而系统的设计者则更关心文件具体的实现方式,也即文件的物理结构。1. 文件逻辑结构文件的逻辑结构是用户可见结构,即从用户角度观察到的文件系统。从逻辑结构来看, Linux 系统的文件采用的是字符流式的无结构文件。用户通过对文件的存取访问来完成对文件的各种操作,常用的访问方式包括顺序方式和随机方式。 Linux系统同时支持顺序和随机两种访问方式。用户对文件的操作只能通过操作系统提供的命令接口或者函数调用接口。
![Page 12: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/12.jpg)
2. 文件物理结构文件的物理结构指的是文件在存储设备上的组织方式,即一个文件在具体设备上的实现方法。外部存储器也按照一定的规则划分为小的物理单元,称为块,每个块大小相等,相应地,文件信息也划分为和外存物理块相等大小的逻辑块。对于无结构文件来讲,文件本身没有特定的逻辑结构,最小的单位是字节,可以很方便地划分为逻辑块。文件的物理结构通常解决文件的逻辑块与物理块之间的映射关系,也即一个文件对应的物理块的具体组织方式。常用的文件物理结构有顺序、串联、索引和多重索引等方式。
![Page 13: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/13.jpg)
(1) 顺序方式顺序方式按照逻辑上的连续关系把文件依次存放在连续的物理块中。如图 6.2 所示,文件逻辑块和物理块之间是最简单的线性关系,因此很容易实现,也可以相当方便地实现文件的顺序和随机访问,只要确定了文件头的位置和文件长度,一切操作都可以快速实现。但是,这些优势只有在文件能够一次性写入的情况下才存在。由于文件建立时并不知道文件的长度,系统无法确定该给这个文件分配多少个物理块。而且,这种方式也容易造成磁盘碎片。
![Page 14: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/14.jpg)
图 6.2 顺序方式文件示意图
![Page 15: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/15.jpg)
(2) 串联方式串联方式的结构采用链表来实现,每一个物理块分为两个部分,一部分用于存放数据,另一部分存放一个指针,指向后续连接的下一个物理块。存放同一个文件的物理块不需要连续,整个文件的连续性由链表的指针来保证,如图 6.3 所示。这种方法几乎可以利用每一个物理块,没有连续方式那样的碎片问题,可以实现文件的动态增长,也可以在文件中任何一个部位增加和删除内容。文件的顺序访问也可以方便地实现,但是随机访问的实现变得很复杂。
![Page 16: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/16.jpg)
图 6.3 串联方式文件示意图
![Page 17: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/17.jpg)
(3) 索引方式索引方式为每一个文件建立一张索引表,表中存放文件的逻辑块与物理块之间的对应关系。也就是把串联方式中每一个接点所记录的链表指针信息统一保存在一个索引表中,如图 6.4 所示。这使得文件的非连续存放、文件动态增长、方便的文件内部修改等串联方式的优点都保留了下来,同时,也能够方便地实现文件的随机访问。如果把整个索引表保存在内存中,整个文件的访问效率也可以大幅度提高。这种方案的问题在于索引表的处理。连续方式、链表方式、索引方式都可以用来解决索引表的存放,比较好的方案是索引方式。
![Page 18: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/18.jpg)
图 6.4 索引方式文件示意图
![Page 19: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/19.jpg)
实际中,很多操作系统采用一种称为多重索引的物理结构,同时使用单级索引和多级索引。每个文件由一张索引表描述,表中一部分内容直接指向物理块,称为直接块。索引表中同时还包含一部分二级索引指针,指向新的索引表,类似的,文件索引表中还可以包括三级甚至更高级的索引指针,提供更多的间接块。对于比较小的文件,可以直接存放在一次间接块提供的空间中,而对于较大的文件,才使用多次间接块。这种方式的缺点一是索引表本身占用存储空间,二是每次访问数据都需要先访问索引表,需要更多的系统时间开销。只要索引表设计合理,能够保证正常使用的大多数都只利用直接块,还可以把索引表放在内存中,保证系统的访问效率。
![Page 20: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/20.jpg)
这种方式基本上保证了文件的动态可变,实现了文件高效率地顺序和随机访问, Linux 系统文件的物理结构采用的就是多重索引方式,见图 6.5 。
![Page 21: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/21.jpg)
图 6.5 多重索引方式文件示意图
![Page 22: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/22.jpg)
6.2.3 Linux 文件Linux 系统的文件是无结构的流式文件,文件的物理结构采用易于扩展的多重索引方式,便于文件动态增长,同时也可以方便地实现顺序和随机访问。基于字节流的概念, Linux 系统把目录、设备等都当作文件来统一对待。 Linux 默认的是 Ext2 逻辑文件系统。
![Page 23: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/23.jpg)
Ext2 文件系统中的所有文件都采用 i 节点( i-node )来描述,每一个文件、目录或者设备都对应于一个且只能对应于一个 i 节点。每一个 i 节点包含两个部分的基本参数:文件说明信息和索引表。根据所存放的位置, i 节点又可以分为磁盘 i 节点和内存 i 节点,分别使用数据结构 ext2-inode 和 ext2-inode-info 来描述。其中磁盘 i 节点静态存放在外部存储器,包含了整个文件的完整说明信息和物理块分布情况,而内存 i 节点是为了减少设备存取次数、提高文件访问效率,在内存中特定区域中建立的磁盘 i 节点的映像。
![Page 24: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/24.jpg)
磁盘 i 节点文件说明信息包括文件名称、类型、文件长度、所占用的物理块数、创建和最近一次访问时间等基本信息,以及链接数、拥有者用户名、用户组名以及存取控制表等与文件共享、保护和保密相关的信息。每一个 i 节点的索引表前 12 个项记录文件直接物理块的位置,后面 3项分别是间接、二级间接和三级间接物理块索引,这样的方式既可以保证小文件能够快速存取,又可以适应大文件存储扩展的需要。 Ext2 文件系统物理块的大小可以是 1024 、 2048或者 4096 字节,在初始化文件系统的时候由用户指定,默认值是 1KB ,块地址占 4 字节,因此每个物理块可以存放 256 个块的地址,这样,如果把一个 i 节点所有的物理块放满,得到最大的文件应该是:
![Page 25: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/25.jpg)
直接块 + 间接块 +二次间接块 +三次间接块即:12KB+256KB+64MB+16GB实际上,在 32位 PC 上的 Linux 系统中,寻址范围 3
2位,文件最大最多只能达到 4GB 。如果一个文件的内容小于等于 12 个块,物理块采用默认值时是 12KB ,就可以全部使用直接块来存放,能够保证相当高的存取效率。 i 节点具体结构可以参看图 6.5 。内存 i 节点除了包含磁盘 i 节点的说明信息之外,还增加了当前文件打开状态信息。
![Page 26: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/26.jpg)
6.3 目录每一个文件系统都提供目录来记录文件的有关信息,在包括 Linux 在内的很多操作系统中,目录本身也是一种文件,可以按照文件进行管理,在 Linux 中称为目录文件。利用目录的层次结构,可以对系统中的文件方便地进行分隔管理,实现文件的快速搜索,解决文件之间的命名冲突,同时也可以提供文件共享的解决方案。
![Page 27: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/27.jpg)
6.3.1 目录结构最简单、最原始的结构是单级目录如图 6.6(a) 。这种结构实现简单,可以实现文件系统空间的自动管理。但是,这样的结构中,用户必须保证每一个文件的名称在整个系统中惟一。系统要访问某一个文件,必须在整张目录表中搜索,效率也较低。一个直观的扩展方式是采用两级目录结构,根目录下面可以存放文件,也可以存放下一级目录(称为子目录),子目录下面存放文件,如图 6.6(b) 。进一步推广这种层次关系,就形成了多级目录结构,每一级目录中都存放所属文件和下一级目录的信息,整个目录层次结构形成一个完整的目录树。如图 6.
6(c) 。
![Page 28: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/28.jpg)
图 6.6 文件目录结构类型
![Page 29: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/29.jpg)
树形的多级目录结构,可以更好地解决文件命名冲突问题。同时,文件系统用一个树状结构表示,根据文件不同的类型、不同的拥有者以及不同的保护要求,可以划分为不同子树,方便地实现文件的管理,在这种树形层次结构中,文件的搜索速度也更快。几乎所有的操作系统都采用树形的多级目录结构。
![Page 30: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/30.jpg)
在树形的多级目录系统中,文件名由路径名给出,路径名惟一确定一个文件在整个文件系统中的位置,可以有两种方式来表示文件的路径。一种是绝对路径名;另外一种方式是从当前目录开始,指定文件相对于当前目录的位置。当前目录是指用户当前在目录树中所处的目录位置,也称为工作目录。例如,在 Linux 系统下有路径 /home/dy/linux/kernel/sched.c ,路径的第一个字符是 Linux 系统的分隔符“ /” ,代表从根目录开始,是一个绝对路径,这个路径表明在根目录下有 home 目录,而 home下又有 dy 子目录,一直到最后的文件,文件的名称为 sched.c 。如果当前用户的工作目录是 /home/dy/linux/ ,这时相对路径 kernel/sched.c 所指得就是文件 /home/dy/linux/kernel/sched.c 。
![Page 31: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/31.jpg)
和大多数支持多级目录的操作系统一样, Linux 系统每一个目录下面都有两个特殊的目录项“ .” 和“ ..” ,前者指当前目录,而后者指当前目录的上一级目录。对于上面的例子,当前目录是 /home/dy/linux/ ,相对路径 ./kernel/sched.c 和 kernel/sched.c 具有相同的含义,而 ../指的就是 /home/dy ,因此, ../linux/kernel/sched.c 也是指 /home/dy/linux/kernel/sched.c 。
![Page 32: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/32.jpg)
6.3.2 访问权限对于普通文件、目录以及具体的设备,都存在一个访问权限(也称为存取权限)控制问题。文件存取权限即文件读、写和执行的许可权,它和文件的共享、保护及保密相互联系、密不可分。文件的共享是指不同的用户共同使用一个文件。共享和由此带来的安全性问题是一对矛盾,每一个操作系统都必须在二者之间找到一个平衡点。所谓安全性,通常包括保护和保密两层含义。
![Page 33: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/33.jpg)
1. 文件共享文件共享指允许多个用户共同使用一个文件。文件系统一般都提供文件共享方法,使得只要保存某个文件的一个副本,就可以实现多个用户在不同目录下共同访问这一副本。系统中实现共享最简单的方法就是不同的用户使用相同的绝对路径名来访问同一个文件,这种方法中,所有用户使用同样的名称来访问共享文件。如图 6.
7(a) 所示,可以看出,这种方法的主要缺陷是需要访问多级目录,多次访问外部存储器,效率低。
![Page 34: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/34.jpg)
图 6.7 文件共享方式示意图
![Page 35: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/35.jpg)
Linux 等操作系统还提供了更为简洁的链接法来实现共享。在需要访问共享文件的地方建立一个特殊的链接文件,直接指向共享文件,链接文件和原共享文件可以具有不同的名称,链接文件名也称为原共享文件的别名,它们都指向相同的文件内容,访问链接文件就是在访问共享文件本身。如图 6. 7(b) 所示。这种方法具有更高的效率,但原本完整的树状文件系统,经过链接之后变成了网状结构,一部分文件的路径不惟一,也带来一定的管理开销,在 Linux 系统中,链接文件作为一种单独的文件类型来对待。
![Page 36: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/36.jpg)
2. 访问权限控制文件的共享、保护和保密都涉及到文件访问许可权限的问题,针对不同的需要,系统可以采用多种不同的方式来控制文件的存取权限。(1) 口令方式在文件创建的时候,文件拥有者可以为每一个文件设置访问口令( password ),访问口令被记录在文件说明信息中。文件系统在用户试图访问该文件的时候,首先要求用户提供口令并与文件说明信息中记录的口令进行比较,使用者必须提供正确的文件访问口令才能够存取该文件。通过这样的方法,可以简单地实现文件的共享与保密。口令验证的过程比较简单,只是保密性能相对比较差。
![Page 37: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/37.jpg)
(2) 密码方式密码( encryption )在文件创建的时候,文件拥有者在文件写入存储设备之前,通过特定的算法和加密密钥对文件内容进行编码加密,而在读取文件的时候,必须提供相应的解密密钥进行译码解密。加密和解密可以采用相同或不同的密钥,只有确切知道解密密钥的用户才能够读出被加密的文件。口令方式中有时也采用一定的加密技术。加密口令方式只是对口令本身加密,加密后的口令仍然存放在文件说明信息中,而密码方式是对整个文件进行加密,加密时采用的密钥掌握在用户自己手中,因此,密码方式的保密性强,但是要耗费大量的处理时间。
![Page 38: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/38.jpg)
上面两种文件存取权限控制方法是针对特定文件的,在多用户系统中,还可以针对特定的用户进行文件存取权限控制。大多数系统,包括 Linux ,用户身份验证都采用用户口令方式,建立用户的时候,设置其口令,口令以加密的形式存放在系统中,每次用户登录都要提供口令,与系统中存放的数据进行比较,如果相同,用户登录成功,否则,拒绝用户登录。在这样的系统中,多个用户可能同时使用计算机,每个用户都拥有自己的文件,这些文件的存取使用控制权由用户拥有。
![Page 39: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/39.jpg)
(3) 存取控制矩阵存取控制矩阵是一个二维矩阵,其中一维是系统中所有的用户,另一维是系统中所有的文件,矩阵的每一个元素都表示该元素对应的用户对文件的存取控制权限,如图 6.8 所示。当用户对某个文件进行操作时,系统查找矩阵中该用户和该文件所对应的元素的值,只有当该元素表明有访问许可时,才可以进行具体的访问。利用这样的矩阵,可以对系统中所有文件的存取权限进行完整有效的控制。但是对于规模比较大的系统,存储和管理这样的矩阵需要比较大的系统开销。用户对每一个文件的访问,都要对矩阵的一行进行搜索,整体的效率比较低。
![Page 40: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/40.jpg)
图 6.8 文件存取控制矩阵示意图
![Page 41: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/41.jpg)
(4) 存取控制表存取控制表是针对某个特定文件,把文件拥有者和相关的用户按照某种关系划分为类,按照不同的用户类赋予用户文件存取权限。 Linux 系统中,文件的存取权限分别赋予文件拥有者、拥有者所在用户组和其他用户组这三类用户,每一类访问的权限设置三位,分别为读、写和执行,这样就相当于每个文件只需要记录 9位数据就可以进行权限控制了。实际上,每一个文件的存取控制表都相当于是整个存取控制矩阵中的一行元素。存取控制矩阵中的每一行对应于一个文件,首先去掉空元素,然后把所有的用户按照文件所有者、所有者所在组和其他用户组简化之后,就可以得到该文件的存取控制表。
![Page 42: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/42.jpg)
在 Linux 系统中,每一个文件都在文件说明信息中保存着自己的文件存取控制表,只有符合存取控制表中规定的条件,才允许进行具体的访问。对设备文件的权限设置实际上是限制了用户对设备本身的操作。设置文件访问口令和文件加密属于文件级的访问权限控制。在多用户系统中,必须要进行用户验证,文件系统针对特定的用户,可以通过存取控制矩阵或存取控制表来设置对文件的存取权限,这类方法可以认为是基于用户身份的存取权限控制,属于用户级的访问权限控制。
![Page 43: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/43.jpg)
在这些控制方法中,不论是口令还是密钥,都可以归结为口令。文件的存取控制是通过用户登录口令来控制的,因此,文件的保护、保密,关键在于用户口令的选取和保护。 Linux 系统中,文件的存取权限可以通过特定的用户命令来修改,具体的控制方法,参看本书第 3 部分相关内容。实际上,计算机硬件故障、系统软件缺陷,都会影响到文件的安全性,都可能涉及到文件的保护和保密问题,这些内容不属于本书的讨论范围。
![Page 44: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/44.jpg)
6.3.3 Linux 目录分布Linux 系统中采用的是树形的多级目录结构。只有在没有使用链接文件的情况下,整个文件系统构成完整的目录树,每一个目录或者文件都有惟一的绝对路径来确定。如果为了达到共享目的,建立链接文件之后,目录树就由树状结构变成了网状结构,被共享的文件内容可以通过不同的绝对路径来访问,造成有些文件的绝对路径不惟一。
![Page 45: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/45.jpg)
图 6.9 Linux 文件系统目录层次结构图
![Page 46: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/46.jpg)
Linux 系统根目录下通常有多个默认的子目录,它们是 bin 实用程序子目录,存放大多数用户都可以使用的常用系统工具; boot 子目录,存放系统启动时必须的内核映像等文件; dev 设备子目录,系统在这个子目录里为每个设备分配一个 i 节点; etc基本数据子目录,存放系统的用户口令、网络配置等设置文件, home 用户数据子目录,默认情况下,每个用户登录后的工作目录都设在这个目录下; lib 系统函数库子目录,存放着系统提供的动态和静态库函数; proc 系统状态子目录,通过这个目录,可以动态地了解系统内核的运行情况; root 系统管理员的用户目录; sbin 系统管理实用程序子目录;另外还有 tmp临时文件目录、 usr 用户软件子目录以及 var记载系统运行情况的日志子目录。
![Page 47: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/47.jpg)
除了这些默认的子目录之外,系统管理员还可以根据实际需要在根目录下建立新的子目录,比如专门用来安装( mount )其他文件系统的特殊子目录等等。一般用户,通常只能在自己的工作目录下或者其他得到授权的目录下工作,根据需要建立合适的子目录,安排自己的文件,未经授权,一般用户无法访问其他人的用户目录及其中的文件。
![Page 48: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/48.jpg)
6.3.4 Linux 目录文件Linux 系统中,目录也是文件的一种,称为目录文件,每一个目录也由一个 i 节点来描述, i 节点中文件类型标识这是一个目录文件,同时在对应的物理块中存放用来描述文件的目录项列表。目录项列表用来描述一个目录所包含的全部文件和子目录,每一个目录项对应着一个文件或目录,具体的数据结构为:
![Page 49: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/49.jpg)
struct ext2-dir-entry-2 { —u32 inode; /* Inode number */ —u16 rec-len; /* Directory entry length */ —u8 name-len; /* Name length */ —u8 file-type; /* File type*/ char name\[EXT2-NAME-LEN\]; /* File name */};每一个目录项中记录着该文件的名称和对应的 i 节点号等信息。任何一个目录表的前两项内容都是标准目录项“ .” 和“ ..” 。
![Page 50: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/50.jpg)
当用户给出一个完整的路径名,比如 /home/dy/linux/kernel/sched.c ,首先得到文件系统根目录对应的 i节点,读取其中的信息,根据文件类型判定是一个目录文件,在这个 i 节点保存的目录项列表中找到名称为 home 的那一项,查找该目录项就可以得到这个子目录对应的 i 节点,然后再读取该 i 节点的信息,每一个目录文件中都保存着自己所包含文件和直接子目录的目录项,逐个查找,最终可以找到所需要文件的 i 节点号,访问相应的 i 节点,通过该 i 节点的索引表,得到存储文件内容的物理块,就得到了指定文件的内容。整个访问过程中多次访问不同的 i 节点,系统是通过在内存中建立一张内存 i 节点表来实现的,查找 i 节点可以直接在内存中进行,这样就提高了文件的访问效率。
![Page 51: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/51.jpg)
6.3.5 特殊目录在系统默认的目录中,最值得注意的是 dev 设备子目录和 proc 系统进程子目录。1. /dev 子目录系统所有的设备文件都存放在 dev 设备子目录下。每一个设备文件也使用惟一的 i 节点来标识,设备文件 i 节点不指向文件系统中的任何实际的物理块,不占用数据空间,通过这个 i 节点可以访问相应的设备驱动,对设备文件的操作就是直接对设备本身进行相应的操作。 Linux 系统中有两种类型的设备文件:字符设备文件和块设备文件,分别对应于系统的字符设备和块设备。
![Page 52: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/52.jpg)
每一个设备文件的文件名由该设备的名称以及它的从设备号来描述。例如在系统中第一个 IDE 控制器上的主硬盘的设备名称号为 hda ,它上面的第一个分区的从设备号为 1 ,所以这个分区对应的文件名就是 /dev/hda1 。使用命令 ls -l /dev/hda* 就可以看到第一个硬盘可能包含的全部设备文件:brw-rw---- 1 root disk 3 , 0 May61998 hdabrw-rw---- 1 root disk 3 , 1 May61998 hda1brw-rw---- 1 root disk 3 , 10 May61998 hda10brw-rw---- 1 root disk 3 , 11 May61998 hda11brw-rw---- 1 root disk 3 , 12 May61998 hda12brw-rw---- 1 root disk 3 , 13 May61998 hda13brw-rw---- 1 root disk 3 , 14 May61998 hda14brw-rw---- 1 root disk 3 , 15 May61998 hda15
![Page 53: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/53.jpg)
brw-rw---- 1 root disk 3 , 16 May61998 hda16brw-rw---- 1 root disk 3 , 2 May61998 hda2brw-rw---- 1 root disk 3 , 3 May61998 hda3brw-rw---- 1 root disk 3 , 4 May61998 hda4brw-rw---- 1 root disk 3 , 5 May61998 hda5brw-rw---- 1 root disk 3 , 6 May61998 hda6brw-rw---- 1 root disk 3 , 7 May61998 hda7brw-rw---- 1 root disk 3 , 8 May61998 hda8brw-rw---- 1 root disk 3 , 9 May61998 hda9
其中第一个字符都是 b ,表明是块设备文件,接下来的 9位数字控制设备文件的访问权限,表示只有设备所有者 root 和所属 disk 组成员可以读写,所有设备的主设备号都是 3 ,从设备号依次为 0 到 16 ,最后给出的是设备文件名。
![Page 54: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/54.jpg)
2. /proc 子目录在 proc 子目录下存放的是关于当前运行系统的动态资料。这个目录及其所包含的文件属于一个称为 pr
oc 的逻辑文件系统,和其他文件系统不同的是, proc 文件系统是一个并不真正存在于块设备上的文件系统,这个目录下的文件也并没有存放在设备中。在系统的初始化过程中, proc 文件系统注册并建立该目录下所有的 i 节点,而只有当访问到其中的目录或文件时, Linux 虚拟文件系统才利用内核信息实时地建立这些文件和目录的内容。
![Page 55: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/55.jpg)
proc 目录为用户提供了几乎全部系统运行的动态资料, CPU 、内存、系统各种外部设备、中断等计算机硬件和设备控制信息,以及内存资源和外部设备的使用情况,系统中所有当前进程的工作情况等等。每一个当前存在于系统中的进程都在 proc 目录下有一个子目录,进程号是该目录的名称,如果用户希望了解 1号进程的当前情况,使用命令 ls -l /proc/1 ,就可以看到该进程的相关内容如下:
![Page 56: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/56.jpg)
total 0-r--r--r-- 1 root root0 Nov2 23:25 cmdlinelrwx------ 1 root root0 Nov2 23:25 cwd -> /-r-------- 1 root root0 Nov2 23:25 environlrwx------ 1 root root0 Nov2 23:25 exe -> /sbin/initdr-x------ 2 root root0 Nov2 23:25 fdpr--r--r-- 1 root root0 Nov2 23:25 maps-rw------- 1 root root0 Nov2 23:25 memlrwx------ 1 root root0 Nov2 23:25 root -> /-r--r--r-- 1 root root0 Nov2 23:25 stat-r--r--r-- 1 root root0 Nov2 23:25 statm-r--r--r-- 1 root root0 Nov2 23:25 status
![Page 57: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/57.jpg)
从上面的内容可以看到,这个进程对应的应用程序是/sbin/init ,建立这些文件和目录的时间就是运行 ls命令的当前时间,同时每一个文件的大小都是 0 ,即没有使用任何磁盘空间。可以通过这个目录下的stat 、 statm 和 status 文件进一步了解进程的执行状态,例如,我们可以使用命令 cat /proc/1/status来显示 init 进程的当前情况:Name: initState: S (sleeping)Pid: 1PPid: 0Uid: 0 0 0 0Gid: 0 0 0 0
![Page 58: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/58.jpg)
Groups: VmSize: 1120 kBVmLck: 0 kBVmRSS: 476 kBVmData: 36 kBVmStk: 8 kBVmExe: 24 kBVmLib: 1024 kBSigPnd: 0000000000000000SigBlk: 0000000000000000SigIgn: ffffffffd7f0d8fcSigCgt: 00000000280b2603CapInh: 00000000fffffeffCapPrm: 00000000ffffffffCapEff: 00000000fffffeff
![Page 59: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/59.jpg)
进程的名称、进程号以及所处状态等基本信息,用户号、用户组号等信息,以及内存空间,信号状态等各种更为详细的资料都一览无余。综上所述, proc 目录可以看作是一个观察系统内核内部工作情况的途径和窗口,通过这个目录下的内容,用户可以动态地了解计算机的软、硬件运行情况,可以用于实时监测,进行系统故障诊断。
![Page 60: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/60.jpg)
6.4 逻辑文件系统—— Ext2在整个 Linux 文件系统中,逻辑文件系统屏蔽了具体的设备细节,向虚拟文件系统提供服务,它真正存在于物理设备中。 Linux 系统可以支持几十种不同的文件系统,比如 DOS 系统的 MSDOS 文件系统、
Windows NT 的 NTFS 文件系统, MINIX 系统的MINIX 文件系统等等,它们都属于逻辑文件系统。Linux 本身默认的逻辑文件系统是 Ext2 。
6.4.1 Ext2 文件系统Ext2 文件系统是一种具有伸缩性,高效、可靠的逻辑文件系统。
![Page 61: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/61.jpg)
1. Ext2 文件系统的历史Linux 操作系统最初是从MINIX 操作系统发展起来的,它最早使用的文件系统是 MINIX 文件系统,但是 MINIX 文件系统本身功能不完备,性能欠佳。称为 VFS 的虚拟文件系统接口加入到系统的核心。
1992年,专为 Linux 设计的第一个文件系统 Ext( Extended File System )诞生了,碎片和效率是其中最为严重的两个弱点。1993年,推出了新的专门用于 Linux 系统的 Ext2 文件系统。 Ext2 完全具备了高级文件系统的特点,性能也相当好, Ext2 文件系统采用可变大小的物理块,具有良好的可扩展性,作为所有 Linux发行版本的默认文件系统。
![Page 62: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/62.jpg)
2. Ext2 文件系统的布局系统中的文件和目录等信息都存放在磁盘等块设备中,一个 Linux 系统可以支持多个物理磁盘设备,这主要取决于计算机硬件的支持能力,通常的 PC 中,最多可以支持到 4或 8 个 IDE 设备,每一个物理磁盘又可以定义多个分区,每个分区是存放逻辑文件系统的最小单位。在 Linux 系统中,这些分区可以安装不同的逻辑文件系统,系统可以同时使用这些文件系统,而且在用户的眼里,它们表现出基本相同的性能,互相之间可以进行数据传输,这就是 Li
nux 虚拟文件系统的优势。
![Page 63: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/63.jpg)
每一个逻辑文件系统都按照不同的规则,把自己所控制的磁盘分区定义为一组逻辑块的序列,通常包括引导块、超级块、 i 节点区和数据区。引导块在磁盘分区的头部,一般占用一个扇区,用来存放引导程序。在系统启动过程中,根据系统引导设置,该分区引导块的内容被读入内存执行,负责启动操作系统,启动完成之后,引导块不再使用,因此引导块在系统实际运行过程中并不属于文件系统管理。超级块用来记录整个逻辑文件系统的基本管理信息,不同的文件系统中定义为不同的数据结构,主要用来记录文件系统当前的状态,比如文件系统的大小、
i 节点和物理块的使用情况等等。
![Page 64: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/64.jpg)
i 节点区存放这个逻辑文件系统中所有的 i 节点,第一个 i 节点是这个系统的根节点,其他所有文件和目录都占用一个 i 节点。利用根节点,可以把存放在这个磁盘分区的整个文件系统安装到另一个文件系统的枝节点上,作为另外文件系统完整的一棵独立子树。数据区中存放文件系统中的各种物理块,可以存放直接块和各种间接块等文件内容,也可以用来存放各级间接块的地址等管理数据。Ext2 文件系统把它所占用的磁盘分区首先分为引导区和块组,每一个块组中都由超级块、记录所有块组信息的组描述符表、块位图、 i 节点位图、 i 节点区和数据区组成,见图 6.10 。
![Page 65: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/65.jpg)
图 6.10 磁盘分区中 Ext2 文件系统的布局
![Page 66: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/66.jpg)
每个块组中的超级块和组描述符都是相同的,前者记录整个文件系统的管理信息,后者记录每个块组的描述符。在系统启动的过程中,只有第一个块组中的超级块和组描述符被读取到内存空间中,其他块组中的数据作为冗余备份。此外,所有块组中的超级块和组描述符必须保持一致,当系统意外关机遭到部分破坏后,系统启动之后要进行文件系统一致性检查,首先要检查的就是这些数据,冗余数据虽然占用了一部分存储空间,但是提高了文件系统的可靠性。Ext2 系统采用位图来描述空闲物理块和 i 节点,分别称为块位图和 i 节点位图,记录本块组数据区中物理块和 i 节点区中 i 节点的使用情况。
![Page 67: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/67.jpg)
6.4.2 基本数据结构本节介绍 Ext2 文件系统主要数据结构。超级块和 i节点是其中最关键的两个结构, i 节点用来描述各种类型的文件,是整个文件系统的基本管理单元,超级块则是描述整个文件系统的重要数据,是这里要介绍的重点。另外,这里还介绍组描述符。它是描述文件系统块组分布和使用情况的主要数据。1. 超级块Ext2 文件系统的超级块用来描述目录和文件在物理设备上的静态分布情况,随着系统文件操作,超级块的内容也在不停地改变。对于 PC 机来讲,每一个磁盘分区都格式化为一个独立的文件系统,具有自己的超级块。
![Page 68: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/68.jpg)
超级块包含物理块和 i 节点的分配情况以及文件系统安装、检查情况等基本参数,描述整个文件系统的分布情况,同时也用于空闲 i 节点和物理块的分配和回收,是文件系统中最重要的数据,如果超级块的数据被破坏而且无法恢复的话,这个文件系统所管理的磁盘分区的数据就有可能全部丢失,因此超级块被同时记录在整个文件系统的每一个块组中,尽可能保证它的安全。系统根据超级块中的检查信息,确定整个文件系统的状态,如果发现错误或者是文件系统使用超过一定时间之后,都需要对整个文件系统进行检查,修正错误,整理磁盘碎片。
![Page 69: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/69.jpg)
根据所存放的位置,超级块也可以分为磁盘超级块和内存超级块,分别用结构 ext2-super-block 和 ext2-sb-info 来描述。其中磁盘超级块静态存放在外部存储器,而内存超级块是在文件系统启动时由外部超级块初始化形成,除了包含外部超级块所记录的信息之外,还增加了描述文件系统当前状态的动态信息和指向文件系统缓冲区的指针。内存超级块是系统内核其他部分进行文件操作的接口,内存超级块在文件操作发生之后通常会被修改,系统定期用内存超级块的数据更新磁盘超级块的内容。
![Page 70: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/70.jpg)
2. 组描述符块组是 Ext2 文件系统划分和管理文件系统的单位,每个块组都由一个组描述符( group descriptor )来具体描述,组描述符定义为 ext2-group-desc 数据结构,主要记录了该块组中空闲物理块和 i 节点的数目和描述它们的位图表的位置等信息,通过它可以管理整个块组内存储空间的分配和回收,它在块组中的地位就相当于超级块在整个文件系统中的地位。整个文件系统的所有块组的描述符集中在一起,形成组描述符表,这张表在每一个块组中都保存一个相同的副本,以便得到有效的保护。组描述符表位于该块组中超级块之后,可能占用多个数据块。
![Page 71: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/71.jpg)
6.4.3 存储空间管理文件系统的主要目标除了实现文件的有效管理和使用,同时还要保证存储器资源的有效利用。 Linux 系统默认的 Ext2 文件系统采用分块的组织方式,利用多重索引的物理文件结构来实现外部存储空间的管理。1. 块的大小Ext2 逻辑文件系统中,块的大小可以在一定范围内调整,但是在格式化磁盘分区生成文件系统时必须指定块的大小,因此每一个实际存在的 Ext2 文件系统的块的大小都是固定的,块的大小对文件系统性能和存储空间利用率有相当大的影响。
![Page 72: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/72.jpg)
如果块这个存储管理的基本单位选取比较大的话,存储空间的利用率就可能比较低。反过来,如果存储单元选取很小,文件系统的时间效率就很低。因此,时间效率和空间利用率是一对矛盾。一般, 文件系统块的大小可选值为 512 、 1K 、 2K或者是 4K 字节, Ext2 文件系统数据块大小的可选值是 1K~4K字节。通常块的大小根据文件系统中文件的平均长度来选取比较合适。前面我们学习过, Linux 使用的 Ext2系统中采用多重索引方式来组织文件,块大小选取的标准是:能够保证大部分文件都可以用 12 个直接块存放,这样,每次寻址只要访问 i 节点就可以得到物理块的地址,能够保证相当高的时间效率。
![Page 73: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/73.jpg)
2. 空闲空间管理系统对所有使用和未使用的存储空间,在 Ext2 文件系统中包括 i 节点和物理块,都需要做精确的记录,这是内存进一步分配和回收的依据。块的使用情况,具体记录在每一个文件的 i 节点中,而 i 节点的使用情况,记录在目录项中,这些都可以通过文件系统实现快速搜索和管理。文件系统记录空闲存储空间,包括记录空闲块和空闲
i 节点,广泛采用的两种基本方式是空闲链表和位图,同样的方法也可以用来管理空闲内存。
![Page 74: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/74.jpg)
我们以空闲块的管理为例简单说明这两种方法的基本原理。空闲链表把文件存储设备上的所有空闲块装入一个链表中,每一个空闲块中都记录着下一个空闲块的地址指针,通常以多个相邻空闲块组成的空闲区作为链表的节点单元,分配和释放空闲块也尽可能以空闲区为单位,可以按照空闲区大小顺序或者释放顺序来组织链表。当申请使用硬盘空间时,从链表头开始搜索并分配合适的空闲区,然后相应地调整链表指针,当回收空闲块时,把释放的存储空间按照空闲区为单位加入到链表中。
![Page 75: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/75.jpg)
位图方法是在存储区中划分一个单独的区域建立位图,位图中的每一个比特位数据都对应于存储区中的一个块,使用“ 0” 来表示空闲,使用“ 1” 来表示已经使用(或者相反)。这样,位图就可以反映整个存储区域中所有块的使用情况。分配和释放的过程中,只要通过查找位图中相应位的数据,就可以确定指定块的使用情况。空闲链表具有较好的空间效率,但是时间效率比较低。而位图方法需要占用固定的存储空间,但是具有很好的时间效率。
![Page 76: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/76.jpg)
Ext2 文件系统的空闲空间管理采用位图方式,在每个块组中都划分了特定的位图区来记录块和 i 节点的使用情况,分别称为块位图和 i 节点位图,参看图 6.10 。每一种位图分别占用一个块的空间,如果某一位的值为“ 0” ,表示相应的块或者 i 节点空闲,反之则表示已经分配。 Ext2 文件系统采用两个高速缓冲区来分别管理这两种位图,以提高时间效率。3. 分配策略当建立一个新的文件或者目录时,文件系统必须决定使用哪一个 i 节点来表示它,同时还要分配相应数目的块来存放数据。当一个文件在操作过程中,添加了新的内容,文件系统也必须确定给这个文件加入新的块来存放这些内容。
![Page 77: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/77.jpg)
i 节点和块的分配策略在一定程度上决定着文件系统的整体效率。 Ext2 文件系统采用块组的概念,尽可能把同一个文件所使用的块、同一个目录所使用的 i 节点存放在相邻的单元中,至少是在同一个块组内,减少磁盘访问过程中的寻道时间,以提高访问效率。具体对于一个新分配的 i 节点,新目录尽可能保证它和父目录分配在同一个组当中,新文件也要尽可能保证和目录同组,同时,尽可能保证所有的节点平均分配到所有的块组中。
![Page 78: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/78.jpg)
Ext2 文件系统采用称为预分配的机制来保证文件内容扩展时块的分配效率和效果,在文件建立的时候,如果有足够的空闲块,就在相邻的位置为文件分配多于当前使用的块,称为预分配块,当文件内容扩展时,优先使用这些块,可以提高分配效率也可以保证这些块具有连续关系。如果预分配的块用完或者是根本没有启动预分配机制,分配新块时也要尽可能保证与原有块相邻。在申请分配 i 节点和空闲块的过程中,都需要改写文件系统的超级块,在分配过程中,必须要申请使用超级块并加锁,超级块分配采用的是先来先服务算法,后面申请的进程必须等待,直到所有前面申请的进程都使用完解锁并释放才可以得到超级块的使用权。
![Page 79: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/79.jpg)
6.5 虚拟文件系统—— VFSLinux 虚拟文件系统位于 Linux整个文件系统的最上层,提供文件系统对用户命令、系统调用及内核其他模块的统一接口,它负责管理并控制下层的逻辑文件系统,使它们按照各自特定的模式正常运转,同时能够对用户提供尽可能相同的表现形式。虚拟文件系统只存在于内存中,并没有真正存在于磁盘分区中,磁盘分区存放的是逻辑文件系统的内容,所有虚拟文件系统的数据结构都是在系统启动之后才建立完成,并在系统关闭时撤销。同时,它必须和其他实际存在于磁盘的文件系统,比如 Linux 默认的 Ext2或者Windows NT 的 NTFS 等逻辑文件系统一起,才能构成一个完整的文件系统。
![Page 80: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/80.jpg)
虚拟文件系统对逻辑文件系统进行抽象,采用统一的数据结构在内存中描述所有这些文件系统,接受用户层的系统调用和核心层其他模块的访问,通过 VFS 操作函数,按照一定的映射关系,把这些访问重新定向到逻辑文件系统中相应的函数调用,然后由逻辑文件系统来完成真正的具体操作,这样, VFS 只负责处理设备无关的操作,主要是进行具体操作的映射关系。正是 VFS 的这种抽象的功能层次,保证了 Linux 系统可以支持多种不同的逻辑文件系统,所有文件系统都具有基本相同的外部表现,而且可以方便地进行相互访问。
![Page 81: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/81.jpg)
针对下层的逻辑文件系统, Linux 系统中的 VFS 为它们提供一致接口,统一管理各种逻辑文件系统,包括进行文件系统的注册和注销、安装和卸载等,提供限额机制,负责对用户使用存储空间的数量进行有效控制。把文件操作进行适当的转换,转交由具体逻辑文件系统进行处理,然后把具体的操作结果提供给上层的调用者。针对上层, VFS对用户函数调用和内核其他模块的访问提供接口,接受访问并返回由具体逻辑文件系统完成的结果。此外,VFS 还负责管理文件系统的各种缓冲区,保证文件系统的整体效率。
![Page 82: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/82.jpg)
6.5.1 基本数据结构VFS 采用超级块和 i 节点来描述文件系统,这些基本的数据结构在文件系统初始化的过程中,由具体逻辑文件系统的超级块和 i 节点的数据来填充,而当文件系统关闭时, VFS 的超级块和 i 节点也就消失了。1. VFS 超级块初始化完成之后,对于每一个可以访问的逻辑文件系统,都对应于一个 VFS超级块,这些数据驻留在系统内存。 VFS 文件系统的超级块用来描述初始化它的具体逻辑文件系统的目录和文件在物理设备上的静态分布情况,随着逻辑系统文件的改变, V
FS超级块的内容也在变化。
![Page 83: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/83.jpg)
VFS超级块使用数据结构 super-block 来描述。在 VFS超级块中,记录具体逻辑文件系统所在的设备号、类型、第一个 i 节点号等基本信息,包含了对该文件系统文件操作和存储空间限额管理函数的入口指针和所对应的具体逻辑文件系统的内存超级块。虚拟文件系统就是通过 VFS超级块中记录的内存超级块来访问并管理具体的逻辑文件系统的,文件操作通过 VFS 中记录的函数入口指针映射得到对应的函数。图 6.11 以 Ext2 文件系统为例描述了逻辑文件系统磁盘、内存超级块和 VFS超级块之间的关系。
![Page 84: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/84.jpg)
图 6.11 Ext2磁盘超级块、内存超级块和 VFS超级块关系示意图
![Page 85: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/85.jpg)
整个 Linux 文件系统形成一个完整的目录树,每一个逻辑文件系统都可以作为一个独立的子树安装到目录树的某个枝节点上。因此, VFS超级块中采用指针 s-covered记录着该文件系统在另外一个文件系统中安装点的信息,同时 VFS超级块中还使用指针 s-mounted记录指向该逻辑文件系统的第一个节点的位置。对于根文件系统, s-mounted 就是根目录的 i 节点,它没有安装到其他文件系统, s-covered指针无效。对于安装在根文件系统下的文件系统,访问该文件系统管理的文件首先要通过根文件系统,根文件系统中的安装点指针 s-covered 就是该文件系统的访问入口,指向该文件系统的根节点。
![Page 86: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/86.jpg)
2. VFS i 节点VFS i 节点用来描述虚拟文件系统中的文件和目录,同样的,每一个文件、目录或者设备都对应于一个且只能对应于一个 i 节点。 VFS i 节点只存在于内存中,是所有逻辑文件系统 i 节点的抽象描述,和具体逻辑文件系统的 i 节点一一对应,并根据该文件系统的 i 节点信息建立。
![Page 87: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/87.jpg)
VFS i 节点包含具体 i 节点所在设备的设备号和磁盘 i节点号、文件说明信息、文件在内存中的分布和使用信息、锁定和修改标志、一组 VFS i 节点操作函数指针和一个具体逻辑文件系统内存 i 节点。设备号和磁盘 i 节点号在整个文件系统中惟一确定一个VFS i 节点。在内存中,总是同时存在多个 VFS i节点,每一个已经使用的 VFS i 节点表示某设备上一个具体存在的文件或者目录的 i 节点,所有 VFS i 节点组织成一个双向链表,存放在系统内核空间中,链表的头节点之前存放空闲节点,而链表头之后依次是分配出去的 VFS i 节点。
![Page 88: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/88.jpg)
在用户或者内核看来,对目录和文件的操作是对 VFS i 节点进行的。实际上, VFS i 节点根据逻辑文件系统的类型,利用存放在其中的节点操作函数指针,对操作函数进行相应的映射,得到具体逻辑文件系统 i 节点操作函数,对具体的 i 节点进行操作,把结果返回给使用者。
![Page 89: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/89.jpg)
6.5.2 文件系统管理Linux 系统利用虚拟文件系统 VFS 实现对多种文件系统的有效支持,虚拟文件系统负责管理具体的逻辑文件系统,同时也可提供用户存储空间限额管理。1. 逻辑文件系统管理某种类型的逻辑文件系统要得到 Linux 操作系统的支持,首先必须向核心注册。可以采用两种方式,一种是在内核编译过程中确定要支持的文件系统类型,并在系统初始化过程中使用特定的函数调用注册,另外一种方式是在系统启动完成之后,把某种逻辑文件系统类型作为一个内核模块加入到内核中,加入模块时完成注册。
![Page 90: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/90.jpg)
每一个注册过的文件系统类型都初始化一个称为 file-system-type 的数据结构,所有这些数据结构组成一个单向链表,称为文件系统类型注册表。对于某一种文件系统类型,可以管理多个磁盘分区,也就是说有多个该类型的文件系统,但是它只占用类型注册表中的一个节点。当某一种类型的文件系统都不再使用时,可以使用卸载模块的方式来注销该文件系统类型。对于一个具体的文件系统,在微机中就是每一个磁盘分区,要使用该文件系统所管理的文件,必须向内核注册和安装该文件系统,而当卸载一个文件系统时,还需要向内核申请注销该文件系统。
![Page 91: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/91.jpg)
系统中所有注册的文件系统组成一个文件系统注册表,也采用一个单向链表来描述,节点类型为 vfsmount ,记录着对应文件系统的设备号、安装目录名称、超级块以及存储空间限额管理数据,文件注册表实际上可以描述整个目录树在文件系统层次上的构成情况(不能反映每一个文件系统中具体的目录分布)。图 6.12 示意性地描述了文件系统类型注册表、文件系统注册表和 VFS超级块之间的关系。
![Page 92: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/92.jpg)
图 6.12 文件系统注册表、 VFS超级块和文件类型注册表关系示意图
![Page 93: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/93.jpg)
文件系统类型注册表记录着整个系统当前所支持的全部文件系统类型,而文件系统注册表记录着整个系统中当前可以使用的全部文件系统,是操作系统访问具体存储设备上文件系统的入口。看这样一个例子,一台微机只使用一块硬盘,同时安装了 Linux 和 Windows 2000两个操作系统,分别使用不同的分区,不同的文件系统。假定 Linux 系统安装在第一个基本分区中,设备名称为 /dev/hda
1 ,采用默认的 Ext2 文件系统, Windows 2000安装在第二个基本分区中,设备名称为 /dev/hda2 ,采用 NTFS 文件系统,基本分区 /dev/hda3 中是 Linux 系统的交换区,磁盘的逻辑分区 /dev/had5 是Linux 系统的用户数据区,文件系统类型也是 Ext2 。
![Page 94: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/94.jpg)
这种情况下,系统中同时存在 Ext2 、 NTFS 和 Swap等三种类型的逻辑文件系统,要想同时支持这些不同类型的文件系统,必须首先注册这三种文件系统类型,在文件系统类型注册表中加入相应的节点,经过这一步, Linux 系统的核心才能够支持相应的文件系统类型。在这个例子中,如果要使用所有的磁盘分区,还必须把 hda1 、 hda2 、 hda3 和 hda5所对应的具体文件系统都加入到文件系统注册表中。在 Linux 系统启动的过程中,根据记录在 /etc 目录下的 fstab 文件确定并安装文件系统,形成初始目录树。在启动完成之后,具有足够权限的用户,一般是超级用户,可以通过 mount 命令来安装特定的文件系统。
![Page 95: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/95.jpg)
在安装过程中,需要明确指出所安装文件系统的类型、文件系统所在的设备号以及在已有文件系统中的安装点。安装过程中,首先在文件系统类型注册表中查找所指定的文件系统类型是否已经注册,如果没有注册,试图通过内核申请注册该文件系统,注册不成功则错误返回。一旦确定在文件系统类型注册表中有该文件系统,接着开始检查文件系统注册表,确定指定的文件系统是否已经安装,同样一个文件系统是不能多次安装的。确定该文件系统没有安装之后,检查安装点的合法性,每一个安装点也只能安装一个文件系统。
![Page 96: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/96.jpg)
经过这三步检查之后, VFS 分配新的超级块,利用文件系统类型注册表中对应的超级块读入函数,读取指定设备上文件系统的磁盘超级块并初始化这个VFS超级块,填写相应的 s-covered 和 s-mounted信息。然后形成一个类型为 vfsmount 的节点,填写内容并挂到文件系统注册表链表中。
![Page 97: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/97.jpg)
文件系统的安装过程,从用户的角度来看,就是把这个文件系统所记录的独立子树安装到已经存在的目录树某个枝节点上的过程。安装点指明枝节点的位置,它所对应的 VFS i 节点记录在 VFS超级块的指针 s-covered 中,文件系统所在的设备号指出了独立子树的位置,这个文件系统中第 1 节点的位置所对应的 VFS i 节点号记录在 VFS超级块指针 s-mounted 中。安装完成以后,所有对所安装逻辑文件系统的访问都是从文件系统注册表开始,通过 VFS超级块得到具体文件系统的类型和位置(由 VFS i节点号表示)以及操作函数映射到相应的逻辑文件系统,实现具体的文件操作。
![Page 98: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/98.jpg)
通常 Linux 系统关机时会检测并卸载和注销所有已经安装的文件系统。一般运行过程中,只有在文件系统中的任何一个文件或者目录都没有被使用的情况下,超级用户可以使用系统命令 umount 来卸载并注销一个文件系统。 VFS首先处理该文件系统对应的 VFS超级块,如果需要,把它重新写入磁盘超级块中,然后释放该超级块,卸载完成,该文件系统对应的独立目录子树就从整个目录树中摘下来,最后释放文件系统注册表中相应的 vfsmount 节点,注销文件系统。
![Page 99: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/99.jpg)
2. 存储空间限额管理存储空间限额管理是多用户操作系统中所必须考虑的问题,利用这个技术,可以有效控制系统中每一个用户最多可以使用的存储空间,保证所有用户都有可用的空间资源。限额管理可以分为软限额和硬限额两种。硬限额指定的存储空间范围绝对不可以超过,而软限额在用户使用资源超过限额范围之后,系统开始启动定时机制,如果在规定的限制时间之内没有采取措施缩减使用空间的话,软限额变成硬限额,强迫用户进程终止,释放所占用的资源。软限额到硬限额之间的时间可以由系统管理员来设置,系统默认值为一周。
![Page 100: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/100.jpg)
限额分配情况是由限额文件来控制的,文件中以用户号为索引记录每个用户的空间限额配置资料,每一条记录称为一个限额块。每一个文件系统都有限额文件,存放在该文件系统的根目录下,在注册文件系统时,指向该文件的指针保存在文件系统注册表中。 VFS超级块中保存着一个指向相应的限额处理函数的指针,每一个用户的限额块分别使用指针记录在该用户使用的每一个 VFS i 节点中。当用户申请新的块或者 i 节点时,系统按照文件拥有者的用户标识号查找相应的限额记录,如果限额没有满,则接受申请,分配空间并加入到使用计数中,如果达到限额,调用相应的限额处理函数来处理,给出警告信息或者是进行硬限额处理。
![Page 101: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/101.jpg)
6.5.3 VFS 和进程的接口前面介绍的是 VFS针对下层逻辑文件系统的管理功能,作为一个独立的层次,它同时还向用户函数调用和内核其他部分提供服务,它对用户的服务,必须通过内核中的进程实体完成。这里,主要学习 V
FS 文件系统和进程的各种接口。逻辑文件系统是程序和数据的静态组织,而进程反映这些程序和数据的动态过程,文件只有通过进程才能得到执行和访问, VFS 的这些接口提供了它们之间联系的桥梁。
![Page 102: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/102.jpg)
进程和文件系统的接口可以用图 6.13 示意性描述。进程中包括两个关于文件方面的数据,一个记录文件系统信息,另外一个描述进程打开文件的信息。前者是一个指向 fs-struct 结构的指针,主要数据是文件系统根目录和当前目录所对应的 i 节点号。后者是一个指向 file-struct 结构的指针,包含用户打开文件表,是该进程对全部已打开文件进行具体访问的接口。
![Page 103: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/103.jpg)
图 6.13 进程和用户打开文件表、系统打开文件表等数据结构的关系
![Page 104: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/104.jpg)
1. 用户打开文件表和系统打开文件表所有用户对文件的操作,不管是命令方式还是系统调用,最终都是通过特定的进程来实现。在 Linux标识进程的 PCB 中,包含了用户打开文件表,用来建立该进程和所有该进程打开文件之间的联系,同时,系统中所有打开的文件也记录在一张称为系统打开文件表的双向链表中。
![Page 105: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/105.jpg)
用户打开文件表记录是一个数组,记录在 file-struct结构中,每一个进程中含有一个指向该表的指针,其中使用一个数组来存放所有该进程已经同时打开的文件,默认的数组大小为 256 ,数组每一个元素fd\[i\]指向对应于一个 file 结构类型的指针,指向一个特定的文件,数组元素的下标称为文件描述符,供用户操作文件时使用,每次成功打开一个文件,返回的结果就是这个描述符。每一个进程在建立的时候,用户打开文件表中都有默认的三个打开文件,其描述符分别为 0 、 1 和 2 ,分别对应于系统标准输入设备、系统标准输出设备和系统标准错误输出设备。每当用户进程打开一个新文件,系统就在 fd数组中选定其中第一个空闲的元素来指向对应的 file 结构,代表特定的文件。
![Page 106: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/106.jpg)
系统打开文件表描述系统已经打开的文件,具体指明打开同一文件的不同进程、不同进程所对应的打开路径以及不同进程和不同打开路径所对应的读写位置指针。每一个打开文件使用一个 file 结构描述,包括文件打开方式、读写位置指针、文件访问计数、文件 VFS i 节点指针和文件操作指针等关于文件的具体数据以及前后向指针。
![Page 107: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/107.jpg)
进程通过控制块 PCB 得到文件系统信息和对应的用户打开文件表,该表的每一个表项指向一个已经打开的文件,这些打开文件统一由系统打开文件表来管理,打开文件中记录该文件当前打开方式、读写指针等基本信息和文件对应的 i 节点信息以及操作函数,有了这些信息,进程就可以进行具体的文件操作。
![Page 108: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/108.jpg)
2. 共享文件访问多个用户使用同一个文件称为文件共享,前面介绍的是文件系统中用户级别的文件共享方法和权限控制等问题,这只是问题的静态方面。具体共享文件的访问是通过不同的用户进程来具体操作的,这些进程可以属于不同的用户,也可以是同一个用户的不同进程,而且完全有可能两个进程同时对某一个文件进行操作,这里介绍具体的实现方法。
![Page 109: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/109.jpg)
Linux 进程可以通过两种途径来实现文件共享。一种是多个进程同时共享使用一个系统打开文件表的节点(即 file 结构),该节点惟一对应于一个打开的文件,这种情况只在父子进程之间发生,一个新建立的子进程,复制父进程 PCB 中关于文件信息的全部内容,因此两者拥有完全相同的用户打开文件表,使用位于系统打开文件表中相同的节点。另外一种途径是多个进程使用多个系统打开文件表的节点,它们指向相同的 i 节点,这个 i 节点惟一确定一个文件,属于不同或者相同用户的进程同时访问一个文件就使用这种途径,不同进程打开同一个文件可以使用相同的路径名,也可以通过链接方式使用不同的路径名。
![Page 110: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/110.jpg)
这里值得注意的是文件读写位置指针的情况,使用 file 结构共享文件的父子进程使用相同的文件读写位置指针,因此不管是父进程还是子进程在进行文件操作时都会改变指针的值。而指向相同 i 节点的共享方式,每一个进程都要进行文件打开操作,各自维护自己的 file 结构,分别使用不同的文件读写位置指针指向自己操作的当前位置。
![Page 111: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/111.jpg)
6.5.4 缓冲区管理在计算机系统中,内存的访问速度很快,因此,必须采用缓冲技术来提高外存数据的访问效率。缓冲技术的基本原理是在内存中划分称为缓冲区的特定区域,每次从外部设备读取的数据都暂时存放在这里,下次读取数据时,首先搜索缓冲区,如果有需要的数据,则直接从这里读取,如果缓冲区中没有,再启动外部设备读取相应的数据。对于写入磁盘的数据,也先放入到缓冲区中,按照一定的时间间隔或者数据量的大小,分批写出到磁盘中。这样,使用缓冲技术使得大多数数据传输都是直接在内存进程空间和缓冲区之间进行,减少外部设备的访问次数,提高系统的整体性能。
![Page 112: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/112.jpg)
VFS 文件系统相关的缓冲主要有 i 节点缓冲、目录缓冲和块高速缓冲,分别用于 i 节点访问、根据文件目录名查找目录的 i 节点以及块设备的数据读写过程中的缓冲。这里主要以 Linux 2.2.16 中块高速缓冲为例介绍缓冲管理的一般原理及其对系统性能的影响。1. 块高速缓冲区结构块高速缓冲( buffer cache )是文件系统和设备进行数据传输的桥梁,它同时涉及到不同的物理设备和逻辑文件系统,是各种设备驱动程序数据传输的接口,因此是一个相对复杂的数据结构。
![Page 113: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/113.jpg)
每一个可以使用的缓冲区由两个部分组成,用于存放数据的缓冲数据区 buffer 和用于控制的缓冲头部 buffer-head 。为了支持各种不同类型的逻辑文件系统, Linux 系统缓冲数据区的大小不是固定的,按照不同的长度分为 7 种类型。在同一时刻,缓冲区中可能包含不同物理设备的数据块,为了适应不同逻辑文件系统的各种不同大小的数据块,系统中同时采用多种不同大小的缓冲区。缓冲区头部大致包括三类信息:所在设备号、物理块号等描述缓冲区对应数据块内容的信息;描述缓冲区状态和访问计数的信息以及用于缓冲区管理的信息。对于缓冲区的分配、搜索、使用和释放等操作都是通过缓冲头部进行。
![Page 114: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/114.jpg)
缓冲区状态是缓冲区最主要的信息之一。缓冲区状态可以是下面几种情况的组合:缓冲区是否包含有效数据,是否包含需要写出的数据,是否上锁,是否保护等等。在 Linux 的块高速缓冲中,缓冲数据区和缓冲头部并不是完全一一对应的,整个块高速缓冲区中有四类以缓冲头部为节点的链表,其中两类不包含数据区,并不能进行实际的数据缓冲,主要涉及缓冲头部的管理,包括未使用链表 unused-list 和重用链表 reus
e-list ,都采用单向链表存放;另外两类是真正的缓冲区,每一个链表的节点都是由一一对应的缓冲头部和缓冲数据区组成,分别是空闲链表 free-list和正在使用链表 lru-list ,都使用双向链表来保存。
![Page 115: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/115.jpg)
空闲链表 free-list 中保存由内存页面初次创建的缓冲区和从正在使用链表中回收的空闲缓冲区。系统中一共有 7 个这样的链表,分别对应于不同长度的缓冲区类型,它们共同组成一个链表数组。正在使用链表 lru-list 存放当前正在使用的缓冲区,这是一个由 3条链表组成的数组,分别连接不同类型的缓冲区:BUF-CLEAN ,数据已经写出、干净的缓冲区;BUF-LOCKED ,正在进行写出操作的缓冲区;BUF-DIRTY ,“脏”缓冲区。写入新数据,等待写出的缓冲区。
![Page 116: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/116.jpg)
为了提高查找效率, Linux 同时还使用一个散列表( hash table )来组织所有的正在使用链表,如图6.14 。表的节点类型是缓冲头部 buffer-head 类型,散列索引值通过缓冲区所对应物理块所在设备号及其块号来产生,具有相同索引数值的正在使用链表的节点组成新的双向链表。
![Page 117: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/117.jpg)
图 6.14 散列表和缓冲区链表的关系
![Page 118: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/118.jpg)
2. 块高速缓冲区的分配和释放当文件系统对某个数据块进行操作时,一定要通过块高速缓冲区来进行,必须分配相应的缓冲区,完成这个工作的函数是 getblk 。首先根据块对应的设备号和块号在散列表中搜索正在使用的链表中是否包含这个数据块,如果包含,就得到了需要的缓冲区,可以进行数据操作,否则,就需要重新分配一个空闲缓冲区。分配空闲缓冲区时,根据所操作数据块的大小在相应的空闲缓冲区链表中查找,如果找到一个合适的空闲缓冲区,从空闲链表中摘下来该缓冲区,并初始化该缓冲区的控制数据,然后挂到相应的散列表和干净缓冲区链表中,得到可以使用的缓冲区。
![Page 119: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/119.jpg)
如果空闲缓冲区中没有合适的缓冲区,系统就通过两种途径来补充空闲缓冲区的数量,一是申请空闲的内存页面,建立所需长度的新缓冲区并挂到相应的空闲链表中,二是唤醒进程 bdflush 把“脏”缓冲区写出到设备以得到空闲缓冲区,在完成这些操作的过程中,可能已经有别的进程曾经对这里需要访问的数据块进行过访问并在正在使用链表中建立了节点,因此再进行一次散列表的搜索,如果还是没有找到的话,就从空闲缓冲区中获取。内存空闲页面和缓冲区之间的转换关系参看图 6.15 。
![Page 120: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/120.jpg)
图 6.15 内存空闲页面和缓冲区之间的转换关系示意图
![Page 121: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/121.jpg)
缓冲区的释放由函数 tr-to-free-buffers完成。这个函数检查属于同一个物理页面的所有缓冲区,如果这些缓冲区都不忙(没有锁定、没有保护、干净),则可以释放这个页面对应的数据区,缓冲区头部则回收到未使用链表中。否则唤醒函数 dbflush ,试图把脏缓冲区写出到硬盘设备,然后再次判断是否可以释放。3. 块高速缓冲区数据维护Linux 需要采取适当的方式来维护块高速缓冲区,一方面保证不同块设备、不同的用户进程都能够公平地分配到缓冲区,同时还要尽快把数据写出到设备中,保证进程和设备数据的同步并适当减少缓冲区的内存使用量,以便能够使整个系统高效运行。
![Page 122: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/122.jpg)
维护块高速缓冲区,把其中需要写出的“脏”缓冲区写到具体设备中是由两个内核线程 bdflush 和 update 来完成,它们直接使用系统空间,运行于内核态,具有较高的优先权。
内核线程 bdflush 的进程号为 2 ,进程名称为 kflushd 。在以下几种情况下被唤醒:文件系统申请新缓冲区时,空闲缓冲区链表中为空,而且申请空闲内存页面建立新缓冲区没有成功,说明系统内存不足,需要减缩正在使用的缓冲区数量;系统正在使用缓冲区链表中的“脏”缓冲区超过一定的数目或者“脏”缓冲区数量已经占到块高速缓冲区总数的一定百分比以上,表明系统缓冲区中积累了大量需要写出的数据。 bdflush 负责将一定数量的“脏”缓冲区写出到具体设备,同时试图释放缓冲区所占的内存页面。
![Page 123: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/123.jpg)
内核线程 update 的进程号为 2 ,进程名称为 kupdate 。它周期性地被唤醒,按照“脏”缓冲区存在时间长短,把老的“脏”缓冲区写出到设备中,然后试图释放内存页面,它与 bdflush 的差别在于唤醒方式、确定要写出的缓冲区的标准不同,且它在写完之后,要改写缓冲区头部记录的时间标记,记录当前写出时间。
块高速缓冲区中的数据同时联系着设备以及用户进程,在使用过程中,用户进程对块设备的数据访问都通过缓冲区进行。采用的是异步写的方式。这样可以大大提高运行效率,但如果在数据进入缓冲区但是还没有写入设备之前系统崩溃,这些数据就丢失,造成文件系统数据错误,这也就是为什么 Linux 等操作系统不能直接关机的主要原因。
![Page 124: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/124.jpg)
6.6 小结本章介绍了 Linux 的文件系统。文件系统是用户接触、使用操作系统过程中面对的部分,它负责管理静态的文件。文件是计算机存储信息的基本单位, Linux 系统采用无格式的流文件,使用多重索引的方式以块为单位进行存储,利用目录组织成一个完整的目录树。 Li
nux 系统默认的逻辑文件系统是 Ext2 ,其基本的数据结构是记录文件系统信息的超级块和表示文件和目录的 i 节点,使用块组技术,对文件系统中重要的数据(超级块和块组描述符)进行冗余备份,保证文件系统具有相当高的可靠性。
![Page 125: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/125.jpg)
Linux 系统支持多种不同格式的文件系统,通过虚拟文件系统屏蔽了各种具体文件系统的差异,为用户命令、系统调用以及内核其他模块提供统一的操作接口,并负责把文件系统的操作映射到具体的逻辑文件系统和设备。 Linux 系统使用了块高速缓冲、目录缓冲以及 i 节点缓冲等多种缓冲技术,使得整个文件系统具有相当高的效率。Linux 系统提供了链接等实现文件和目录共享的手段,支持多个用户共同访问一个文件。也带来了相当大的安全性问题,具体包括保护和保密两种情况,这实际是一个文件的访问权限控制问题, Linux 系统通过用户验证和简化的存取控制表来实现一定程度的共享安全性。
![Page 126: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/126.jpg)
习题6-1 什么是文件、文件系统?文件系统提供哪些功能?6-2 什么是文件的逻辑结构和物理结构? Linux 文件系统分别采用什么样的结构?有什么优点和缺点 ?6-3 Linux 文件可以根据什么分类?可以分为哪些类?6-4 Linux 采用什么样的目录结构?这种目录结构有什么优点?有什么缺点?6-5 Linux 文件共享可以用哪些方法来实现?它们各有什么特点?6-6 Linux 文件访问权限的控制采用什么方法?如何看待用户口令?你认为可以采用什么样的策略来保护口令本身?
![Page 127: 第 6 章 文件系统](https://reader035.vdocuments.pub/reader035/viewer/2022081520/56814c4c550346895db955e9/html5/thumbnails/127.jpg)
6-7 通过文件系统如何了解 Linux 当前各进程的运行情况、内存占用情况?6-8 在 Linux 系统中, Ext2磁盘 i 节点和内存 i 节点有什么不同? VFS 有磁盘 i 节点和内存 i 节点的区别吗 ? 为什么?这些 i 节点之间有什么关系?6-9 在网上获取新的 Linux 核心,了解 VFS超级块和 i 节点数据结构的变化情况。6-10 Linux 中和文件系统相关的缓冲区有哪些种 ? 分别有什么作用?6-11 bdflush 进程有什么作用?什么情况下被唤醒?和它一样属于内核线程的还有哪些进程?