山用英语怎么读:linux文件系统基础知识

来源:百度文库 编辑:中财网 时间:2024/04/28 19:51:46
2009年05月03日 06:37 来源:ChinaUnix博客 作者:lvfeihu316 编辑:周荣茂

    1、linux文件系统分配策略:

     块分配( block allocation ) 和 扩展分配 ( extent allocation )

     块分配:磁盘上的文件块根据需要分配给文件,避免了存储空间的浪费。但当文件扩充时,会造成文件中文件块的不连续,从而导致过多的磁盘寻道时间。

     每一次文件扩展时,块分配算法就需要写入文件块的结构信息,也就是 meta-dada 。meta-data总是与文件一起写入存储设备,改变文件的操作要等到所有meta-data的操作都完成后才能进行,

     因此,meta-data的操作会明显降低整个文件系统的性能。

     扩展分配: 文件创建时,一次性分配一连串连续的块,当文件扩展时,也一次分配很多块。meta-data在文件创建时写入,当文件大小没有超过所有已分配文件块大小时,就不用写入meta-data,直到需要再分配文件块的时候。

     扩展分配采用成组分配块的方式,减少了SCSI设备写数据的时间,在读取顺序文件时具有良好的性能,但随机读取文件时,就和块分配类似了。

     文件块的组或块簇 ( block cluster) 的大小是在编译时确定的。簇的大小对文件系统的性能有很大的影响。

     注: meta-data 元信息:和文件有关的信息,比如权限、所有者以及创建、访问或更改时间等。

    2、文件的记录形式

     linux文家系统使用索引节点(inode)来记录文件信息。索引节点是一种数据结构,它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息。

    一个文件系统维护了一个索引节点的数组,每个文件或目录都与索引节点数组中的唯一的元素对应。每个索引节点在数组中的索引号,称为索引节点号。

     linux文件系统将文件索引节点号和文件名同时保存在目录中,所以,目录只是将文件的名称和它的索引节点号结合在一起的一张表,目录中每一对文件名称和索引节点号称为一个连接。

    对于一个文件来说,有一个索引节点号与之对应;而对于一个索引节点号,却可以对应多个文件名。

     连接分为软连接和硬连接,其中软连接又叫符号连接。

     硬连接: 原文件名和连接文件名都指向相同的物理地址。目录不能有硬连接;硬连接不能跨文件系统(不能跨越不同的分区),文件在磁盘中只有一个拷贝。

     由于删除文件要在同一个索引节点属于唯一的连接时才能成功,因此硬连接可以防止不必要的误删除。

     软连接: 用 ln -s 命令建立文件的符号连接。符号连接是linux特殊文件的一种,作为一个文件,它的数据是它所连接的文件的路径名。没有防止误删除的功能。

    3、文件系统类型:

    

     ext2 : 早期linux中常用的文件系统

     ext3 : ext2的升级版,带日志功能

     RAMFS : 内存文件系统,速度很快

     NFS : 网络文件系统,由SUN发明,主要用于远程文件共享

     MS-DOS : MS-DOS文件系统

     VFAT : Windows 95/98 操作系统采用的文件系统

     FAT : Windows XP 操作系统采用的文件系统

     NTFS : Windows NT/XP 操作系统采用的文件系统

     HPFS : OS/2 操作系统采用的文件系统

     PROC : 虚拟的进程文件系统

     ISO9660 : 大部分光盘所采用的文件系统

     ufsSun : OS 所采用的文件系统

     NCPFS : Novell 服务器所采用的文件系统

     SMBFS : Samba 的共享文件系统

     XFS : 由SGI开发的先进的日志文件系统,支持超大容量文件

     JFS :IBM的AIX使用的日志文件系统

     ReiserFS : 基于平衡树结构的文件系统

     udf: 可擦写的数据光盘文件系统

    4、虚拟文件系统VFS

    

     linux支持的所有文件系统称为逻辑文件系统,而linux在传统的逻辑文件系统的基础上增加料一个蓄念文件系统( Vitual File System ,VFS) 的接口层。

     虚拟文件系统(VFS) 位于文件系统的最上层,管理各种逻辑文件系统,并可以屏蔽各种逻辑文件系统之间的差异,提供统一文件和设备的访问接口。

    5、文件的逻辑结构

     文件的逻辑结构可分为两大类: 字节流式的无结构文件 和 记录式的有结构文件。

     由字节流(字节序列)组成的文件是一种无结构文件或流式文件 ,不考虑文件内部的逻辑结构,只是简单地看作是一系列字节的序列,便于在文件的任意位置添加内容。

     由记录组成的文件称为记录式文件 ,记录是这种文件类型的基本信息单位,记录式文件通用于信息管理。

    6、文件类型

    

     普通文件 : 通常是流式文件

     目录文件 : 用于表示和管理系统中的全部文件

     连接文件 : 用于不同目录下文件的共享

     设备文件 : 包括块设备文件和字符设备文件,块设备文件表示磁盘文件、光盘等,字符设备文件按照字符操作终端、键盘等设备。

     管道(FIFO)文件 : 提供进程建通信的一种方式

     套接字(socket) 文件: 该文件类型与网络通信有关

    7、文件结构: 包括索引节点和数据

     索引节点 : 又称 I 节点,在文件系统结构中,包含有关相应文件的信息的一个记录,这些信息包括文件权限、文件名、文件大小、存放位置、建立日期等。文件系统中所有文件的索引节点保存在索引节点表中。

     数据 : 文件的实际内容。可以是空的,也可以非常大,并且拥有自己的结构。

    8、ext2文件系统

    

     ext2文件系统的数据块大小一般为 1024B、2048B 或 4096B

     ext2文件系统采用的索引节点(inode):

     索引节点采用了多重索引结构,主要体现在直接指针和3个间接指针。直接指针包含12个直接指针块,它们直接指向包含文件数据的数据块,紧接在后面的3个间接指针是为了适应文件的大小变化而设计的。

     e.g: 假设数据块大小为1024B ,利用12个直接指针,可以保存最大为12KB的文件,当文件超过12KB时,则要利用单级间接指针,该指针指向的数据块保存有一组数据块指针,这些指针依次指向包含有实际数据的数据块,

    

     假如每个指针占用4B,则每个单级指针数据块可保存 1024/4=256 个数据指针,因此利用直接指针和单级间接指针可保存

    1024*12+1024*256=268 KB的文件。当文件超过268KB时,再利用二级间接指针,直到使用三级间接指针。

     利用直接指针、单级间接指针、二级间接指针、三级间接指针可保存的最大文件大小为:

     1024*12+1024*256+1024*256*256+1024*256*256*256=16843020 KB,约 16GB

     若数据块大小为2048B,指针占4B,则最大文件大小为: 2048*12+2048*512+2048*512*512+2048*512*512*512=268,960,792 KB 约 268GB

     若数据块大小为4096B,指针占4B,则最大文件大小为: 4096*12+4096*1024+4096*1024*1024+4096*1024*1024*1024=4,299,165,744 KB ,约 4TB

     注: 命令 tune2fs -l /dev/sda5 可查看文件系统

     ext2文件系统最大文件名长度: 255个字符

    

     ext2文件系统的缺点:

     ext2在写入文件内容的同时并没有同时写入文件meta-data, 其工作顺序是先写入文件的内容,然后等空闲时候才写入文件的meta-data。若发生意外,则文件系统就会处于不一致状态。

     在重新启动系统的时候,linux会启动 fsk ( file system check) 的程序,扫描整个文件系统并试图修复,但不提供保证。

    9、ext3文件系统:

    

     ext3基于ext2的代码,所以磁盘格式与ext2相同,使用相同的元数据。

     ext2文件系统无损转化为ext3文件系统: tune2fs -j /dev/sda6

    

     日志块设备( Journaling block device layer,JBD)完成ext3文件系统日志功能。JBD不是ext3文件系统所特有的,它的设计目标是为了向一个块设备添加日志功能。

     当一个文件修改执行时,ext3文件系统代码将通知JBD,称为一个事务(transaction)。发生意外时,日志功能具有的重放功能,能重新执行中断的事务。

    

     日志中的3种数据模式:

     1)、data=writeback :不处理任何形式的日志数据,给用户整体上的最高性能

     2)、data=odered :只记录元数据日志,但将元数据和数据组成一个单元称为事务(transaction) 。此模式保持所句句的可靠性与文件系统的一致性,性能远低于data=writeback模式,但比data=journal模式快

     3)、data=journal :提供完整的数据及元数据日志,所有新数据首先被写入日志,然后才被定位。意外发生过后,日志可以被重放,将数据与元数据带回一致状态。这种模式整体性能最慢,但数据需要从磁盘读取和写入磁盘时却是3种模式中最快的。

     ext3文件系统最大文件名长度: 255个字符

     ext3文件系统的优点:可用性、数据完整性、速度、兼容性

    10、ReiserFS文件系统

    

     ReiserFS文件系统是由Hans Reiser和他领导的开发小组共同开发的,整个文件系统完全是从头设计的,是一个非常优秀的文件系统。也是最早用于Linux的日志文件系统之一。

     ReiserFS的特点

     先进的日志机制

     ReiserFS有先进的日志(Journaling/logging)功能 机制。日志机制保证了在每个实际数据修改之前,相应的日志已经写入硬盘。文件与数据的安全性有了很大提高。

     高效的磁盘空间利用

     Reiserfs对一些小文件不分配inode。而是将这些文件打包,存放在同一个磁盘分块中。而其它文件系统则为每个小文件分别放置到一个磁盘分块中。

     独特的搜寻方式

    

     ReiserFS基于快速平衡树(balanced

    tree)搜索,平衡树在性能上非常卓越,这是一种非常高效的算法。ReiserFS搜索大量文件时,搜索速度要比ext2快得多。Reiserfs文件

    系统使用B*Tree存储文件,而其它文件系统使用B+Tree树。B*Tree查询速度比B+Tree要快很多。Reiserfs在文件定位上速度非常

    快。

     在实际运用中,ReiserFS 在处理小于 4k 的文件时,比ext2 快 5 倍;带尾文件压缩功能(默认)的ReiserFS 比ext2文件系统多存储6%的数据。

     支持海量磁盘

     ReiserFS是一个非常优秀的文件系统,一直被用在高端UNIX系统上,可轻松管理上百G的文件系统,ReiserFS文件系统最大支持的文件系统尺寸为16TB。这非常适合企业级应用中。

     优异的性能

    

    

     由于它的高效存储和快速小文件I/O特点,使用ReiserFs文件系统的PC,在启动X窗口系统时,所花的时间要比在同一台机器上使用ext2文

    件系统少1/3。另外,ReiserFS文件系统支持单个文件尺寸为4G的文件,这为大型数据库系统在linux上的应用提供了更好的选择。

    转自:http://man.chinaunix.net/tech/lyceum/linuxK/fs/filesystem.html

     本章主要描叙Linux核心对文件系统的支持, 虚拟文件系统(VFS)以及Linux核心对实际文件系统的支持。

    Linux的最重要特征之一就是支持多种文件系统。这样它更加灵活并可以和许多其它种操作系统共存。在本文写作时Linux已经支持15种文件系统:

    ext,ext2,xia,minix,umsdos,msdos,vfat,proc,smb,ncp,iso9660,sysv,hpfs,affs

    以及ufs。毫无疑问,今后支持的文件系统类型还将增加。

    Linux和Unix并不使用设备标志符(如设备号或驱动器名称)来访问独立文件系统,而是通过一个将整个文件系统表示成单一实体的层次树结构来访问它。

    Linux每安装(mount)一个文件系统时都会其加入到文件系统层次树中。不管是文件系统属于什么类型,都被连接到一个目录上且此文件系统上的文件将

    取代此目录中已存在的文件。这个目录被称为安装点或者安装目录。当卸载此文件系统时这个安装目录中原有的文件将再次出现。

    当磁盘初始化时(使用fdisk),磁盘中将添加一个描叙物理磁盘逻辑构成的分区结构。每个分区可以拥有一个独立文件系统如EXT2。文件系统将文件组织

    成包含目录,软连接等存在于物理块设备中的逻辑层次结构。包含文件系统的设备叫块设备。Linux文件系统认为这些块设备是简单的线性块集合,它并不关心

    或理解底层的物理磁盘结构。这个工作由块设备驱动来完成,由它将对某个特定块的请求映射到正确的设备上去;此块所在硬盘的对应磁道、扇区及柱面数都被保存

    起来。不管哪个设备持有这个块,文件系统都必须使用相同的方式来寻找并操纵此块。Linux文件系统不管(至少对系统用户来说)系统中有哪些不同的控制器

    控制着哪些不同的物理介质且这些物理介质上有几个不同的文件系统。文件系统甚至还可以不在本地系统而在通过网络连接的远程硬盘上。设有一个根目录内容如下

    的SCSI硬盘:

    A E boot etc lib opt tmp usr

    C F cdrom fd proc root var sbin

    D bin dev home mnt lost+found

    此时不管是用户还是程序都无需知道他们现在操纵的这些文件中的/C实际上是位于系统第一个IDE硬盘上并已安装VFAT文件系统。在此例中/E表示系统中

    第二个IDE控制器上的主IDE硬盘。至于第一个IDE控制器是PCI控制器和第二个则是控制IDE

    CDROM的ISA控制器无关紧要。当使用modem通过PPP网络协议来拨入网络时,可以将Alpha AXP

    Linux文件系统安装到/mnt/remote目录下。

    文件系统中的文件是数据的集合;包含本章内容的文件是一个名叫filesystems.tex的ASCII文件。文件系统不仅包含着文件中的数据而且还有

    文件系统的结构。所有Linux用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其中。此外文件系统中必须包含安全信息以便保持操作系统的基

    本完整性。没人愿意使用一个动不动就丢失数据和文件的操作系统。

     Linux最早的文件系统是Minix,它受限甚大且性能低下。其文件名最长不能超过14个字符(虽然比8.3

    文件名要好)且最大文件大小为64M字节。64M字节看上去很大,但实际上一个中等的数据库将超过这个尺寸。

    第一个专门为Linux设计的文件系统被称为扩展文件系统(Extended File

    System)或EXT。它出现于1992年四月,虽然能够解决一些问题但性能依旧不好。1993年扩展文件系统第二版或EXT2被设计出来并添加到

    Linux中。它是本章将详细讨论的文件系统。

     将EXT文件系统添加入Linux产生了重大影响。每个实际文件系统从操作系统和系统服务中分离出来,它们之间通过一个接口层:虚拟文件系统或VFS来通讯。

    VFS使得Linux可以支持多个不同的文件系统,每个表示一个VFS的通用接口。由于软件将Linux文件系统的所有细节进行了转换,

    所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。 Linux的虚拟文件系统允许用户同时能透明地安装许多不同的文件系统。

    虚拟文件系统的设计目标是为Linux用户提供快速且高效的文件访问服务。同时它必须保证文件及其数据的正确性。这两个目标相互间可能存在冲突。当安装一

    个文件系统并使用时, Linux

    VFS为其缓存相关信息。此缓存中数据在创建、写入和删除文件与目录时如果被修改,则必须谨慎地更新文件系统中对应内容。

    如果能够在运行核心内看到文件系统的数据结构,

    那么就可以看到那些正被文件系统读写的数据块。描叙文件与目录的数据结构被不断的创建与删除而设备驱动将不停地读取与写入数据。这些缓存中最重要的是

    Buffer Cache,它被集成到独立文件系统访问底层块设备的例程中。当进行块存取时数据块首先将被放入Buffer

    Cache里并根据其状态保存在各个队列中。此Buffer Cache不仅缓存数据而且帮助管理块设备驱动中的异步接口。

    

    9.1 第二代扩展文件系统(EXT2)

    

    

    

    

     图9.1 EXT2文件系统的物理分布

    

    

    第二代扩展文件系统由Rey Card设计,其目标是为Linux提供一个强大的可扩展文件系统。它同时也是Linux界中设计最成功的文件系统。

     象很多文件系统一样,

    EXT2建立在数据被保存在数据块中的文件内这个前提下。这些数据块长度相等且这个长度可以变化,某个EXT2文件系统的块大小在创建(使用

    mke2fs)时设置。

    每个文件的大小和刚好大于它的块大小正数倍相等。如果块大小为1024字节而一个1025字节长的文件将占据两个1024字节大小的块。这样你不得不浪费

    差不多一般的空间。我们通常需要在CPU的内存利用率和磁盘空间使用上进行折中。而大多数操作系统,包括Linux在内,为了减少CPU的工作负载而被迫

    选择相对较低的磁盘空间利用率。并不是文件中每个块都包含数据,其中有些块被用来包含描叙此文件系统结构的信息。EXT2通过一个inode结构来描叙文

    件系统中文件并确定此文件系统的拓扑结构。

    inode结构描叙文件中数据占据哪个块以及文件的存取权限、文件修改时间及文件类型。EXT2文件系统中的每个文件用一个inode来表示且每个

    inode有唯一的编号。文件系统中所有的inode都被保存在inode表中。

    EXT2目录仅是一个包含指向其目录入口指针的特殊文件(也用inode表示)。

    图9.1给出了占用一系列数据块的EXT2文件系统的布局。对文件系统而言文件仅是一系列可读写的数据块。文件系统并不需要了解数据块应该放置到物理介质

    上什么位置,这些都是设备驱动的任务。无论何时只要文件系统需要从包含它的块设备中读取信息或数据,它将请求底层的设备驱动读取一个基本块大小整数倍的数

    据块。EXT2文件系统将它所使用的逻辑分区划分成数据块组。每个数据块组将那些对文件系统完整性最重要的信息复制出来,

    同时将实际文件和目录看作信息与数据块。为了发生灾难性事件时文件系统的修复,这些复制非常有必要。以下一节将着重描叙每个数据块组的内容。

    

    9.1.1 The EXT2 Inode

    

    

    

    

     图9.2 EXT2 Inode

    

    在EXT2文件系统中inode是基本块;文件系统中的每个文件与目录由唯一的inode来描叙。每个数据块组的EXT2

    inode被保存在inode表中, 同时还有一个位图被系统用来跟踪已分配和未分配的inode。图 9.2给出了EXT2

    inode的格式,它包含以下几个域:

    

    mode 它包含两类信息;inode描叙的内容以及用户使用权限。EXT2中的inode可以表示一个文件、目录、符号连接、块设备、字符设备或FIFO。 Owner Information 表示此文件或目录所有者的用户和组标志符。文件系统根据它可以进行正确的存取。 Size 以字节计算的文件尺寸。 Timestamps inode创建及最后一次被修改的时间。 Datablocks 指向此inode描叙的包含数据的块指针。前12个指针指向包含由inode描叙的物理块, 最后三个指针包含多级间接指针。例如两级间接指针指向一块指针,而这些指针又指向一些数据块。这意味着访问文件尺寸小于或等于12个数据块的文件将比访问大文件快得多。

     EXT2 inode还可以描叙特殊设备文件。虽然它们不是真正的文件, 但可以通过它们访问设备。所有那些位于/dev中的设备文件可用来存取Linux设备。例如mount程序可把设备文件作为参数。

    

    9.1.2 EXT2 超块

     超块中包含了描叙文件系统基本尺寸和形态的信息。文件系统管理器利用它们来使用和维护文件系统。 通常安装文件系统时只读取数据块组0中的超块,但是为了防止文件系统被破坏, 每个数据块组都包含了复制拷贝。超块包含如下信息:

    

    Magic Number 文件系统安装软件用来检验是否是一个真正的EXT2文件系统超块。当前EXT2版本中为0xEF53。 Revision Level 这个主从修订版本号让安装代码能判断此文件系统是否支持只存在于某个特定版本文件系统中的属性。同时它还是特性兼容标志以帮助安装代码判断此文件系统的新特性是否可以安全使用。 Mount Count and Maximum Mount Count

    系统使用它们来决定是否应对此文件系统进行全面检查。每次文件系统安装时此安装记数将递增,当它等于最大安装记数时系统将显示一条警告信息

    “maxumal mount count reached, running e2fsck is recommended”。 Block Group Number 超块的拷贝。 Block Size 以字节记数的文件系统块大小,如1024字节。 Blocks per Group 每个组中块数目。当文件系统创建时此块大小被固定下来。 Free Blocks 文件系统中空闲块数。 Free Inodes 文件系统中空闲Inode数。 First Inode 文件系统中第一个inode号。EXT2根文件系统中第一个inode将是指向'/'目录的目录入口。

    

    9.1.3 EXT2 组标志符

     每个数据块组都拥有一个描叙它结构。象超块一样,所有数据块组中的组描叙符被复制到每个数据块组中以防文件系统崩溃。每个组描叙符包含以下信息:

    

    

    Blocks Bitmap 对应此数据块组的块分配位图的块号。在块分配和回收时使用。 Inode Bitmap 对应此数据块组的inode分配位图的块号。在inode分配和回收时使用。 Inode Table 对应数据块组的inode表的起始块号。每个inode用下面的EXT2 inode结构来表示。 Free blocks count, Free Inodes count, Used directory count

    

     组描叙符放置在一起形成了组描叙符表。每个数据块组在超块拷贝后包含整个组描叙符表。EXT2文件系统仅使用第一个拷贝(在数据块组0中)。其它拷贝都象超块拷贝一样用来防止主拷贝被破坏。

    

    9.1.4 EXT2 目录

    

    

    

    

     图9.3 EXT2目录

    

    

    在EXT2文件系统中目录是用来创建和包含文件系统中文件存取路径的特殊文件。图9.3给出了内存中的目录入口布局。

     目录文件是一组目录入口的链表,它们包含以下信息:

    

    inode 对应每个目录入口的inode。它被用来索引储存在数据块组的Inode表中的inode数组。 在图9.3中file文件的目录入口中有一个对inode号11的引用。 name length 以字节记数的目录入口长度。 name 目录入口的名称

     每个目录的前两个入口总是"."和".."。它们分别表示当前目录和父目录。

    

    9.1.5 在EXT2文件系统中搜寻文件

    Linux文件名的格式与Unix类似,是一系列以"/"隔开的目录名并以文件名结尾。/home/rusling/.cshrc中/home和

    /rusling都是目录名而文件名为.cshrc。象Unix系统一样,Linux并不关心文件名格式本身,它可以由任意可打印字符组成。为了寻找

    EXT2文件系统中表示此文件的inode,系统必须将文件名从目录名中分离出来。

     我们所需要的第一个inode是根文件系统的inode,它被存放在文件系统的超块中。为读取某个EXT2 inode,

    我们必须在适当数据块组的inode表中进行搜寻。如果根inode号为42则我们需要数据块组0

    inode表的第42个inode。此根inode对应于一个EXT2目录,即根inode的mode域将它描叙成目录且其数据块包含EXT2目录入口。

    home目录是许多目录的入口同时此目录给我们提供了大量描叙/home目录的inode。我们必须读取此目录以找到rusling目录入口,此入口又提

    供了许多描叙/home/rusling目录的inode。最后读取由/home/rusling目录描叙的inode指向的目录入口以找出.cshrc

    文件的inode号并从中取得包含在文件中信息的数据块。

    

    9.1.6 改变EXT2文件系统中文件的大小

    文件系统普遍存在的一个问题是碎块化。一个文件所包含的数据块遍布整个文件系统,这使得对文件数据块的顺序访问越来越慢。EXT2文件系统试图通过分配一

    个和当前文件数据块在物理位置上邻接或者至少位于同一个数据块组中的新块来解决这个问题。只有在这种分配策略失败时才在其它数据块组中分配空间。

     当进程准备写某文件时,

    Linux文件系统首先检查数据是否已经超出了文件最后一个被分配的块空间。如果是则必须为此文件分配一个新数据块。进程将一直等待到此分配完成;然后将

    其余数据写入此文件。EXT2块分配例程所作的第一件事是对此文件系统的EXT2超块加锁。这是因为块分配和回收将导致超块中某些域的改变,Linux文

    件系统不能在同一时刻为多个进程进行此类服务。如果另外一个进程需要分配更多的数据块时它必须等到此进程完成分配操作为止。

    在超块上等待的进程将被挂起直到超块的控制权被其当前使用者释放。对超块的访问遵循先来先服务原则,一旦进程取得了超块的控制则它必须保持到操作结束为

    止。如果系统中空闲块不多则此分配的将失败,进程会释放对文件系统超块的控制。

    如果EXT2文件系统被设成预先分配数据块则我们可以从中取得一个。预先分配块实际上并不存在,它们仅仅包含在已分配块的位图中。我们试图为之分配新数据

    块文件所对应的VFS

    inode包含两个EXT2特殊域:prealloc_block和prealloc_count,它们分别代表第一个预先分配数据块的块号以及各自的数

    目。如果没有使用预先分配块或块预先分配数据块策略,则EXT2文件系统必须分配一个新块。它首先检查此文件最后一个块后的数据块是否空闲。从逻辑上来说

    这是让其顺序访问更快的最有效块分配策略。如果此块已被使用则它会在理想块周围64个块中选择一个。这个块虽然不是最理想但和此文件的其它数据块都位于同

    一个数据块组中。

    如果此块还是不空闲则进程将在所有其它数据块组中搜寻,直到找到一空闲块。块分配代码将在某个数据块组中寻找一个由8个空闲数据块组成的簇。如果找不到那

    么它将取更小的尺寸。如果使用了块预先分配则它将更新相应的prealloc_block和prealloc_count。

     找到空闲块后块分配代码将更新数据块组中的位图并在buffer

    cache中为它分配一个数据缓存。这个数据缓存由文件系统支撑设备的标志符以及已分配块的块号来标志。缓存中的数据被置0且缓存被标记成dirty以显

    示其内容还没有写入物理磁盘。最后超块也被标记为dirty以表示它已被更新并解锁了。如果有进程在等待这个超块则队列中的第一个进程将得到运行并取得对

    超块的独占控制。如果数据块被填满则进程的数据被写入新数据块中,以上的整个过程将重复且另一个数据块被分配。

    

    9.2 虚拟文件系统(VFS)

    

    

    

    

     图9.4 虚拟文件系统的逻辑示意图

    

    图9.4给出了Linux核心中虚拟文件系统和实际文件系统间的关系。此虚拟文件系统必须能够管理在任何时刻mount到系统的不同文件系统。它通过维护一个描叙整个虚拟文件系统和实际已安装文件系统的结构来完成这个工作。

     容易让人混淆的是VFS使用了和EXT2文件系统类似的方式:超块和inode来描叙文件系统。象EXT2 inode一样 VFS

    inode描叙系统中的文件和目录以及VFS中的内容和拓扑结构。从现在开始我将用VFS inode和VFS超块来将它们和EXT2

    inode和超块进行区分。

    文件系统初始化时将其自身注册到VFS中。它发生在系统启动和操作系统初始化时。这些实际文件系统可以构造到核心中也可以设计成可加载模块。文件系统模块

    可以在系统需要时进行加载,例如VFAT就被实现成一个核心模块,当mount

    VFAT文件系统时它将被加载。mount一个基于块设备且包含根文件系统的文件系统时,VFS必须读取其超块。每个文件系统类型的超块读取例程必须了解

    文件系统的拓扑结构并将这些信息映射到VFS超块结构中。VFS在系统中保存着一组已安装文件系统的链表及其VFS超块。每个VFS

    超块包含一些信息以及一个执行特定功能的函数指针。例如表示一个已安装EXT2文件系统的超块包含一个指向EXT2相关inode读例程的指针。这个

    EXT2 inode读例程象所有文件系统相关读例程一样填充了VFS inode中的域。每个VFS超块包含此文件系统中第一个VFS

    inode的指针。对于根文件系统此inode表示的是"/"目录。这种信息映射方式对EXT2文件系统非常有效但是对其它文件系统要稍差。

     系统中进程访问目录和文件时将使用系统调用遍历系统的VFS inode。

     例如键入ls或cat命令则会引起虚拟文件系统对表示此文件系统的VFS inode的搜寻。由于系统中每个文件与目录都使用一个VFS

    inode来表示,所以许多inode会被重复访问。这些inode被保存在inode

    cache中以加快访问速度。如果某个inode不在inode cache中则必须调用一个文件系统相关例程来读取此inode。对这个inode

    的读将把此它放到inode cache中以备下一次访问。不经常使用的VFS inode将会从cache中移出。

     所有Linux文件系统使用一个通用buffer cache来缓冲来自底层设备的数据以便加速对包含此文件系统的物理 设备的存取。

     这个buffer

    cache与文件系统无关并被集成到Linux核心分配与读写数据缓存的机制中。让Linux文件系统独立于底层介质和设备驱动好处很多。所有的块结构设

    备将其自身注册到Linux核心中并提供基于块的一致性异步接口。象SCSI设备这种相对复杂的块设备也是如此。当实际文件系统从底层物理磁盘读取数据

    时,块设备驱动将从它们所控制的设备中读取物理块。buffer cache也被集成到了块设备接口中。

    当文件系统读取数据块时它们将被保存在由所有文件系统和Linux核心共享的全局buffer

    cache中。这些buffer由其块号和读取设备的设备号来表示。所以当某个数据块被频繁使用则它很可能能从buffer

    cache而不是磁盘中读取出来,后者显然将花费更长的时间。有些设备支持通过预测将下一次可能使用的数据提前读取出来。

    VFS还支持一种目录cache以便对经常使用的目录对应的inode进行快速查找。我们可以做一个这样的实验,首先我们对一个最近没有执行过列目录操作

    的目录进行列目录操作。第一次列目录时你可能发现会有较短的停顿但第二次操作时结果会立刻出现。目录cache不存储目录本身的inode;这些应该在

    inode cache中,目录cache 仅仅保存全目录名和其inode号之间的映射关系。

    

    9.2.1 VFS 超块

     每个已安装的文件系统由一个VFS超块表示;它包含如下信息:

    

    Device 表示文件系统所在块设备的设备标志符。例如系统中第一个IDE硬盘的设备标志符为0x301。 Inode pointers 这个mounted inode指针指向文件系统中第一个inode。而covered inode指针指向此文件系统安装目录的inode。根文件系统的VFS超块不包含covered指针。 Blocksize 以字节记数的文件系统块大小,如1024字节。 Superblock operations 指向此文件系统一组超块操纵例程的指针。这些例程被VFS用来读写inode和超块。 File System type 这是一个指向已安装文件系统的file_system_type结构的指针。 File System specific 指向文件系统所需信息的指针。

    

    9.2.2 The VFS Inode

     和EXT2文件系统相同,VFS中的每个文件、目录等都用且只用一个VFS inode表示。每个VFS

    inode中的信息通过文件系统相关例程从底层文件系统中得到。VFS inode仅存在于核心内存并且保存只要对系统有用,它们就会被保存在在VFS

    inode cache中。每个VFS inode包含下列域:

    

    device 包含此文件或此VFS inode代表的任何东西的设备的设备标志符。 inode number 文件系统中唯一的inode号。在虚拟文件系统中device和inode号的组合是唯一的。 mode 和EXT2中的相同, 表示此VFS inode的存取权限。 user ids 所有者的标志符。 times VFS inode 创建、修改和写入时间。 block size 以字节计算的文件块大小,如1024字节。 inode operations 指向一组例程地址的指针。这些例程和文件系统相关且对此inode执行操作,如截断此inode表示的文件。 count 使用此VFS inode的系统部件数。一个count为0的inode可以被自由的丢弃或重新使用。 lock 用来对某个VFS inode加锁,如用于读取文件系统时。 dirty 表示这个VFS inode是否已经被写过,如果是则底层文件系统需要更新。 file system specific information

    

    

    9.2.3 注册文件系统

    

    

    

    

     图9.5 已注册文件系统

    

    当重新建立Linux核心时安装程序会询问是否需要所有可支持的文件系统。核心重建时文件系统启动代码包含了所有那些编入核心的文件系统的初始化例程。

     Linux文件系统可构造成模块, 此时它们会仅在需要时加载或者使用insmod来载入。当文件系统模块被加载时,

    它将向核心注册并在卸载时撤除注册。每个文件系统的初始化例程还将向虚拟文件系统注册,它用一个包含文件系统名称和指向其VFS超块读例程的指针的

    file_system_type结构表示。每个file_system_type结构包含下列信息:

    

    Superblock read routine 此例程载文件系统的一个实例被安装时由VFS调用。 File System name 文件系统的名称如ext2。 Device needed 文件系统是否需要设备支持。并不是所有的文件系统都需要设备来保存它。例如/proc文件系统不需要块设备支持。

     你可以通过查阅/proc/filesystems可找出已注册的文件系统,如:

     ext2

    nodev proc

     iso9660

    

    9.2.4 安装文件系统

     当超级用户试图安装一个文件系统时,Linux核心首先使系统调用中的参数有效化。尽管mount程序会做一些基本的检查, 但是它并不知道核心构造时已经支持那些文件系统,同时那些建议的安装点的确存在。看如下的一个mount命令:

    $ mount -t iso9660 -o ro /dev/cdrom /mnt/cdrom

     mount命令将传递三个参数给核心:文件系统名,包含文件系统的物理块设备以及此新文件系统要安装到的已存在的目录名。

     虚拟文件系统首先必须做的是找到此文件系统。它将通过由链指针file_systems指向的file_system_type结 构来在所有已知文件系统中搜寻。

     如果找到了一个相匹配的文件系统名,那么它就知道核心支持此文件系统并可得到读取此文件系统超块相关例程的指针。如果找不到,但文件系统使用了可动态加载核心模块,则操作仍可继续。此时核心将请求核心后台进程加载相应的文件系统模块。

     接下来如果由mount传递的物理设备还没有安装, 则必须找到新文件系统将要安装到的那个目录的VFS inode。 这个VFS

    inode可能在inode

    cache中也可能在支撑这个安装点所在文件系统的块设备中。一旦找到这个inode则将对它进行检查以确定在此目录中是否已经安装了其它类型的文件系

    统。多个文件系统不能使用相同目录作为安装点。

     此时VFS安装代码必须分配一个VFS超块并将安装信息传递到此文件系统的超块读例程中。系统中所有的VFS

    超块都被保存在由super_block结构构成的super_blocks数组中, 并且对应此安装应有一个这种结构。超块读

    例程将基于这些从物理设备中读取的信息来填充这些VFS超块域。对于EXT2文件系统此信息的转化过程十分

    简便,仅需要读取EXT2超块并填充VFS超块。但其它文件系统如MS-DOS文件系统就不那么容易了。不管哪种文件系统,对VFS超块的填充意味着文件

    系统必须从支持它的块设备中读取描叙它的所有信息。如果块设备驱动不能从中读取或不包含这种类型文件系统则mount命令会失败。

    

    

    

    

     图9.6 一个已安装的文件系统

    

    每个文件系统用一个vfsmount结构来描叙。如图9.6所示。它们被排入由vfsmntlist指向的的链表中。

     另外一个指针:vfsmnttail指向链表的最后一个入口, 同时mru_vfsmnt指针指向最近使用最多的文件系统。

    每个vfsmount结构中由以下部分组成:包含此文件系统的块设备的设备号,此文件系统安装的目录以及文件

    系统安装时分配的VFS超块指针。VFS超块指向这种类型文件系统和此文件系统根inode的file_system_type结构。一旦此文件系统被加

    载, 这个inode将一直驻留在VFS inod cache中。

    

    9.2.5 在虚拟文件系统中搜寻文件

     为了在虚拟文件系统中找到某个文件的VFS inode,VFS必须依次解析此文件名字中的间接目录直到找到此VFS

    inode。每次目录查找包括一个对包含在表示父目录VFS inode中的查找函数的调用。由于我们总是让每个文件系统的根可用并且由此系统的VFS

    超块指向它,所以这是一个可行方案。每次在实际文件系统中寻找inode

    时,文件系统将在目录cache中寻找相应目录。如果在目录cache中无相应入口则文件系统必须从底层文件系统或inode

    cache中取得此VFS inode。

    

    9.2.6 Creating a File in the Virtual File System

    

    9.2.7 卸载文件系统

    如果已安装文件系统中有些文件还在被系统使用则不能卸载此文件系统。例如有进程使用/mnt/cdrom或其子目录时将不能卸载此文件系统。如果将要卸载

    的文件系统中有些文件还在被使用,那么在VFS inode cache中有与其对应的VFS

    inode。通过在inode链表中查找此文件系统占用设备的inode来完成此工作。对应此已安装文件系统的VFS超块为dirty,表示它已被修改过

    所以必须写回到磁盘的文件系统中。一旦写入磁盘,VFS超块占用的内存将归还到核心的空闲内存池中。最后对应的vfsmount结构将从

    vfsmntlist中释放。

    

    9.2.8 The VFS Inode Cache

     操纵已安装文件系统时,它们的VFS inode将被连续读写。虚拟文件系统通过维护一个inode cache来加速对所有已安装文件系统的访问。每次VFS inode都可从inode cache中读取出来以加速对物理设备的访问。

     VFS inode cache以散列表形式实现,其入口时指向具有相同散列值的VFS

    inode链表。每个inode的散列值可通过包含此文件系统的底层物理设备标志符和inode号计算出来。每当虚拟文件系统访问一个inode时,系统

    将首先在VFS inode

    cache中查找。为了在cache中寻找inode,系统先计算出其散列值然后将其作为inode散列表的索引。这样将得到指向一系列相同散列值的

    inode链表。然后依次读取每个inode直到找到那个具有相同inode号以及设备标志符的inode为止。

     如果在cache中找到了此inode则它的count值递增以表示用户增加了一个,同时文件操作将继续进行。否则必须找到一个空闲VFS

    inode以便文件系统能从内存中读取此inode。VFS有许多种选择来取得空闲inode。如果系统可以分配多个VFS

    inode则它将按如下步骤进行:首先分配核心页面并将其打碎成新的空闲inode并将其放入inode链表中。系统所有的VFS

    inode都被放到由first_inode指向的链表和inode散列表中。如果系统已经拥有所有inode,

    则它必须找到便于重新使用的inode。那些inode最好count记数为0;因为这种inode没有谁在使用。很重要的VFS

    inode,如文件系统的根inode,其count

    域总是大于0,所以它所使用的inode是不能被重新使用的。一旦找到可重用inode则应清除之: 其VFS

    inode可能为dirty,必须要写入到文件系统中或者需要加锁,此时系统必须等到解锁时才能继续运行。

     找到新的VFS inode后必须调用文件系统相关例程使用从底层实际文件系统中读出的内容填充它。在填充过程 中,此新VFS inode的count记数为1并被加锁以排斥其它进程对它的使用直到此inode包含有效信息为止。

     为了取得真正需要的VFS

    inode,文件系统可能需要存取几类其它inode。我们读取一个目录时虽然只需要最后一级目录但是所有的中间目录也被读了出来。由于使用了VFS

    inode cache,较少使用的inode将被丢弃而较多使用的inode将保存在cache中。

    

    9.2.9 目录 Cache

     为了加速对常用目录的访问,VFS维护着一个目录入口cache。

    当在实际文件系统寻找目录时,有关此目录的细节将被存入目录cache中。当再次寻找此目录时,例如在此目录中列文件名或打开文件,则这些信息就可以在目

    录cache中找到。在实际实现中只有短目录入口(最多15个字

    符)被缓存,这是因为那些较短目录名的目录正是使用最频繁的。例如/usr/X11R6/bin这个短目录经常被X server所使用。

    目录cache也由散列表组成,每个入口指向具有相同散列值的目录cache人口链表。散列函数使用包含此文件系统的设备号以及目录名称来计算在此散列表

    中的偏移值或者索引值, 这样能很快找到被缓存的目录。 如果在cache中的搜寻消耗的时间太长或者甚至没有找到则使用此cache用处不大。

    为了保证cache的有效性和及时更新,VFS保存着一个最近最少使用(LRU)的目录cache人口链表。当首次查找此目录时其目录入口被首次放入

    cache中并添加到第一级LRU链表的尾部。在已经充满的cache

    中它代替位于LRU链表最前端的现存入口。此目录入口被再次使用时它将被放到第二级LRU cache链表的最后。此时需要将位于第二级LRU

    cache链表的最前端的那个替换掉。入口在链表前端的唯一原因是它们已经很久没被访问过了。如果被访问过那么它们将位于此链表的尾部附近。位于第二级

    LRU cache链表中的入口要比位于第一级LRU cache链表中的安全一些。

    

    9.3 The Buffer Cache

    

    

    

    

     图9.7 Buffer Cache示意图

    

    操纵已安装文件系统将产生大量对此块设备的读写请求。这些块读写请求都是通过标准核心例程调用以buffer_head结构形式传递到设备

    驱动中。它们提供了设备驱动所需的所有信息:表示设备的设备标志符