Linux虚拟文件系统(VFS)

虚拟地址空间通常是与进程密切相关的概念,而不是文件系统。虚拟地址空间是为了提供进程对内存的抽象和隔离而设计的。

文件系统不使用页表,直接使用物理地址。

虚拟文件系统是linux内核的一个核心子系统。、

虚拟文件系统的目的:通过一个抽象层,存储设备使用不同的文件系统都可以通过相同的接口访问:open(),red(),write();
在这里插入图片描述

文件系统抽象层

linux能支持各种文件系统,就是因为有文件系统抽象层。
调用过程:write(fd,buf,len);
用户空间write()->虚拟文件系统sys_write()->硬件的文件系统的写方法——>物理介质

Unix文件系统

Unix使用了四种文件系统的抽象概念:文件,目录项,索引节点和安装点(mount point)。
在Unix中,目录属于普通文件,它列出包含在其中的所有文件。

inode和元数据

Unix把文件的相关信息和文件本身这两个概念加以区分,已经是说,文件的元数据(控制权限,大小,创建者。。)被存储在一个单独的数据结构中,该结构被称为索引节点(inode:index node的缩写)。

将元数据和实际数据分开存储是一种思想

Unix文件系统,在物理磁盘布局中也是按照这种思想实现的,在磁盘上,文件(目录也是文件)的元数据存储在单独的几个块中(按照索引顺序)。
控制信息被集中存储在磁盘的超级块中。

VFS对象及数据结构

VFS采用的是面向对象。使用一组数据结构来代表通用文件对象。
VFS主要有四个对象类型:

  1. 超级块对象,它代表一个已安装的文件系统
  2. 索引节点对象,它代表一个具体文件(可以是目录文件)。
  3. 目录项对象,目录项。
  4. 文件对象,有对象打开的文件。
    每个数据结构其中都包含操作函数(以函数指针的形式存储在数据结构中)。

超级块对象

每个文件系统都必须实现超级块对象,存储文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块。不基于磁盘的文件系统,会在使用时动态创建超级块。

struct super_block {
    /* 文件系统特定的信息和操作 */
    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;      // 超级块标志
    const char              *s_id;         // 文件系统的唯一标识符
    unsigned int            s_blocksize;   // 块大小
    unsigned char           s_blocksize_bits; // 块大小的位数
    unsigned char           s_dirt;        // 超级块的脏标志
    int                     s_count;       // 超级块的引用计数
    atomic_t                s_active;      // 超级块的活跃引用计数
    struct hlist_head       s_inode_lru;   // 超级块关联的Inode的LRU链表头
    struct list_head        s_list;        // 全局超级块链表
    struct list_head        s_instances;   // 文件系统实例链表

    /* 与文件系统类型相关的信息 */
    const struct file_system_type *s_type; // 文件系统类型
    const struct fs_context_operations *s_fs_info; // 文件系统信息
    struct fscrypt_info    *s_cop; // 文件系统加密信息

    /* 与底层存储介质相关的信息 */
    struct block_device    *s_bdev; // 超级块对应的块设备
    struct backing_dev_info *s_bdi; // 超级块的后备设备信息

    /* 文件系统挂载点的信息 */
    struct mtd_info        *s_mtd; // 关联的Memory Technology Device(MTD)信息
    struct gendisk         *s_disk; // 关联的块设备信息
    struct hlist_head      s_dentry_lru; // 超级块关联的Dentry的LRU链表头

    /* 其他字段和操作省略... */
};

索引节点对象:存储文件的元数据

内核是根据索引节点对象的信息来操作文件的。
对于Unix风格的文件系统,这些信息可以从磁盘读入。没有索引对象信息,则需要现场创建。

