zoukankan      html  css  js  c++  java
  • Linux VFS分析

    1. 概念

    VFS,即Virtual File System,在Linux中指虚拟文件系统
    VFS封装了底层文件系统的所有功能和抽象,同时负责把应用层的请求转发给特定的文件系统

    VFS抽象四个基本概念

     - 超级块(superblock): 存放文件系统控制信息
    - 索引节点(inode): 存放具体文件的一般信息, 用来标识存储介质上的文件
    - 文件(file): 存放已打开的文件和进程之间交互的信息
    - 目录项(dentry): 存放文件的名称和文件的路径

    2. 数据结构

    vfs中重要数据结构包括superblock、inode、file和dentry,其他重要数据结构包括

     - file_system_type: 用来描述不同的文件系统
    - vfsmount:   描述系统中已经挂载的文件系统信息, 用于对超级块和inode进行跟踪

    superblock主要成员如下

    成员 作用
    s_list 指向下一个superblock,所有的superblock组成一个链表,头指针保存在super_blocks变量中
    s_fs_info 指向特定文件系统的superblock信息,比如ext2,这个指针指向ext2_sb_info结构
    s_dirt 因为superblock既存在于内存中也存在于磁盘中,所以需要这个标记标示内存中的数据是否和磁盘中的同步
    s_root 文件系统根目录的dentry,表示这个文件系统的mount点
    s_inodes 指向所有inodes组成的链表的头指针
    s_files 指向所有file对象组成的链表的头指针
    s_op 超级块操作函数集,struct super_operations类型,包括alloc_inode,destroy_inode,put_super等函数,用来管理这个文件系统中的 inode 的函数

    inode的主要成员如下

    成员 作用
    i_dentry 指向本inode的所有dentry对象组成的链表的头指针
    i_ino 指向特定文件系统的superblock信息,比如ext2,这个指针指向ext2_sb_info结构
    i_nlink inode的硬连接引用计数
    i_count 进程对inode的引用计数
    i_uid/i_gid 所属用户/组的id
    i_atime inode访问时间,类型域有i_mtime和i_ctime
    i_mode inode的权限
    i_size 文件大小(单位:字节)
    i_data 数据地址索引,struct address_space结构类型
    i_mapping 内存索引页面,struct address_space结构类型指针,指向i_data(?)
    i_blocks 所占的block数
    i_bytes 最后一个block使用了的字节数
    i_sb_list 指向super_block中s_inodes链表中本inode的下一个inode
    i_op 索引节点操作函数集,inode_operations类型,定义直接在 inode 上执行的操作
    i_cdev/i_pipe/i_bdev 非特殊文件时,inode所存储的设备
    i_rdev 非特殊文件时,所存储设备的设备号

    dentry的主要成员如下

    成员 作用
    d_name 文件名
    d_inode 指向的inode
    d_parent 父目录的dentry对象
    d_count 目录项对象使用计数器
    d_child 对于目录来说,和本dentry相同父目录的目录dentry对象链表的头指针
    d_subdirs 对于目录来说,当前dentry下的子目录dentry对象链表的头指
    d_alias 指向相同inode的所有dentry对象构成的链表的头指针
    d_op 目录项操作表,dentry_operations类型
    d_sb 文件的超级块对象

    file的主要成员如下

    成员 作用
    f_dentry 指向当前file对象关联的dentry对象
    f_vfsmnt  
    f_pos 文件指针
    f_op 定义与文件和目录相关的方法(即标准系统调用POSIX标准文件I/O管理函数),file_operations结构类型

    file_system_type的主要数据结构

    成员 作用
    name 文件系统的名称
    fs_flags 一些特殊标记,如FS_REQUIRES_DEV
    mount 本文件系统的挂载方法,执行kern_mount函数时调用
    kill_sb 卸载文件系统超级块的方法
    next file_system_type类型单项链表,指向其他文件系统,单链表的表头由全局变量file_systems表示
    fs_supers 双向链表,指向本文件系统所支持的super_block

    vfsmount的主要数据结构

    成员 作用
    mnt_parent 上一层挂载点
    mnt_mounts 子文件系统的链表头
    mnt_child 指向上一层挂载点mnt_mounts形成双链表的兄弟结点
    mnt_mountpoint 指向挂载点dentry结构的指针
    mnt_root 指向本文件系统的根路径dentry
    mnt_sb 指向文件系统超级块
    mnt_flags 挂载选项,如MNT_NODEV,MNT_READONLY等
    mnt_list 指向vfsmount结构所形成链表的头指针

    TIP: 通常,superblock, inode会保存至存储介质;而dentry ,file仅存在于内存中

    3. 文件系统实现

    下面以实现某个简单文件系统为例

    static struct vfsmount *fixfs_mnt;
    static struct file_system_type fixfs_fs_type = {
        .owner =     THIS_MODULE,
        .name  =     "fixfs",
        .mount =     fixfs_mount,
        .kill_sb =   fixfs_kill_sb,
    };
    
    static int __init init_fixfs_fs(void)
    {
        int ret;
    
        /* fixfs specify init */
        ret = register_filesystem(&fixfs_fs_type);
        if (!ret) {
            fixfs_mnt = kern_mount(&fixfs_fs_type);
            if (IS_ERR(fixfs_mnt)) {
                fixfs_mnt = NULL;
                unregister_filesystem(&fixfs_fs_type);
            }
        }
        /* error handle specs */
    }
    
    static void __exit exit_fixfs_fs(void)
    {
        unregister_filesystem(&fixfs_fs_type);
    
        /* fixfs specify cleanup */
    } 
    
    module_init(init_fixfs_fs);
    module_exit(exit_fixfs_fs);

    4. 特殊文件系统

    Linux中有一些特殊文件系统,有特殊的用途,基于内存实现
    主要包括rootfs、proc、sysfs、swap、tmpfs等

    4.1 rootfs

    roofs初始化主要过程如下

    vfs_caches_init
      mnt_init
        init_rootfs
        init_mount_tree

    roofs初始化后创建一个基于内存虚拟的根文件系统,后面会指向真正的根文件系统(基于block_dev)

    上面两个函数执行完成后,rootfs的挂载点默认为"/",init_task进程的根目录和当前目录为"/"。

    下面介绍实际的根文件系统挂载
    在Linux中,允许实际的根文件系统存放在不同的地方,如硬盘分区,软盘,NFS或保存在ramdisk中,此时需要在内核中指定变量ROOT_DEV或由bootloader来传递root提供包含根文件系统的设备号
    也可以将实际的根文件系统编进内核

    
    

    实际根文件系统的挂载在函数prepare_namespace中,该函数必须在do_basic_setup之后
    之所以在do_basic_setup之后,因为do_basic_setup完成了模块的加载(do_initcalls),也包括设备驱动程序,这样后面在具体设备上读取根文件系统才能成功。

    
    

    在do_initcalls函数会执行rootfs_initcall,
    对于initrd类型(initrd机制)会调用populate_rootfs,否则调用default_rootfs
    populate_rootfs主要完成initrd的检测工作,检查并解压CPIO Initrd或Initramfs或Image-Initrd
    对于initramfs和cpio-initrd的,都会将文件系统解压到根文件系统,此时将不会执行prepare_namespace
    default_rootfs创建目录(/dev,/root)及节点(/dev/console)

    
    

    prepare_namespace首先会解析内核参数root(由bootloader传递)并生成ROOT_DEV
    然后尝试加载Image-Initrd(/initrd.image)
    然后会尝试加载软盘0分区上的根文件系统
    最后通过mount_root依次加载NFS,软盘1分区及块设备上的根文件系统
    当成功加载一种根文件系统后,会进行根文件系统的切换

    当实际根文件系统成功挂载后,init_post会执行一些清理工作并执行init程序切换至用户空间

  • 相关阅读:
    Oracle 导入导出报错的简单处理
    Windows 下面 winrar 压缩简单记录
    zip 与 unzip的简单使用
    [知乎]山东:一枚神奇独一的“三棱锥”
    【喷嚏图卦】 委内瑞拉崩溃的背后:渐行渐近的石油危机
    [互联网]2018年互联网套路简史
    [wiki]陶德曼调停
    [阮一峰]找回密码的功能设计
    sap 最新财报以及云业务转型情况
    debian 7 安装 rz sz lrzsz
  • 原文地址:https://www.cnblogs.com/hzl6255/p/2764925.html
Copyright © 2011-2022 走看看