在文件系统方面,®可以算得上操作系统中的“瑞士军刀”。支持许多种文件系统,从日志型文件系统到集群文件系统和加密文件系统。对于使用标准的和比较独特的文件系统以及开发文件系统来说,Linux是极好的平台。本文讨论Linux内核中的虚拟文件系统(VFS,有时侯称为虚拟文件系统交换器),之后介绍将文件系统联接在一起的主要结构。
基本的文件系统体系结构
Linux文件系统体系结构是一个对复杂系统进行具象化的有趣事例。通过使用一组通用的API函数,Linux可以在许多种储存设备上支持许多种文件系统。诸如,read函数调用可以从指定的文件描述符读取一定数目的字节。read函数不了解文件系统的类型,例如ext3或NFS。它也不了解文件系统所在的储存媒体,例如ATAttachmentPacketInterface(ATAPI)c盘、Serial-AttachedSCSI(SAS)c盘或SerialAdvancedTechnologyAttachment(SATA)c盘。并且,当通过调用read函数读取一个文件时,数据会正常返回。本文讲解这个机制的实现方式并介绍Linux文件系统层的主要结构。
哪些是文件系统?
首先回答最常见的问题,“什么是文件系统”。文件系统是对一个储存设备上的数据和元数据进行组织的机制。因为定义这么笼统,支持它的代码会很有意思。正如上面提及的,有许多种文件系统和媒体。因为存在如此多类型,可以预想到Linux文件系统插口实现为分层的体系结构,进而将用户插口层、文件系统实现和操作储存设备的驱动程序分隔开。
挂装
在Linux上将一个文件系统与一个储存设备关联上去的过程称为挂装(mount)。使用mount命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。
为了说明Linux文件系统层的功能(以及挂装的方式),我们在当前文件系统的一个文件中创建一个文件系统。实现的方式是,首先用dd命令创建一个指定大小的文件(使用/dev/zero作为源进行文件复制)——换句话说,一个用零进行初始化的文件,见清单1。
清单1.创建一个经过初始化的文件
$ddif=/dev/zerof=file.imgbs=1kcount=10000
10000+0recordsin
10000+0recordsout
如今有了一个10MB的file.img文件。使用losetup命令将一个循环设备与这个文件关联上去,让它看上去像一个块设备,而不是文件系统中的常规文件:
$losetup/dev/loop0file.img
这个文件现今作为一个块设备出现(由/dev/loop0表示)。之后用mke2fs在这个设备上创建一个文件系统。这个命令创建一个指定大小的新的ext2文件系统,见清单2。
清单2.用循环设备创建ext2文件系统
$mke2fs-c/dev/loop010000
mke2fs1.35(28-Feb-2004)
max_blocks1024000,rsv_groups=1250,rsv_gdb=39
Filesystemlabel=
OStype:Linux
Blocksize=1024(log=0)
Fragmentsize=1024(log=0)
2512inodes,10000blocks
500blocks(5.00%)reservedforthesuperuser
...
使用mount命令将循环设备(/dev/loop0)所表示的file.img文件挂装到挂装点/mnt/point1。注意,文件系统类型指定为ext2。挂装以后,就可以将这个挂装点当成一个新的文件系统,例如使用ls命令,见清单3。
清单3.创建挂装点并通过循环设备挂装文件系统
$mkdir/mnt/point1
$mount-text2/dev/loop0/mnt/point1
$ls/mnt/point1
lost+found
如清单4所示linux 输入法,还可以继续这个过程:在昨天挂装的文件系统中创建一个新文件,将它与一个循环设备关联上去,再在里面创建另一个文件系统。
清单4.在循环文件系统中创建一个新的循环文件系统
$ddif=/dev/zerof=/mnt/point1/file.imgbs=1kcount=1000
1000+0recordsin
1000+0recordsout
$losetup/dev/loop1/mnt/point1/file.img
$mke2fs-c/dev/loop11000
mke2fs1.35(28-Feb-2004)
max_blocks1024000,rsv_groups=125,rsv_gdb=3
Filesystemlabel=
...
$mkdir/mnt/point2
$mount-text2/dev/loop1/mnt/point2
$ls/mnt/point2
lost+found
$ls/mnt/point1
file.imglost+found
通过这个简单的演示很容易感受到Linux文件系统(和循环设备)是多么强悍。可以根据相同的方式在文件上用循环设备创建加密的文件系统。可以在须要时使用循环设备临时挂装文件,这有助于保护数据。详尽的技术请登陆飞客数据恢复中心的网站,里面有好多有关Linux文件系统方面的知识以及有关的Linux文件系统ext2或ext3方面的数据恢复技术文章。飞客北京数据恢复中心研制部提升这方面的免费电话咨询。
文件系统体系结构
既然早已听到了文件系统的构造方式,如今就瞧瞧Linux文件系统层的体系结构。本文从两个角度考察Linux文件系统。首先采用高层体系结构的角度。之后进行深层次讨论,介绍实现文件系统层的主要结构。
高层体系结构
虽然大多数文件系统代码在内核中(前面讨论的用户空间文件系统除外),而且图1所示的体系结构显示了用户空间和内核中与文件系统相关的主要组件之间的关系。
用户空间包含一些应用程序(比如,文件系统的使用者)和GNUC库(glibc),它们为文件系统调用(打开、读取、写和关掉)提供用户插口。系统调用插口的作用如同是交换器,它将系统调用从用户空间发送到内核空间中的适当端点。
VFS是底层文件系统的主要插口。这个组件导入一组插口,之后将它们具象到各个文件系统,各个文件系统的行为可能差别很大。有两个针对文件系统对象的缓存(inode和dentry)。它们缓存近来使用过的文件系统对象。
每位文件系统实现(例如ext2、JFS等等)导入一组通用插口,供VFS使用。缓冲区缓存会缓存文件系统和相关块设备之间的恳求。诸如,对底层设备驱动程序的读写恳求会通过缓冲区缓存来传递。这就容许在其中缓存恳求,降低访问数学设备的次数,推动访问速率。以近来使用(LRU)列表的方式管理缓冲区缓存。注意,可以使用sync命令将缓冲区缓存中的恳求发送到储存媒体(促使所有未写的数据发送到设备驱动程序,从而发送到储存设备)。
这就是VFS和文件系统组件的高层情况。现今,讨论实现这个子系统的主要结构。
主要结构
Linux以一组通用对象的角度看待所有文件系统。这种对象是超级块(superblock)、inode、dentry和文件。超级块在每位文件系统的根上linux文件描述符linux文件描述符,超级块描述和维护文件系统的状态。文件系统中管理的每位对象(文件或目录)在Linux中表示为一个inode。inode包含管理文件系统中的对象所需的所有元数据(包括可以在对象上执行的操作)。另一组结构称为dentry,它们拿来实现名称和inode之间的映射linux查看操作系统,有一个目录缓存拿来保存近来使用的dentry。dentry还维护目录和文件之间的关系,因而支持在文件系统中联通。最后,VFS文件表示一个打开的文件(保存打开的文件的状态,例如写偏斜量等等)。
虚拟文件系统层
VFS作为文件系统插口的根层。VFS记录当前支持的文件系统以及当前挂装的文件系统。
可以使用一组注册函数在Linux中动态地添加或删掉文件系统。内核保存当前支持的文件系统的列表,可以通过/proc文件系统在用户空间中查看这个列表。这个虚拟文件还显示当前与那些文件系统相关联的设备。在Linux中添加新文件系统的方式是调用register_filesystem。这个函数的参数定义一个文件系统结构(file_system_type)的引用,这个结构定义文件系统的名称、一组属性和两个超级块函数。也可以注销文件系统。
在注册新的文件系统时,会把这个文件系统和它的相关信息添加到file_systems列表中(见图2和linux/include/linux/mount.h)。这个列表定义可以支持的文件系统。在命令行上输入cat/proc/filesystems,就可以查看这个列表。a