当进程准备写某文件时, 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指针。
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!



