Vfs文件系统详解
前言:
本文基于linux kernel 3.14.17来讨论VFS机制,以及内核对VFS的支持,试图从源代码的角度来理解,所以在阅读本文之前需要读者对linuxVFS的基本的数据结构有所了解,(super_block、inode、dentry、vfsmount等)。
一、VFS的概念
VFS是Linux中的一个虚拟文件文件系统,也称为虚拟文件系统交换层(Virtual Filesystem Switch)。它为应用程序员提供一层抽象,屏蔽底层各种文件系统的差异。如下图所示:
不同的文件系统,如Ext2/3、XFS、FAT32等,具有不同的结构,假如用户调用open等文件IO函数去打开文件,具体的实现会非常不同。为了屏蔽这种差异,Linux引入了VFS的概念。相当于是Linux自建了一个新的贮存在内存中的文件系统。所有其他文件系统都需要先转换成VFS的结构才能为用户所调用。
二、VFS 概述
VFS 是一种软件机制,也许称它为 Linux 的文件系统管理者更确切点,与它相关的数据结构只存在于物理内存当中。所以在每次系统初始化期间,Linux 都首先要在内存当中构造一棵 VFS 的目录树(在 Linux 的源代码里称之为 namespace),实际上便是在内存中建立相应的数据结构。VFS 目录树在 Linux 的文件系统模块中是个很重要的概念,希望读者不要将其与实际文件系统目录树混淆,在笔者看来,VFS 中的各目录其主要用途是用来提供实际文件系统的挂载点,当然在 VFS 中也会涉及到文件级的操作,本文不阐述这种情况。下文提到目录树或目录,如果不特别说明,均指 VFS 的目录树或目录。图 1 是一种可能的目录树在内存中的影像:
图 1:VFS 目录树结构
三、rootfs目录树的建立
在众多的实际文件系统中,之所以单独介绍 rootfs 文件系统的注册过程,实在是因为该文件系统 VFS 的关系太过密切,如果说 ext2/ext3 是 Linux 的本土文件系统,那么 rootfs 文件系统则是 VFS 存在的基础。
1、文件系统的注册
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type ** p;
BUG_ON(strchr(fs->name, '.'));
if (fs->next)
return -EBUSY;
write_lock(&file_systems_lock);
p = find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
*p = fs;
write_unlock(&file_systems_lock);
return res;
}
static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
struct file_system_type **p;
for (p=&file_systems; *p; p=&(*p)->next)
if (strlen((*p)->name) == len &&
strncmp((*p)->name, name, len) == 0)
break;
return p;
}
注册过程实际上将表示各实际文件系统的
struct file_system_type
数据结构的实例化,然后形成一个链表,内核中用一个名为
file_systems
的全局变量来指向该链表的表头。
2、文件系统的挂载
本节阐述 Linux 在初始化阶段是如何建立根结点的,即 "/"目录。这其中会包括挂载 rootfs 文件系统到根目录 "/" 的具体过程。构造根目录的代码是在 init_mount_tree() 函数 (fs\namespace.c) 中。
文件系统类型
struct file_system_type {
const char *name;
int fs_flags;
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct hlist_head fs_supers;
};
这里只截取了关键的成员变量
图:文件系统挂载流程
内核通过sys_mount来挂载文件系统,其中关键函数是vfs_kern_mount()和graft_tree(),前者申请了一个挂载示例vfsmount,并调用要挂载的文件系统的mount()函数来申请对应的超级块、dentry和inode节点填充必要的字段和文件系统信息。下面我们以rootfs的挂载来详细阐述这一过程。
graft_tree() 函数要做的事情便是将 do_kern_mount() 函数返回的一