linux的虚拟文件系统VFS

时间:2021-02-08 05:14:04

    虚拟文件系统(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 {

     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 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 {

         struct inode *(*alloc_inode)( struct super_block *sb);
         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 *,  intchar *, size_t, loff_t);
        ssize_t (*quota_write)( struct super_block *,  intconst  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