欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

虚拟文件系统

程序员文章站 2022-03-09 11:27:48
...

虚拟文件系统


虚拟文件系统(VFS)是内核子系统, 作为用户空间的文件与文件系统相关的接口.

一个写操作 ret = write(fd, buf, len)

  1. write函数系统调用sys_write()函数处理.
  2. sys_write函数找到fd实际写入的是哪一个文件系统的文件
  3. 然后通过write写入VFS介质中.
  4. 最后VFS将写入介质的数据再写回所对应文件系统的文件.

一方面, 系统调用是通过VFS接口, 提供给用户空间的前端; 另一方面, VFS将具体文件系统的操作给了后端.

VFS 就是文件操作的中转站(介质), 表面看上去文件操作都是统一的, 其实文件是属于不同的文件系统, 只是通过VFS“转”成统一的.

linux对ext文件系统族的支持是最好的,因为VFS抽象层的组织与ext文件系统类似,这样在处理Ext文件系统时可以提高性能,因为在Ext和VFS之间转换几乎不会损失时间. 同样linux的文件系统也是ext.


索引节点(inode)

索引节点 : 记录文件相关信息(元数据).包含了内核操作的文件或目录的全部信息.

索引节点只有文件名和文件索引号没有记录. 而是把两个信息放在目录中, 通过文件名在目录中找到相应的索引号, 后续文件访问就直接使用索引号来标记文件了.

那索引节点与VFS有什么关系呢?

因为有些文件系统是不具备inode结构的, 需要通过VFS将文件系统统一成一个结构, 所以文件系统中的文件也就都会统一具备了 inode结构.

为什么索引节点信息不包含文件名称?

索引节点会储存对于其自身唯一的信息。对于一个硬链接,一个索引节点可能会含有指向同一索引节点的两个不同的文件名. 并且在修改文件名时, 改变也就是仅仅是文件名, 索引号不会改变, 索引节点也不会改变.

在移动文件时索引节点会发生变化吗?

即使将文件从一处移动到另一处,索引节点号码还是会保持不变,但前提是在同一文件系统之下。如果在不同的文件系统之间移动,索引节点号码就会发生变化。

关于inode结构

struct inode {  
    /* 全局的散列表 */  
    struct hlist_node   i_hash;  
    /* 根据inode的状态可能处理不同的链表中(inode_unused/inode_in_use/super_block->dirty) */  
    struct list_head    i_list;  
    /* super_block->s_inodes链表的节点 */  
    struct list_head    i_sb_list;  
    /* inode对应的dentry链表,可能多个dentry指向同一个文件 */  
    struct list_head    i_dentry;  
    /* inode编号 */  
    unsigned long       i_ino;  
    /* 访问该inode的进程数目 */  
    atomic_t        i_count;  
    /* inode的硬链接数 */  
    unsigned int    i_nlink;  
    uid_t           i_uid;  
    gid_t           i_gid;  
    /* inode表示设备文件时的设备号 */  
    dev_t           i_rdev;  
    u64         i_version;  
    /* 文件的大小,以字节为单位 */  
    loff_t          i_size;  
    /* 最后访问时间 */  
    struct timespec     i_atime;  
    /* 最后修改inode数据的时间 */  
    struct timespec     i_mtime;  
    /* 最后修改inode自身的时间 */  
    struct timespec     i_ctime;  
    umode_t         i_mode;  
    spinlock_t      i_lock; 
    struct mutex        i_mutex;  
    struct rw_semaphore i_alloc_sem;  
    /*inode 信号量*/
    struct semaphore i_sem;
    /* inode操作表 */  
    const struct inode_operations   *i_op;  
    /* file操作 */  
    const struct file_operations    *i_fop;  
    /* inode所属的super_block */  
    struct super_block  *i_sb;  
    struct file_lock    *i_flock;  
    /* inode的地址空间映射 */  
    struct address_space    *i_mapping;  
    struct address_space    i_data;  
};

索引节点是保存在一个slab缓存中的inode_cache中, 提供inode的快速分配和释放的.


目录项

在Linux操作系统中,目录就是目录文件。

一个目录文件包含了一组目录项,目录项是放在data block中的.一个目录项主要包括了文件名和索引节点号,索引节点号是指向索引节点表中对应的索引节点的。

目录项对象没有对应的磁盘数据结构, 所以他并非是保存在磁盘上, 而是VFS根据字符串形式的路径名来创建他们, 目录项具体是存放在dcache中. 当你对文件的访问的时侯, VFS会先在dcache中查找, 没有找到的时侯就解析路径, 然后将该目录项加入到dcache中, 以便之后能快速的访问. 同样, 目录项中包含的索引节点也加入到了icache缓存中

目录项结构

struct dentry {  
    atomic_t d_count;  
    unsigned int d_flags;     
    spinlock_t d_lock;      
    /* 该dentry是否是一个装载点 */  
    int d_mounted;  
    /* 文件所属的inode */  
    struct inode *d_inode;  
    /* 全局的dentry散列表 */  
    struct hlist_node d_hash;   
    /* 父目录的dentry */  
    struct dentry *d_parent;   
    /* 文件的名称,例如对/tmp/a.sh,文件名即为a.sh */  
    struct qstr d_name;  
    /* 脏的dentry链表的节点 */  
    struct list_head d_lru;    

    union {  
        struct list_head d_child;  
        struct rcu_head d_rcu;  
    } d_u;  
    /* 该dentry子目录中的dentry的节点链表 */  
    struct list_head d_subdirs;
    /* 硬链接使用几个不同名称表示同一个文件时,用于连接各个dentry */  
    struct list_head d_alias;   
    unsigned long d_time;      
    const struct dentry_operations *d_op;  
    /* 所属的super_block */  
    struct super_block *d_sb;  
    void *d_fsdata;        
    /* 如果文件名由少量字符组成,在保存在这里,加速访问 */  
    unsigned char d_iname[DNAME_INLINE_LEN_MIN];  
};  

目录项也通过散列来快速的进行相关目录项的解析.


超级块

超级块代表一个已经安装的文件系统,用于存储文件系统的控制信息,例如文件系统类型、大小、所有inode对象、脏的inode链表等.

超级块结构

struct super_block {  
    /* 全局链表元素 */  
    struct list_head    s_list;  
    /* 底层文件系统所在的设备 */  
    dev_t           s_dev;  
    /* 文件系统中每一块的长度 */  
    unsigned long       s_blocksize;  
    /* 文件系统中每一块的长度(以2为底的对数) */  
    unsigned char       s_blocksize_bits;  
    /* 是否需要向磁盘回写 */  
    unsigned char       s_dirt;  
    unsigned long long  s_maxbytes; 
    /*脏数据链表*/
    struct list_head s_dirty;
    /*写回链表*/
    struct list_head s_io;
    /* 文件系统类型 */  
    struct file_system_type *s_type;  
    /* 超级块操作方法 */  
    const struct super_operations   *s_op;  
    struct dquot_operations *dq_op;  
    struct quotactl_ops *s_qcop;  
    const struct export_operations *s_export_op;  
    unsigned long       s_flags;  
    unsigned long       s_magic;  
    /* 全局根目录的dentry */  
    struct dentry       *s_root;  
    struct rw_semaphore s_umount;  
    struct mutex        s_lock;  
};

超级块是通过alloc_super()函数进行初始化的.


总结

目录项, 索引节点, 超级块的关系(google图片中找到的)

虚拟文件系统