标题：虚拟文件系统
虚拟文件系统简介
虚拟文件系统 Virtual File Systems（VFS）
Linux 是近年来发展起来的一种新型的操作系统，其最重要的特征之一就是支持多种文件系统，使其更加灵活，从而与许多其它的操作系统共存。Linux支持ext，ext2，xia，minix，umsdos，msdes，fat32 ，ntfs,proc，stub，ncp，hpfs，affs 以及 ufs 等多种文件系统。为了实现这一目的，Linux 对所有的文件系统采用统一的文件界面，用户通过文件的操作界面来实现对不同文件系统的操作。对于用户来说，我们不要去关心不同文件系统的具体操作过程，而只是对一个虚拟的文件操作界面来进行操作，这个操作界面就是 Linux 的虚拟文件系统(VFS ) 。形象地说，Linux 的内核好象一个 PC 机的母板，VFS 就是上面的一个插槽，具体的文件系统就是一块块的接 121 卡。因此，每一个文件系统之间互不干扰，而只是调用相应的程序来实现其功能。在 Linux 的内核文件中，VFS 和具体的文件系统程序都放在 Linux\FS 中，其中每一种文件系统对应一个子目录，另外还有一些共用的 VFS 程序。在具体的实现上，每个文件系统都有自己的文件操作数据结构 file—operations。所以，VFS 作为 ILinux 内核中的一个软件层，用于给用户空间的程序提供文件系统接口，同时也提供了内核中的一个抽象功能，允许不同的文件系统很好地共存。VFS 使 Linux 同时安装、支持许多不同类型的文件系统成为可能。VFS 拥有关于各种特殊文件系统的公共界面，如超级块、inode、文件操作函数入口等。实际文件系统的细节，统一由 VFS 的公共界面来索引，它们对系统核心和用户进程来说是透明的。
虚拟文件系统功能
VFS的功能包括：纪录可用的文件系统的类型；将设备同对应的文件系统联系起来；处理一些面向文件的通用操作；涉及到针对文件系统的操作时，VFS把它们影射到与控制文件、目录以及inode相关的物理文件系统。
当某个进程发布了一个面向文件的系统调用时，核心将调用VFS中相应的函数，这个函数处理一些与物理结构无关的操作，并且把它重定向为真实文件系统中相应的函数调用，后者则用来处理那些与物理结构相关的操作。
VFS与实际文件系统的封装关系如下图所示：
VFS
MINIX FS
VFSinode缓存
VFS目录缓存
EXT FS
EXT2 FS
MSDS FS
缓冲存储
I/O设备驱动
图4 VFS与实际文件系统的封装关系
VFS的源代码集中在/usr/src/linux/fs目录下，关于它的数据结构的描述在文件/usr/src/lunux/include/linux/fs.h中。
虚拟文件系统超级块
VFS使用了与EXT2文件系统类似的方式：超级块和索引节点inode描述文件系统。
VFS超级块是各种逻辑文件系统在安装时建立的，并在这些文件系统卸载时自动删除，它只存在于内存中。VFS中保存了系统中挂接的文件系统的链表以及这些文件系统对应的VFS超级块。系统启动后所有被初始化的文件系统都要向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：指向文件系统所需信息的指针。
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是否已经被写过，如果是则底层文件系统需要更新。
注册文件系统
用户可以通过两种途径向内核注册文件系统：一是在编译内核时确定可支持的文件系统类型，并在系统初始化时通过内嵌的函数调用在VFS中进行注册；二是把某个文件系统当作一个模块，利用模块的加载和卸载特征向注册表登记类型或从注册表注销。
文件系统类型的注册函数为：int register filesystem (struct file_system_type *fs)
每个文件系统都有一个初始化例程，文件系统通过它在VFS中进行注册，即填写file_system_type数据结构。该结构包含了文件系统的名称及一个指向对应VFS超级块读取例程的地址。所有已注册文件系统的file_system_type结构形成了一个注册链表，如下图所示：
file_system_type file_system_type file_system_type 
*read_super()
name
owner
kem_mnt
next
*read_super()
name
owner
kem_mnt
next
*read_super()
name
owner
kem_mnt
next
图5
file_system_type的数据结构在include/linux/fs.h中定义如下：
struct file_system_type {
const char *name;
//文件系统的类型名，如EXT2。这些名称出现在Linux中的/proc/filesystems中且必须是唯一的。
int fs_flags;
//fs_flags的取值可能有很多种。例如，文件系统标识FS_REQUIRES_DEV表示文件系统只能加载在一个块设备上；FS_SINGLE表示文件系统只能有一个超级块；FS_NOMOUNT表示文件系统不能安装在用户空间上。
struct super_block *(*read_super) (struct super_block *, void *, int);
//read_super所指的函数用于读出该文件系统在外存的超级块。
struct module *owner;
//如果实现该文件系统的程序段是由module动态载入的，则指向该module；如果实现该文件系统的程序段是在内核编译时生成的，则owner = NULL。
struct vfsmount * kem_mnt;
//只为标识为FS_SINGLE的文件系统使用(For kernel mount)
struct file_system_type * next;
//文件系统类型链表的后续指针。
};
安装文件系统
文件系统注册后便在设备上按一定格式建立文件系统，但是此时设备上的文件和节点都还不是可访问的，还不能按照一定的路径名访问其中特定的节点或文件。只有把它安装到文件系统中某个节点上，才能使设备上的文件和节点可被访问。因此注册了wej系统只代表Linux系统支持这种文件系统的应用，要真正使用该文件系统还必须安装它。
文件系统的安装必须调用mount命令，把其他子系统安装到已经存在于文件系统的空闲节点上。该命令使用系统的mount()调用：asmlinkage ling sys_mount(char * dev_name, char * dir_name, char * type, unsigned long flags, void * data)
其中dev_name是要安装的文件系统的磁盘分区的路径名，如/dev/hda5。参数dir_name是要安装的文件系统的目录名；type指定磁盘分区上的文件系统类型；flags指定该文件系统如何被安装；data是指向任意的信息结构的指针，其内容依赖于被安装的特定文件系统类型。
使用mount命令后，VFS通过file_systems在file_system_type链表中根据指定的文件系统名称搜索文件系统类型信息。而函数get_fs_type()根据具体文件系统的类型名在内核中找到相应的file_system_type结构:
struct file_system_type *get_fs_type(const char *name)
{
struct file_system_type *fs;
read_lock(&file_systems_lock);
fs = *(find_filesystem(name));
if (!fs && (request_module(name) == 0)) {
read_lock(&file_systems_lock);
fs = *(find_filesystem(name));
if (fs && !try_inc_mod_count(fs->owner))
fs = NULL;
read_unlock(&file_systems_lock);
}
return fs;
}
其中函数find_filesystem(name)扫描file_system对列，找到所需文件系统类型的数据结构。
卸载文件系统
超级用户卸载文件系统使用umount命令。
卸载过程必须检查文件系统及其超级块的状态。如果文件系统正被其他进程使用该文件系统就不能被卸载。如果文件系统的文件或目录正在使用，则VFS索引节点缓存中可能包含相应的VFS索引节点。检查代码在该缓存中，根据文件系统所在的设备标识符查找是否有来自该文件系统的VFS索引节点。如果有且使用计数大于0则说明该文件系统正在使用，不能被删除。如果文件系统的超级块为“脏”，即被修改，则应先将它写回到磁盘上。
文件系统允许在被删除后，对应的VFS超级块被释放，vfsmount数据结构从vfsmntlist链表中断开并被释放。