分类: LINUX
2011-10-05 19:05:28
Linux文件系统浅析
作者:TP 撰写日期:2011-09-20 ~ 2011-09-25
自从上次面试中被问及设计一个文件系统的问题后,我就一直纠结中。文件到底有着什么样的数据结构去表现它们? 我们的操作系统是怎么去管理他们? 前辈大侠们设计文件系统的过程中有些什么样的思考,它又是怎么一步步的演变成今天这样一个稳定而伸缩性强的体系结构的。
在查看一段时间的资料后,对于文件系统终于有了自己的一小点了解。在这里写出分享一下,还请大家不吝赐教。
Linux 支持许多种文件系统,从ext2,ext3到ntfs等等。但本文讨论 Linux 内核中的虚拟文件系统(VFS,有时候称为虚拟文件系统交换器),并介绍将文件系统连接在一起的主要结构。
1.什么是文件系统
文件系统是操作系统在计算机硬盘上存储和检索数据的逻辑方法,从本质上讲是特殊的数据分层存储结构,它包含文件、目录和相关的控制信息。
图 1.
图 1 所示的体系结构显示了用户空间和内核中与文件系统相关的主要组件之间的关系。VFS 是底层文件系统的主要接口。这个组件导出一组接口,然后将它们抽象到各个文件系统,各个文件系统的行为可能差异很大。有两个针对文件系统对象的缓存(inode 和 dentry)。它们缓存最近使用过的文件系统对象。在这里缓冲区缓存和设备驱动的交互、以及VFS提供的系统接口暂不讨论,主要看看实现这个VFS子系统的主要结构。
2.文件系统的主要结构
VFS中主要有四个主要的对象类型,这些对象是超级块(superblock)、索引节点inode、目录项dentry 和文件。超级块代表这一个已经安装的文件系统,索引节点代表着文件系统中的一个文件。另一组结构称为 dentry,它们用来实现名称和 inode 之间的映射,有一个目录缓存用来保存最近使用的 dentry。dentry 还维护目录和文件之间的关系,从而支持在文件系统中移动。最后,VFS 文件表示一个打开的文件(保存打开的文件的状态,比如写偏移量等等)。他们四者的关系可见图2:
图2.
从图2我们可以看到,超级块在每个文件系统的根上,超级块描述和维护文件系统的状态。文件系统中管理的每个对象(文件或目录)在 Linux 中表示为一个 inode。而dentry是路径的是指向inode的,它表现的是文件名称和inode的映射,同时,不同的文件名称可以映射到形同的inode。下面分别对这几个对象做一下简单的解释:
a.目录项对象 dentry: dentry的中文名称是目录项,是Linux文件系统中某个索引节点(inode)的链接。这个索引节点可以是文件,也可以是目录。为了方便查找操作,虚拟文件系统引入的目录项的概念。每个dentry代表路径中的一个特定部分。对路径/bin/vi来说,bin和vi都属于目录对象。前两个是目录,最后一个是普通文件。又由于解析一个路径并走查其分量是一个字符串比较的过程,也是一个耗时的过程,文件系统会引入目录缓存技术用于事先加载部分目录到内存中。以下是dentry的结构体:
点击(此处)折叠或打开
在该结构体中,对以下几个成员做一下说明,因为他们构成了目录项的框架。
d_inode:它直接记录了这个名称有关的索引节点的指针。
d_parent:指向父亲dentry
d_hash:散列表,同过他可以快速的将给定路径解析为相关的目录项对象
d_child:父目录中目录项对象的链表
d_ subdirs:子目录
.索引节点对象inode:一个索引节点代表系统中的一个文件,它包含了内核在操作文件安或目录需要的所有信息。由于索引节点的数据结构比较庞大,这里暂时对几个主要的成员做解释:
点击(此处)折叠或打开
i_hash: Linux保留了活动索引节点以及最近使用索引节点的缓存。可以通过两种突击访问这些节点。第一种途径是通过dcache。第二种途径是通过索引节点散列表。每个索引节点都根据文件系统超级块的地址和索引节点号码创建一个8位数字的散列。然后,具有相同散列值的信息节点在一个双重链接的列表中链接起来。这里的ihash就是指这个散列表。
i_list: i_lish链接列表以不同的状态链接信息节点。包括:inode_in_use列表, inode_unused等。
i_dentry: identry列表是引用这个信息节点的所有dentry结构的列表。即不同的文件名称或则路径映射到了同一个文件。
c.超级块对象super_bolck:超级块结构表示一个文件系统。它包含管理文件系统所需的信息,包括文件系统名称(比如 ext2)、文件系统的大小和状态、块设备的引用和元数据信息(比如空闲列表等等)。超级块通常存储在存储媒体上,但是如果超级块不存在,也可以实时创建它。超级块的数据结构在linux/fs.h中。创建、管理和销毁超级块对象的代码在文件fs/super.c中。超级块对象通过alloc_super()函数创建并初始化。在文件系统安装时,内核会调用该函数以便从磁盘读取文件系统超级块,并且讲其信息填充到内存中的超级块对象中。
不管怎样,虽然对linux文件系统的了解对现有工作没有直接的关系。但我觉得它是一个可伸缩和可扩展的体系结构的绝对经典实例。如果把Linux内核比作是程序员的经典源代码名著,文件系统结构绝对是不容错过的章节。
参考文献:《linux内核设计与实现》、《linux文件系统》