虚拟文件系统(virtual file system),别名虚拟文件系统开关,是linux中的一个软件层,向用户空间提供文件系统操作接口。
VFS包含的系统调用包括open(2)、stat(2)、read(2)、write(2)、chmod(2)等等,这些系统调用在进程环境中执行。下面几个重要的数据结构是VFS(虚拟文件系统中涉及到的数据结构):
1、Directory Entry Cache(dcache)
VFS实现了系统调用open(2)、stat(2)、chmod(2),和其他类似的文件系统调用。用于这些系统调用中的参数被VFS用来进行directory entry cache的对象搜索,其中directory entry cache有多个名字,比如dentry cache或者dcache。 通过dentry cache提供了一种快速查找机制,可以快速的根据路径名字找到具体的dentry。需要特别说明的是:dentry是存在于内存中的,不会保存到磁盘上进行永久性存储的。
2、inode 对象
每一个dentry对象都有一个指针指向具体的inode对象。inode是文件系统的对象,比如正规文件(regular file)、目录(directory)、FIFO(管道)。这些inode对象存在于磁盘(块设备文件文件系统)或者内存(linux下的伪文件系统procfs)。如果是存在于磁盘上的inode对象则需要加载到内存中去,当发生的改变需要保存到磁盘上去。一个inode对象可能有多个dentry对象指向它(因为linux下实现了硬连接特性)。
为了查找一个具体的inode对象需要在父目录的inode上执行lookup操作。而具体的lookup方法是由inode存放的文件系统具体的实现,这个操作是由具体的文件系统进行初始化。一旦VFS拥有具体的dentry对象的时候,很多系统调用就可以迅速完成,比如stat(2)系统调用,它就是获取inode上的数据,根据dentry上的指针可以迅速的找到inode对象。
3、File对象
打开一个文件还需要另外一个操作:分配一个File结构的对象(这是linux内核端的文件描述符的实现)。新申请的File对象初始化了一个指针指向dentry对象和多个文件操作函数(比如read、write、mmap等操作)。File数据结构放在这个进程的文件描述表中(file descriptor table)。
用户空间的read、write等操作都是通过用户空间态(userspace file descriptor)的描述符获得正确的File结构,然后调用File结构中的具体的方法。只要文件处于打开状态,linux内核中就有对应的dentry对象,自然也有对象的inode对象。
4、文件系统对象(filesystem)
登记和卸载一个文件系统使用下面的函数调用。
#include <linux/fs.h>
extern int register_filesystem( struct file_system_type *);
extern int unregister_filesystem(struct file_system_type *);
传入的参数struct file_system_type描述了具体的文件系统。当发出一个命令,需要在你的名字空间的一个目录上挂载一个文件系统的时候,VFS会调用具体文件中的mount方法。当mount操作完成之后,会返回一个struct dentry对象,这个时候会新建一个vfsmount对象,用于指向这个dentry对象,同时这个vfsmount对象会添加到这个挂载点上。所以当路径解析到达这个目录的时候,会跳转到这个vfsmount指向的文件系统中去。
在/proc/filesystems下可以观察到所有挂载的文件系统。
以下是file_system_type结构:
struct file_system_type {
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 list_head fs_supers;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
};
name:文件系统的名字,当前支持的文件名字有“ext2”,“ext3”,“ext4”,“msdos”等
fs_flags:一些标志,比如:FS_REQUIRES_DEV, FS_NO_DCACHE
mount:重要的field,当一个filesystem实例化的时候需要具体的filesystem的mount方法
5、superblock对象
一个superblock(超级块)对象代表了一个挂载的文件系统。
下面是关于超级块的操作的数据结构:
struct super_operations {
void (*destroy_inode)( struct inode *);
void (*dirty_inode) ( struct inode *, int flags);
int (*write_inode) ( struct inode *, int);
void (*drop_inode) ( struct inode *);
void (*delete_inode) ( struct inode *);
void (*put_super) ( struct super_block *);
int (*sync_fs)( struct super_block *sb, int wait);
int (*freeze_fs) ( struct super_block *);
int (*unfreeze_fs) ( struct super_block *);
int (*statfs) ( struct dentry *, struct kstatfs *);
int (*remount_fs) ( struct super_block *, int *, char *);
void (*clear_inode) ( struct inode *);
void (*umount_begin) ( struct super_block *);
int (*show_options)( struct seq_file *, struct dentry *);
ssize_t (*quota_read)( struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)( struct super_block *, int, const char *, size_t, loff_t);
int (*nr_cached_objects)( struct super_block *);
void (*free_cached_objects)( struct super_block *, int);
};
所有的方法都没有lock来维持,这说明了这些方法只可以在一个进程上下文中执行,不能在中断上下文中执行。
6、address space对象
address_space对象用于对page cache中的page进行分组和管理。它可以用来跟踪一个文件中的page cache和一个文件中映射到进程地址空间中的文件区域。
address space提供了大量有显著特征的服务,比如根据通过地址查找page,追踪标志为Dirty或者WriteBack的page。
Further Reading:
1.Creating Linux virtual filesystems. 2002. http://lwn.net/Articles/13325/
2.A tour of the Linux VFS by Michael K. Johnson. 1996. http://www.tldp.org/LDP/khg/HyperNews/get/fs/vfstour.html