虚拟文件系统

虚拟文件系统


虚拟文件系统(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图片中找到的)

这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值