struct inode {
    umode_t               i_mode;      // 文件的权限和类型
    unsigned short        i_opflags;   // 操作标志
    kuid_t                i_uid;       // 文件的用户标识符
    kgid_t                i_gid;       // 文件的组标识符
    dev_t                 i_rdev;      // 设备文件的设备号
    loff_t                i_size;      // 文件大小
    struct timespec       i_atime;     // 最后访问时间
    struct timespec       i_mtime;     // 最后修改时间
    struct timespec       i_ctime;     // 最后状态改变时间
    struct super_block   *i_sb;        // 超级块指针
    const struct inode_operations *i_op; // Inode 操作
    struct file_operations *i_fop;     // 文件操作
    struct address_space *i_mapping;    // 地址空间对象:即文件的内存中的位置信息
    unsigned long         i_ino;       // 文件的 inode 号
    atomic_t              i_count;     // 引用计数
    unsigned int          i_flags;     // Inode 标志
    struct list_head      i_wb_list;   // 写回列表
    struct list_head      i_lru;       // LRU 列表
    struct list_head      i_sb_list;   // 超级块链表
    struct hlist_node     i_hash;      // Inode hash 链表
    struct dquot          *i_dquot[MAXQUOTAS]; // 磁盘配额
    struct file_lock      *i_flock;     // 文件锁
    unsigned long         i_state;      // Inode 状态
    struct mutex          i_mutex;     // Inode 互斥锁
    struct rw_semaphore   i_alloc_sem;  // Inode 分配信号量
    // 其他字段和操作省略...
};

一个索引节点也可以代表设备或者管道这样的特殊文件。

目录项对象:在磁盘中没有对应的数据结构

目录项对象就是为了方便查找操作而引入的,真正操作文件还需要inode对象。
VFS根据字符串形式的路径名现场创建它,其没有真正保存在磁盘上,所以目录项结构体没有是否被修改的标志(不需要写回磁盘)。

文件对象

表示进程已打开的文件。进程直接处理的是文件对象。
文件是已打开的文件在内存中的表示。该对象由open()系统调用创建,由close()系统调用撤销。
文件对象只在进程层面表示已打开的文件,但其指向的对应的索引节点和目录项对象是唯一的。

struct file {
    struct file_operations *f_op;    // 文件操作函数指针集合
    loff_t f_pos;                    // 文件当前位置(偏移量)
    struct inode *f_inode;           // 与文件关联的 inode 结构体指针
    struct address_space *f_mapping; // 文件地址空间指针
    unsigned int f_flags;            // 文件状态和标志
    struct file_ra_state f_ra;       // 文件预读取状态
    void *private_data;              // 指向文件特定私有数据的指针
    // 其他字段和操作省略...
};

其通过访问inode对象来操作文件。

和进程有关的数据结构

每一个进程都有一组自己打开的文件。有两个数据结构将VFS层和系统进程紧密联系。

进程自己打开的文件

struct files_struct {
    atomic_t count;               // 引用计数
    struct fdtable *fdt;          // 指向文件描述符表的指针
    spinlock_t file_lock;         // 文件表的自旋锁
    unsigned int next_fd;         // 下一个可用的文件描述符
    unsigned long close_on_exec;  // 需要在执行新程序时关闭的文件描述符标志
    unsigned long open_fds;        // 已打开文件描述符的位图
    struct file *fd_array[0];     // 指向打开文件的指针数组
};
  • fdt:指向 struct fdtable 的指针,表示文件描述符表。fdtable 包含了打开文件的数组以及相应的控制信息。
  • next_fd:表示下一个可用的文件描述符。在进程打开新文件时,会从这个位置开始分配文件描述符。
  • close_on_exec 和 open_fds:用于标记在执行新程序时需要关闭的文件描述符。
  • fd_array:这是一个指针数组,指向打开文件的指针

进程关联的文件系统状态

struct fs_struct {
    int users;                     // 引用计数
    spinlock_t lock;                // 用于保护结构的自旋锁
    struct path root;               // 进程的根目录
    struct path pwd;                // 进程的当前工作目录
    struct fdtable *files;          // 文件描述符表
    // 其他字段和操作省略...
};

它包含了与进程关联的文件系统状态,包括当前工作目录、根目录、以及与文件描述符表相关的信息。

猜你喜欢

转载自blog.csdn.net/qq_35693377/article/details/136047890