UNIX文件系统

第8章  文件系统

文件系统经常是操作系统中最大的一部分,尽管并不包含最复杂的算法和数据结构。文件是一种操作系统机制,用于从一个会话(session)保存信息到另一个会话(session)中。文件也被用做永久性存档信息的容器,比如运行一个进程所需要的信息就存放在可执行文件中;而财务人员把账目信息存放到账务文件中(比如Windows下的Excel文件),从而可以在任何时候打开它处理。程序员依赖文件系统来简化对保存数据集合的存储设备的使用,比如磁盘。

8.1 概述

文件是最有意义的操作系统抽象之一(构建在设备抽象之上)。从计算的早期年代以来,程序员就使用文件在存储设备上保存信息。在20世纪80年代后期,MS-DOS提供的抽象也主要是文件抽象。文件至今仍然是计算的支撑:它们用来将大量的信息(如一段视频从一个应用传送到另一个应用(见图8-1)。逻辑上,视频数据使用摄像程序创建,媒体播放器可以对它们进行播放。实际上,在摄像时,视频数据被写入到文件中,文件然后被写到存储设备中。文件消费者(这里是媒体播放器)从存储设备中得到文件,然后将它的内容读入进程地址空间。文件系统的管理者——文件管理器建立起抽象的环境,应用不必关注设备存储的细节。当一个应用想要得到信息时,它仅仅调用系统接口打开文件,读取信息,最后关闭它。


图8-1  传输视频信息

图8-1解释了文件抽象和它的实现。在这个抽象中,信息是作为结构化的数据(按照一定的视频编码格式)存储在文件中的。文件管理器把信息转换成连续的字节流,然后存储到面向块的存储设备中(比如磁盘)。当某个应用需要使用信息时,它从文件管理器中得到字节流,然后对该字节流进行解码。

在1960年之前,使用计算机的动机通常是执行高速计算。大多数应用是计算密集型过程,用来预测导弹的轨道、解系统方程或执行其他的科学计算。直到1960年,发生了巨大的变化。人们开始意识到计算机实际上是十分强大的信息存储和操作工具。从此,计算机不仅仅用来执行高速计算,也用来存储大量的信息、处理信息和产生新形式的信息,并对它进行保存。

在现代计算机系统中,文件是信息管理的技术基础(尽管数据库正在逐渐取代文件,但很多时候它依然是建立在文件的基础上的)。从程序员角度看,文件是辅存设备的基本抽象(如磁盘或磁带)。每个文件都是存储在设备上的具有名称标识(文件名)的数据集合。程序员通过系统提供的接口(open、close、read、write等)来访问文件。

文件系统就是由文件和目录组成的集合及相应访问机制的实现。本章主要讲述UNIX文件系统的实现。

8.2 框架

8.2.1 文件存储的实现

UNIX中文件的含义非常广泛,不仅仅包括保存在各类存储设备上的数据,还包括shell终端、打印机等外部设备资源(后来甚至包括了socket等资源,用来建立网络连接,从而传输数据)。对于存储设备,可分为顺序访问设备和随机访问设备。顺序访问设备是指只能按次序对数据进行访问的设备。比如要想访问设备上的第1000个字节,那就必须先访问前999个    字节。

磁带是典型的顺序访问设备(尽管有些也可支持随机访问)。录音机所用的磁带和计算机所用的存储磁带原理上是相同的。以前使用walkman听磁带时,笔者经常使用快进跳过那些不喜欢听的歌,而直接播放自己喜欢的。但这样做有几个缺点:

1.快进的速度依然不够“快”,通常还得等上几秒;

2.快进经常导致定位不准,可能过了,只好再使用快退调整。有时候需要反复调整几次才能准确定位;

3.长时间的快进/快退会损坏磁带上的数据,从而影响音质;

4.磁带上的数据一旦写入后,就不好修改。即使可以修改,新写入的数据也不能超过原来文件的大小。

为了解决顺序访问设备的这些问题,诞生了随机访问设备。所谓随机访问设备是指对其中任何一处数据可以进行随意访问而无须先访问前面的数据,且访问时间都差别不大的设备。硬盘是典型的随机访问设备,访问硬盘上任何一处的数据,其消耗的时间都相差无几。



图8-2  磁盘结构


硬盘采用磁介质存储数据,数据存储在密封于洁净的硬盘驱动器内腔的若干个磁盘片上。这些盘片一般是在以铝为主要成分的片基表面涂上磁性介质而形成,一个磁盘片通常有两面,在磁盘片的每一面上,以转动轴为轴心、以一定的磁密度为间隔的若干个同心圆就被划分成磁道(track),每个磁道又被划分为若干个扇区(sector),数据就按扇区存放在硬盘上,磁盘结构如图8-2所示。

在每一面上都相应地有一个读写磁头(head),不同磁头的所有相同位置的磁道就构成了所谓的柱面(cylinder)。传统的硬盘读写都是以柱面、磁头、扇区为寻址方式的(CHS寻址)。硬盘在上电后保持高速旋转,位于磁头臂上的磁头悬浮在磁盘表面,可以通过步进电机在不同柱面之间移动,对不同的柱面进行读写。

磁盘在进行读写时,大部分时间都花在磁头的寻址操作上。磁头寻址分为磁头定位、柱面定位和磁道定位三个过程。硬盘驱动器首先根据读写地址,判定它位于哪个盘片上;然后启动该盘片的磁头,通过步进电机把它移动到读写地址所在的柱面(必要的话);然后再通过磁片的旋转,定位到磁道上相应的扇区。书中UNIX使用的硬盘是DEC公司的RK05/11系列硬盘。它的转速是1500转/分钟,数据传输率是1.44兆/秒,最大寻址时间是85毫秒。也就是说,最多经过85毫秒,磁盘驱动器就可以把磁头定位到读写地址相应位置处,开始进行读写。这个过程是非常短的,相对于磁带的寻址时间我们几乎可以忽略。

现代硬盘最高转速可达15000转/分钟,最大寻址时间在2毫秒左右,比RK系列磁盘提高了40倍。所以磁盘是名副其实的“随机访问设备”。

磁盘是按扇区管理的(UNIX称扇区为“块”,在本书中,它们是同一个意思),每个块大小相等,磁盘驱动器以它为单位进行读写。也就是说,即使往磁盘写入一个字节,那么也要重写该字节所在的整个块,对于读操作也是一样。RK系列磁盘的块大小为512字节。而相对内存的访问速度,磁盘访问速度要慢1个甚至几个数量级,这就应运而生了各种高性能的磁盘访问算法,最著名的就是缓存区管理算法。

UNIX文件系统的实现共分三层:文件访问接口层、节点和块管理层、设备驱动层,如图8-3所示。



图8-3  文件系统层次结构图

文件访问接口层提供给程序员一整套接口以访问文件,包括对文件的创建、打开、读写、关闭等。节点和块管理层位于文件访问接口的下层,它把存储设备分成许多大小相等的逻辑块和节点进行管理,文件数据以字节流的形式存放在这些逻辑块中,其他属性存放在节点中。

节点是一种逻辑概念,它比磁盘块小,用于记录文件的一些属性,比如文件大小、数据所在块号、修改时间等。节点本身也存储在磁盘块中。

节点和块管理层提供给文件访问接口层丰富的接口进行操作:比如读节点(块)、写节点(块)、分配节点(块)、释放节点(块)。在程序调用文件接口执行写文件操作时,文件访问接口层调用节点和块管理层的接口把数据写入到对应的逻辑块(节点)中,节点和块管理层再负责把逻辑块(节点)写入到设备中,而这是通过调用设备驱动层的接口来实现的。

作为文件系统的最底层,设备驱动层担负着把数据最终写入硬件(或从硬件中读取数据,这里的硬件包含存储设备和外围设备)的任务,它并不知道也不关心所要写入或读取数据的具体格式,在它眼中,数据都是以字节流的形式存在的。

对于节点和块管理层而言,它们也并不需要知道具体的驱动实现,它根据文件节点中的相关信息,在全局驱动函数表中查找对应的驱动并调用,所以驱动对于节点和块管理层也是透   明的。

由于对打印机、电传输入输出终端和纸带打孔机等外围设备的访问也是通过标准文件接口实现的,因此设备驱动层也包含了它们的驱动。

节点和块管理层是文件系统中最复杂的一部分,它的性能直接决定了文件系统的整体性能。节点和块管理层包含了一系列经典的算法来实现对磁盘块的访问,其中的缓存机制就是为了提高性能而实现的一套优秀的存取方案,它是UNIX的一大闪光点。

这样的分层架构提供了很强的扩展性。比如,如果有新的磁盘(外设)增加到系统中,那么只需要在设备驱动层增加它的驱动程序,而节点和块管理层、文件访问接口层不需要做任何改动就可以对它进行读写(如果磁盘块大小不是512字节的话,也需要修改节点和块管理层,不过这种情况并不常见)。

UNIX文件分为正规文件(Regular File)、块文件和字符文件。其中正规文件就是我们通常所访问的存储在磁盘(或其他辅存设备)上的普通文件;而块文件和字符文件都是设备文件,用来描述某个外围设备,这样就把对外围设备的访问抽象成对文件的访问。

顾名思义,块文件对应块设备,比如磁盘、磁带;字符文件对应字符设备,比如打印机、shell终端等。

正规文件的数据存储在磁盘块中。假定块大小为bsize,文件大小为fsize,则需要nblock=(fsize+bsize-1)/bsize个块来存储。最直接的想法就是在磁盘上分配连续nblock个块空间来存储该文件,但是这样磁盘的利用率可能会很低。举一个简单的例子:假如磁盘上共有1000个空闲块,文件F1分配了300个块来存储数据,文件F2分配了200个块,文件F3分配了300个块,文件F4分配了最后的200个块,块全部分配后的情况如图8-4所示。


图8-4  块全部分配后的情况

一段时间后,文件F2和F4被删除,所占用的磁盘块也被释放,如图8-5所示。


图8-5  部分块释放后的情况

这时候文件F5被创建,并请求分配300个块存储数据,尽管磁盘上还有400个块的空间,但由于它们不连续,所以分配失败。

为了提高磁盘的利用率,在分配磁盘块时就不能要求它们在物理上连续。那么在文件系统中如何对这些块进行管理呢?通常有下面两种方法:

1.链表关联

在分配磁盘块给文件时,并不要求它们在物理上是连续的,它们可以是分散的,而通过链表的形式连接到一起,这样只要知道链首块的位置,就可以依次访问到其他各个块。为了更加方便地在文件内进行随意访问,通常采用双向链表。每一个块内预留几个字节存放相邻的上一个块地址(块号)和下一个块地址。这样只需要知道链表中任何一个块的地址,就可以访问到其他所有的块,如图8-6所示。


图8-6  块的链表存储算法

相对于磁盘块而言,图8-6中的块称为逻辑块。逻辑块和物理块相对应,它们通常大小是一样的。但有时也可以不一样,比如物理块大小如果是512字节,那么逻辑块大小可以是256、512、1024、2048,等等。但一般情况下,为了算法的简便和效率,它们的大小保持一致。

采用本算法,上面的问题就迎刃而解。可以先分配块301~500(它们之间用双向链表相连),再分配块801~900(它们之间也用双向链表相连),最后将块500和801以双向链表相连,分配给F5,这样就可以满足它300个块的需求。文件F5逻辑块和物理块的映射图如图8-7所示。


图8-7  文件F5逻辑块和物理块的映射图

逻辑块号和物理块号互相独立,没有任何联系。一个文件内的逻辑块号总是从1开始依次递增,最大为文件所占用的块数,而它所对应的物理块号则取决于磁盘上块的分配情况。如果把号较小的块称作靠前的块,那么靠前的逻辑块所对应的物理块不一定也靠前。比如文件F占用了4个块,那么它的块分布可能如图8-8所示:

首物理块号(8)记录在文件描述结构中(该结构还包括文件大小、文件名等属性)。文件描述结构和文件数据的存储是分离的,它们单独存放在磁盘的某个位置,比如开始几个块。所有文件的描述结构就构成了文件分配表(FileAllocation Table)。访问某个文件时,首先要在文件分配表中找到它对应的文件描述结构,再读出它记录的首物理块号,最后就可以访问该块中数据了。




图8-8  文件F逻辑块和物理块的映射

使用链表关联算法的优点是灵活方便,空间利用率高。由于文件存放在各个单独的块中,空间上并不要求连续,这样空间的分配异常灵活,利用率也很高,只要有空闲的物理块,就可以被分配使用。

链表关联算法的缺点是文件随机访问的效率较低。一个极端的情况是,在打开文件后,首次访问就读取最后一个逻辑块中的数据,那么需要跳过前面所有逻辑块,才能访问到最后一个逻辑块对应的物理块。比如,对于上述文件F,假定每个物理块大小为512字节,文件大小为1900字节,则需要(1900+507)/508= 4个物理块(每个物理块中有4个字节用于记录前后物理块号)。如果用户此时要访问第1800个字节,它位于第4个逻辑块、也就是物理块10内,那么文件系统需要逐次读出物理块8、物理块5和物理块3中的下一个块号才能找到最后一个物理块,加上第一次对文件节点的读取,一共是4次。这样,如果文件存储在n个物理块中,那么访问某指定位置的数据,最少需要2次读磁盘操作(1次访问文件节点,1次访问数据),最多需要n+1次读磁盘操作,平均(n+1+2)/2=n/2+1次,显然是太多了一点。

为了减少磁盘块访问次数,一个简单的优化方案是:在文件描述结构中不仅存储文件的首物理块号信息,同样存储末物理块号信息。这样,对于大小为size的文件F,在访问指定位置p信息时,如果该位置距离文件尾更近(p> size/2),那么就从末物理块开始前向搜索该指定位置所在物理块,否则跟上面一样(p<= size/2),从首物理块开始后向搜索。这样访问文件时,磁盘的平均读操作次数就减少到:(n/2+1+2)/2≈ n/4+1,减少了一半。改进后的块链表存储结构如图8-9所示。



图8-9  改进后的块链表存储结构

如果引入缓存机制,进一步的优化方案是:每次搜索到物理块后,把它的物理块号以链表形式记录到内存中,这样如果所有的物理块都被访问过,那么它们形成的一个完整的链表结构(不包含数据)就被记录到内存中了,以后再访问该文件任何位置的信息,就可以直接搜索内存中的链表结构而找到对应物理块号,再访问该物理块中数据,这就只有一次磁盘操作。

不考虑文件描述结构所占用的磁盘空间,链表结构的空间利用率Rs(文件的数据空间和存储这些数据所需要的实际空间的比率)如下。

Rs = n*508/n*512 =508/512=99.219%(假定文件恰好占用了整数个物理块)。

可见利用率很高。尽管如此,采用链表结构来管理磁盘块还是增加了不少额外的读取开销,为了减少这样的开销,引入了一种新的算法——索引映射算法,这正是UNIX文件系统所采用的磁盘块管理算法。

2.索引映射

文件使用的物理块依然是随机分配的,它们在空间上同样不要求连续,但各个物理块号都是按逻辑顺序集中记录在文件描述结构中的。这样,只要读出文件的描述结构,就可以很快定位任何位置的文件数据所在的物理块号,而无须再次读取磁盘。块号记录的索引结构如图8-10所示。


图8-10  块号记录的索引结构


假定物理块大小为512字节,每个块号占用2个字节,则文件信息描述结构可用20个字节的连续空间来存放10个物理块号。在文件大小不超过10个物理块(5120字节)时,文件数据所在的块号都存放在这20字节空间中,我们称之为块索引记录。如果文件F大小为5000字节,占用了10个物理块,序号是10~14、20、30、31、108和50,那么块索引记录的内容如图8-11所示:


图8-11  F文件描述结构中的块索引记录

其中,块10存放了文件F的第1~512字节的内容,块11存放了第513~1024字节的内容……块50存放了第4609~5000字节的内容。

如果程序需要访问第2000个字节,则它位于(2000+512-1)/512= 4号逻辑块,所以访问块索引记录中的第4个项就可以知道它所在的物理块——13号物理块。在读取13号物理块的512个字节到内存中后,其第464(2000-3*512)个字节就是所需内容。在这里,仅通过2次磁盘读操作(读文件信息描述表和块13)就访问到了指定位置的内容,这也是访问文件F内任意位置内容所需要的操作次数。和链表关联算法平均相比,它大大减少了磁盘读取的次数,提高了性能。其空间利用率Rs=10*512/(10*512+10*2)=512/514≈99.611%,也毫不逊色。

但使用这样的索引结构存在一个问题,它只能存储大小不超过5120个字节的文件,对于更大的文件就没办法了,其原因就在于块索引记录部分的大小有限,从而所表示的物理块的个数也有限,导致所能表示的文件大小也有限。

为了能存储更大的文件,文件系统拿出块索引记录中的一项指向一个特殊的物理块,该物理块的数据还是块索引记录,它最大可记录256个物理块号——这些块存储了文件数据。相对于上面的块索引项,该索引项称为间接索引,或者叫一级间接索引,如图8-12所示。

图8-12  块间接索引记录

使用间接索引,最大可存储大小为265*512=135680≈132K字节的文件,空间利用率Rs=

≈99.609%,比直接索引有细微的降低,但还是很高的。

类似地,对于更大的文件,可用二级间接索引来表示,如图8-13所示。

二级间接索引记录最大可存储65545*512=33559040≈32M字节大小的文件,空间利用率Rs=

≈99.609%,没有什么改变。

依此可以类推,使用三级索引记录,最大可存储大小为9*512+256*256*256*512=8589939200≈8G字节的文件。

一般地,使用i级索引记录,最大可存储大小为(256i + 9)*512字节的文件,空间利用率



.(其中255**i = 256i)


图8-13  块二级间接索引记录

Rs随着i的增大而减小,且当i→∝时,



由此可见,不管使用多少级索引记录来管理磁盘的物理块时,利用率都会很高。但索引层次越多,寻找到对应物理块所需要的磁盘读操作也可能越多,性能就会略微下降,而且这还是在最理想情况下的空间利用率(文件占满了整个块),实际上常常是达不到这么高的。以图8-11为例,如果文件只有1个字节大小,那么它也需要占用1个物理块,这时


(因此在磁盘上如果存储过多的远小于物理块大小的小文件,会形成大量的磁盘碎片而降低空间利用率)。如果文件大小为9*512+1= 4609个字节,那么它需要占用10个物理块,这时Rs=

,这是一个相对更贴近实际的数字。

 

8.2.2 UNIX文件系统

如前所述,UNIX文件包含描述信息和数据两部分。描述信息包含文件大小、块索引记录、修改时间等属性,定义为inode结构。

-------------------------选自光盘文件/usr/sys/ino.h-------------------------
/*
 * 磁盘上的inode结构。除
  * check,df,dump命令外,
  * 系统中并没有(直接)使用它。
 */

/*
  * Inode structure as it appears on
  * the disk. Not used by the system,
  * but by things like check, df, dump.
  */

 struct inode
 {
   int i_mode;
   char i_nlink;
   char i_uid;
   char i_gid;
   char i_size0;
   char *i_size1;
   int i_addr[8];
   int i_atime[2];
   int i_mtime[2];
 };

 

—     i_mode字段

它定义文件的一些特定信息,比如目录结构、读写权限等。其16位对应宏定义如下:

-------------------------选自光盘文件/usr/sys/ino.h-------------------------

/* modes */

 #define IALLOC 0100000              /* file is used */

 #define IFMT   060000              /* type of file */

 #define IFDIR  040000              /* directory */

 #define IFCHR  020000              /* character special*/

 #define IFBLK  060000              /* block special, 0 isregular */

 #define ILARG  010000              /* large addressingalgorithm */

 #define ISUID  04000               /* set user id onexecution */

 #define ISGID  02000               /* set group id onexecution */

 #define ISVTX  01000               /* save swapped texteven after use */

 #define IREAD  0400                /* read, write,execute permissions */

 #define IWRITE 0200

 #define IEXEC  0100

对应的含义如图8-14所示:

                      图8-14  i_mode各位含义

位14和13很重要,正是它区分了文件的类型,这样我们可以知道文件是一个普通文件还是设备文件,也正是它把外部设备也都统一成文件访问。

位14和13

文件类型

00

随机访问文件(普通文件)

10

随机访问目录

01

字符设备文件,表示字符设备,比如交换终端、打印机等

11

块设备文件,表示块设备,比如磁盘等

—    i_nlink字段本文件被其他文件链接的个数,详细说明请参照link/unlink函数的讲解。

—     i_uid字段

如果imode的位11被设置,那么该字段表示文件所有者的用户ID。

—    i_gid字段

如果imode的位10被设置,那么该字段表示文件所有者的组ID。

—    i_size0、i_size1字段


它们组合用来表示文件的大小(字节数),文件大小等于i_size0<<16+i_size1。

虽然一共有32位,但实际只使用24位,所以UNIX所支持的文件最大是224 = 16M。在今天看来这也许太小了,但在当时存储设备容量有限的情况下,已经算很大了。而且它比CPU支持的最大位数还多了8位,换算到32位系统中,相当于支持40位大小的文件——1024G=1T。但对于块设备或字符设备文件,它们是没有意义的,因为设备上输入、输出的字符个数是不确定的,而且另有结构来记录输入输出的字符。

—    i_addr[8]字段

① 对于普通文件,它是文件数据所在块的块号。i_addr的每一个元素记录一个块号,该块存放了文件数据。如果该元素未被使用,它的值为0。如果使用直接索引结构,最多可记录8个块,所以它的大小不超过8*512=4K。

如果文件大小超过4K,imode字段的位12会被设置,标识它是大文件。在这种情况下,i_addr使用一级间接索引结构或二级间接索引结构来记录文件数据所在的块。使用一级间接索引时,和8.2.1节所讲的稍有区别,i_addr[0]~[6]都指向直接索引块。而i_addr[7]等于0(无效物理块号)。

这样所表示的文件最大为1792*512=896K。UNIX大文件存储结构如图8-15所示。

图8-15  UNIX大文件存储结构

对于更大的文件,UNIX称之为“巨型文件”,采用二级索引结构记录。此时i_addr[0]~[6]指向直接索引块,而i_addr[7]指向一个间接索引块,它最多可记录249个直接索引块的块号,这样巨型文件最多可有(7+249)*256=256*256=65536个数据块,大小为65536*512=32M,UNIX巨型文件存储结构如图8-16所示。

但实际上,UNIX文件最大为224 =16M,所以“巨型文件”实际上最多可有16M/(512*256) = 128个直接索引块。

② 对于设备文件(块或字符设备),只有i_addr[0]被使用,它记录了文件所在的设备号(高字节是主设备号,低字节是从设备号)。

 

—    i_atime[2]

表示最后一次访问文件(读、写、打开或关闭)的时间,单位是秒,即全局变量time[2]所记录的自从1970年以来的秒数。

—    i_mtime[2]

和i_atime类似,但它表示最后一次写文件的时间。很显然,i_atime≥ i_mtime。

UNIX文件系统采用树状目录结构。对于每个存储设备,都有一个唯一的根目录——“/”,所有其他的文件和目录都建立在它下面,如图8-16所示。



图8-16  UNIX巨型文件存储结构


图8-17  UNIX文件树状图

而根设备外的其他存储设备在加载时,其根目录被映射(mount)到了根设备上的某个目录,通过对该目录的访问实现对新设备的访问,因此UNIX文件系统中只有一个唯一的“/”目录,图8-17只是逻辑概念。

如前所述,磁盘上每一块都有一个唯一的编号,0磁面、0磁道、1扇区称为1号块,0磁面、0磁道、2扇区称为2号块,依次类推。当然,这里的唯一只是针对同一类型的磁盘而言的,同一台电脑上不同的磁盘,其块编号都从1开始,所以在对磁盘内的某块进行访问时,只需要给出块号就可以了。

为了方便文件的管理,UNIX文件系统把磁盘空间分成两部分,节点空间和数据空间。节点空间用来存放文件描述信息,也就是inode结构。数据空间存放文件数据。因为inode结构的大小为32字节,所以每个磁盘块可存放512/32=16个节点,也就是说,1个磁盘块可存放16个文件的描述信息。节点空间和数据空间是明确分开而没有重叠的,节点空间占用磁盘上前n个块,其中n=filsys.s_isize(详见8.2.3节);剩余块用于存放数据,如图8-18所示。

图8-18  节点和数据分布示意图

对同一个块而言,它要么只能存储节点,要么只能存储数据,不能既存储节点又存储数据。节点空间可称为“文件描述表”。

文件系统同样把节点进行唯一编号。其中,位于2号块上的1号节点称之为根节点,它存储了根目录的描述信息。1号块称之为“超级块”,保留用来存储文件分配表,所以1号节点存放在2号块的起始32个字节中,其他节点依次递增。比如2号节点存放在2号块的第33~64字节中。一般地,n号节点存放在号块中,并位于块内第((n-1)%16)*32~ ((n-1)%16)*32+31字节中。

由于节点块是连续的,所以系统中节点的编号也一定是连续的。根据唯一的节点号,就可以知道它所在磁盘上的位置,从而进行访问。UNIX磁盘空间分布的情况如图8-19所示。



图8-19  UNIX磁盘空间分布图(最后几块保留作为交换区)

文件的唯一标识是文件名(文件的全路径名)。在内核中,以句柄(其实是一个整数,UNIX称之为文件描述符——file descriptor)作为进程内所打开文件的唯一标识。用户在调用open打开一个文件时(入参是文件名和访问类型),open接口根据文件名找到它对应的描述信息——文件描述表中的某节点,再根据描述信息中的i_addr字段找到对应的数据块,访问数据。

目录又称为“文件夹”,就是包含多个文件或目录的“特殊文件”。目录在磁盘上的存储方式和文件一样,也分为描述信息和数据两部分。唯一不同的是,目录的数据是所包含文件的文件名和对应节点号,可称之为“文件项”——就是u.u_dent结构。目录user下的文件结构如图8-20所示。



图8-20  目录user下含“Jerry”,“Tom”和“Hawk”3个文件

文件系统是如何根据文件名(相对路径或全路径)找到它对应的描述信息的呢?这是根据文件所在的目录找到的。如图8-20所示,每一个文件(目录)的名称和描述节点号都在它的父目录的数据区。而要找到其父目录,又要找到父目录的父目录,这样一级一级的递归搜索,直至根目录。所以在查找文件时,如果是全路径(绝对路径),从则根目录开始一级一级地依次查找,直到找到所需文件(如找不到则返回错误);如果是相对路径,则从当前路径开始进行同样的查找。事实上,由于目录结构呈树状结构,对文件的访问也就是对某个叶子节点的访问,因此本过程类似于对n叉树中叶子节点的访问,而对某个目录的访问类似于对n叉树非叶子节点的访问。

比如:给定文件“/bin/sh”,则首先从1号节点中读出根目录描述信息,再根据i_addr读出根目录数据,然后从中找到目录bin的描述节点号,再读出bin的节点和数据。再从bin的数据中找到文件sh的描述节点号;最后根据该节点号读出文件sh的描述信息,就可以访问文件的数据了。

     在AIX 5.2系统中运行“df”命令可以看到如下输出:


图8-21  AIX中df命令输出

可以看出系统中共有5个设备,其中设备/dev/hd4被加载到根目录,设备/dev/hd4就是根设备。它虽然还有192704个空闲块,但相比数据空间的22121168个块已经不足1%,所以认为其空间已100%用完。值得注意的是第5和第6列,它们表示已使用的节点空间及使用率。相对于其数据空间,设备/dev/hd4的节点空间才使用了1%。造成这种情况的一个原因可能是大文件比较多。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值