linux文件系统初始化过程(2)---挂载rootfs文件系统

2023-10-29

一、目的

    本文主要讲述linux3.10文件系统初始化过程的第一阶段:挂载rootfs文件系统。

    rootfs是基于内存的文件系统,所有操作都在内存中完成;也没有实际的存储设备,所以不需要设备驱动程序的参与。基于以上原因,linux在启动阶段使用rootfs文件系统,当磁盘驱动程序和磁盘文件系统成功加载后,linux系统会将系统根目录从rootfs切换到磁盘文件系统。

 

二、主要函数调用过程

    图1描述了挂载rootfs的函数调用关系(图中红色部分),便于后面的分析。

    从图中发现,在挂载rootfs前会先挂载sysfs,这样做的原因是确保sysfs能够完整的记录下设备驱动模型。

    sysfs_init()完成注册和挂载sysfs文件系统的功能;init_rootfs()负责注册rootfs,init_mount_tree()负责挂载rootfs,并将init_task的命名空间与之联系起来。

                                   图1

 

三、linux文件系统初始化

    vfs_cache_init()首先建立并初始化目录hash表dentry_hashtable和索引节点hash表inode_hashtable;然后设置内核可以打开的最大文件数;最后调用mnt_init()完成sysfs和rootfs文件系统的注册和挂载。

    linux使用哈希表存储目录和索引节点,以提高目录和索引节点的查找效率;dentry_hashtable是目录哈希表,inode_hashtable是索引节点哈希表。

 

四、挂载sysfs文件系统

    sysfs用来记录和展示linux驱动模型,sysfs先于rootfs挂载是为全面展示linux驱动模型做好准备。

    mnt_init()调用sysfs_init()注册并挂载sysfs文件系统,然后调用kobject_create_and_add()创建"fs"目录。

 

2735 err = sysfs_init();  
2736 if (err)  
2737 printk(KERN_WARNING "%s: sysfs_init error: %d\n",  
2738 __func__, err);  
2739 fs_kobj = kobject_create_and_add("fs", NULL);  
2740 if (!fs_kobj)  
2741 printk(KERN_WARNING "%s: kobj create error\n", __func__);  

 

    下面详细介绍sysfs文件系统的挂载过程:

    1、sysfs_init()调用register_filesystem()注册文件系统类型sysfs_fs_type,并加入到全局单链表file_systems中。sysfs_fs_type定义如下,.mount成员函数负责超级块、根目录和索引节点的创建和初始化工作。

 

173     err = register_filesystem(&sysfs_fs_type);  
174     if (!err) {  
175         sysfs_mnt = kern_mount(&sysfs_fs_type);  
176         if (IS_ERR(sysfs_mnt)) {  
177             printk(KERN_ERR "sysfs: could not mount!\n");  
178             err = PTR_ERR(sysfs_mnt);  
179             sysfs_mnt = NULL;  
180             unregister_filesystem(&sysfs_fs_type);  
181             goto out_err;  
182         }   

 

 

 
152 static struct file_system_type sysfs_fs_type = {  
153     .name       = "sysfs",  
154     .mount      = sysfs_mount,  
155     .kill_sb    = sysfs_kill_sb,  
156     .fs_flags   = FS_USERNS_MOUNT,  
157 };  
 

 

 

    2、sysfs_init()->kern_mount()->vfs_kern_mount()创建并初始化struct mount挂载点,并使用全局变量sysfs_mnt保存该挂载点的挂载项(mnt成员)。

 
783     mnt = alloc_vfsmnt(name);  
784     if (!mnt)  
785         return ERR_PTR(-ENOMEM);  
 

 

    3、kern_mount()调用sysfs_fs_type的.mount成员sysfs_mount()创建并初始化超级块、根目录'/'、根目录的索引节点等数据结构;并且把超级块添加到全局单链表super_blocks中,把索引节点添加到hash表inode_hashtable和超级块的inode链表中。

    目前,我们可以得出一个重要结论:kern_mount()主要完成挂载点、超级块、根目录和索引节点的创建和初始化操作,可以看成是一个原子操作,这个函数以后会频繁使用。

 

790     root = mount_fs(type, flags, name, data);  
1091 struct dentry *  
1092 mount_fs(struct file_system_type *type, int flags, const char *name, void*data)  
1093 {  
1094     struct dentry *root;  
              ...  
1108   
1109     root = type->mount(type, flags, name, data);  

 

 

 
107 static struct dentry *sysfs_mount(struct file_system_type *fs_type,  
108     int flags, const char *dev_name, void *data)  
109 {                 ...  
112     struct super_block *sb;  
                  ...  
125     sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);  
            ...  
130     if (!sb->s_root) {  
131         error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);  
      4、vfs_kern_mount()初始化挂载点的根目录和超级块。

 

 

 

 

 

796 mnt->mnt.mnt_root = root;  
797 mnt->mnt.mnt_sb = root->d_sb;  
798 mnt->mnt_mountpoint = mnt->mnt.mnt_root;  
799 mnt->mnt_parent = mnt;  
 

    5、mnt_init()调用kobject_create_and_add()创建"fs"目录。

 

 

 

    通过以上步骤,sysfs文件系统在VFS中的视图如图2所示:挂载点指向超级块和根目录;超级块处在super_blocks单链表中,并且链接起所有属于该文件系统的索引节点;根目录'/'和目录"fs"指向各自的索引节点;为了提高查找效率,索引节点保存在hash表中。

                    图2

 

五、挂载rootfs文件系统

    mnt_init()调用init_rootfs()注册rootfs,然后调用init_mount_tree()挂载rootfs。

    下面详细介绍rootfs文件系统的挂载过程:
    1、mnt_init()调用init_rootfs()注册文件系统类型rootfs_fs_type,并加入到全局单链表file_systems中。

rootfs_fs_type定义如下,mount成员函数负责超级块、根目录和索引节点的建立和初始化工作。

 

265 static struct file_system_type rootfs_fs_type = {  
266     .name       = "rootfs",  
267     .mount      = rootfs_mount,  
268     .kill_sb    = kill_litter_super,  
269 };  

 

    2、init_mount_tree()调用vfs_kern_mount()挂载rootfs文件系统,详细的挂载过程与sysfs文件系统类似,不再赘述。

    3、init_mount_tree()调用create_mnt_ns()创建命名空间,并设置该命名空间的挂载点为rootfs的挂载点,同时将rootfs的挂载点链接到该命名空间的双向链表中。

 

 

2459 static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)  
2460 {  
2461     struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns);  
2462     if (!IS_ERR(new_ns)) {  
2463         struct mount *mnt = real_mount(m);  
2464         mnt->mnt_ns = new_ns;  
2465         new_ns->root = mnt;  
2466         list_add(&mnt->mnt_list, &new_ns->list);  
2467     }   
 

 

 

    4、init_mount_tree()设置init_task的命名空间,同时调用set_fs_pwd()和set_fs_root()设置init_task任务的当前目录和根目录为rootfs的根目录'/'。

 

 

2696     ns = create_mnt_ns(mnt);  
2697     if (IS_ERR(ns))  
2698         panic("Can't allocate initial namespace");  
2699   
2700     init_task.nsproxy->mnt_ns = ns;  
2701     get_mnt_ns(ns);  
2702   
2703     root.mnt = mnt;  
2704     root.dentry = mnt->mnt_root;  
2705   
2706     set_fs_pwd(current->fs, &root);  
2707     set_fs_root(current->fs, &root);  

 

 

    通过以上分析,我们发现sysfs和rootfs的区别在于:虽然系统同时挂载了sysfs和rootfs文件系统,但是只有rootfs处于init_task进程的命名空间内,也就是说系统当前实际使用的是rootfs文件系统。

    此时,sysfs和rootfs在VFS中的视图如图3所示:为了突出主要关系,省略了挂载点指向超级块和根目录。
从图中看出,rootfs处于进程的命名空间中,并且进程的fs_struct数据结构的root和pwd都指向了rootfs的根目录'/',所以用户实际使用的是rootfs文件系统。另外,rootfs为VFS提供了'/'根目录,所以文件操作和文件系统的挂载操作都可以在VFS上进行了。

                   图3

 

六、总结

    linux文件系统在初始化时,同时挂载了sysfs和rootfs文件系统,但是只有rootfs处于进程的命名空间中,且进程的root目录和pwd目录都指向rootfs的根目录。至此,linux的VFS已经准备好了根目录(rootfs的根目录'/'),此时用户可以使用系统调用对VFS树进行扩展。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux文件系统初始化过程(2)---挂载rootfs文件系统 的相关文章

  • petalinux uboot源码在哪的问题

    petalinux uboot源码在哪的问题 提出问题解决问题注意 xff1a 要知道自己的版本 1 uboot2 kernel 提出问题 petalinux 源码目录存放在哪里的问题 xff0c 也就是petalinux工程的uboot和
  • petalinux uboot源码怎么打补丁

    petalinux的源码 petalinux工程对于我来说 xff0c 就是有一点不能直接起修改源码 xff0c 你需要间接的修改源码的内容 xff1f 这个修改你还需要遵从petalinux的规章流程 当你不知道的时候你会感到无从下手 x
  • linux文件系统初始化过程(3)---加载initrd(上)

    一 目的 本文主要讲述linux3 10文件系统初始化过程的第二阶段 加载initrd initrd是一个临时文件系统 由bootload负责加载到内存中 里面包含了基本的可执行程序和驱动程序 在linux初始化的初级阶段 它提供了一个基本
  • uboot下内存操作mw和md命令详解

    mw简介 u boot 中的 mw 命令是用于向内存写入数据的命令 它有4种形式 mw b 写入 1 个字节 8 比特 的数据 mw w 写入 1 个字 2 字节 16 比特 的数据 mw l 写入 1 个长字 4 字节 32 比特 的数据
  • 紫枫术河 imx6 uboot的mtd分区总结(rootfs为ubi文件系统) imx6 uboot的mtd分区总结(rootfs为ubi文件系统)

    版权声明 本文为博主原创文章 未经博主允许不得转载 https blog csdn net qq 29729577 article details 51130209 此文章基于U Boot 2014 04版本 烧写工具为mfgtool 开发
  • uboot环境变量分析

    项目情景 最近我在一个新平台的开发过程中遇到烧录问题 具体的问题是使用原厂提供的烧录脚本烧录成功 但是固件却没有更新 其中kernel和dtb烧录指令如下 adnl exe Partition M mem P 0x1000000 F lin
  • ZYNQ平台在SDK下引导启动UBOOT

    ZYNQ芯片 Linux系统搭建完成后 希望通过QSPI Flash的方式来进行程序加载 QSPI Flash启动则需要烧录以下文件 BOOT bin fsbl elf uboot elf uImage linux内核 zynq board
  • 2.移植uboot-添加2440单板,并实现NOR、NAND启动

    1 首先在uboot里新建单板2440 1 1将2410的单板文件夹拷贝成2440 cd board samsung cp smdk2410 smdk2440 rf 拷贝文件夹 然后将smdk2440下的smdk2410 c改为smdk24
  • u-boot常用命令

    u boot常用命令 查看u boot所支持的命令 查询命令 u boot版本 环境变量 板子相关信息 环境变量操作 内存操作 网络操作 EMMC和 SD卡操作 FAT 格式文件系统操作 EXT格式文件系统操作 ubi格式文件系统操作 bo
  • IMX6ULL NXP官方原版u-boot编译烧录体验以及出现的问题

    编译 guangjie ubuntu work imx6ull uboot imx rel imx 4 1 15 2 1 0 ga xgj cat make imx6ull emmc sh bin bash make ARCH arm CR
  • BootLoader介绍

    文章目录 一 BootLoader的引入 二 BootLoader的启动方式 三 BootLoader的结构和启动过程 四 自己写一个BootLoader 1 BootLoader第一阶段 2 BootLoader第二阶段 一 BootLo
  • 玩转树莓派4B之Uboot移植

    此文参考了以下文章 https blog csdn net weixin 42233878 article details 84980951 个人使用的编译环境为ubuntu1904 64位 我的目的是修改树莓派的uboot代码并且看下深入
  • Uboot启动参数说明

    29 Uboot 启动参数说明 bootcmd cp b 0xc4200000 0x7fc0 0x200000 bootm 倒计时到 0 以后 自动执行的指令 bootdelay 2 baudrate 38400 串口波特率 一般使用 38
  • linux rootfs制作

    作一个嵌入式Linux rootfs 并且实现 web 服务 1 文件系统简介 理论上说一个嵌入式设备如果内核能够运行起来 且不需要运行用户进程的话 是不需要文件系统的 文件系统简单的说就是一种目录结构 由于 linux操作系统的设备在系统
  • TQ210烧写uboot secureCRT和minicom都没有信息输出

    前几天一直在纠结TQ210烧写uboot 串口没有信息打印信息输出 结果又是这样的 说明波特率 串口号都是正确的 开发板一上电 按住空格键 结果还是一样 本以为是这个软件是破解版 有BUG 好 切换到LINUX 使用minicom 试试 还
  • linux文件系统初始化过程(4)---加载initrd(中)

    一 目的 上文详细介绍了CPIO格式的initrd文件 本文从源代码角度分析加载并解析initrd文件的过程 initrd文件和linux内核一般存储在磁盘空间中 在系统启动阶段由bootload负责把磁盘上的内核和initrd加载到指定的
  • 图像与 zImage 与 uImage

    它们之间有什么区别 我知道u boot需要uImage格式的内核 我使用的系统首先从第一阶段加载程序启动 然后调用 u boot 我想放弃 u boot 并直接从第一阶段加载程序启动 我必须使用哪种类型的内核映像 它们之间有什么区别 Ima
  • u-boot:搬迁

    这是一个与u boot相关的基本问题 为什么 u boot 代码会自行重新定位 好吧 如果 u boot 是从 NOR flash 或启动 ROM 空间执行 那么这是有道理的 但如果它已经从 SDRAM 运行 为什么它必须再次重新定位自己呢
  • Beaglebone Black 的 U-boot 无法构建 - 目标 CPU 不支持 THUMB 指令

    我正在尝试按照 Chris Simmonds 的 掌握嵌入式 Linux 编程 中的说明为 Beagle Bone Black 构建 u boot 我已经构建了交叉工具链 现在正在尝试使用该工具链构建 Das U boot 但由于不支持 T
  • 如何在uboot中制作“if”和比较语句?

    我是 uboot 和 tftp 编程的新手 基于this url http www denx de wiki view DULG CommandLineParsing 有如何制作if像这样的声明if imi addr then echo I

随机推荐

  • VUE-数字格式化每三位加一个逗号

    描述 将数字格式化成金融格式的数据展示 我的项目不包含小数 方式一 通过过滤器进行格式化 filters 1 在数据出添加过滤方法 div style text align center font size 12px span style
  • docker macvlan虚拟化网络与宿主机通信问题解决——筑梦之路

    默认情况下各个macvlan之间可以通讯 但是不能与宿主机进行通讯 主要原因 为了安全而禁止互通 如宿主机ping容器的ip 尽管他们属于同一网段 但也是ping不通的 反过来也是 这里用两个实例来说明如何解决这个问题 实例一 环境说明 宿
  • 实现strstr函数

    题目 给定两个两个字符串 str1和str2 str1是否包含str2 若包含则返回字符串出现的第一个位置 错误返回 1 示例1 输入 str1 hello str2 ll 输出 2 思路 1 判断两个字符串长度大小 2 判断两个字符串是否
  • The Serenity Prayer

    The Serenity Prayer God grant me the serenity to accept the things I cannot change courage to change the things I can an
  • JavaScript 身份证号合法验证

    let reg 1 9 d 5 18 19 20 3 d d 2 0 1 9 1 0 2 0 2 1 9 10 20 30 31 d 3 0 9Xx if reg test this dataForm visitorCode false t
  • 某个网站(比如CSDN、GitHub)突然打开、加载很慢,有些途径访问正常、其他网站访问正常,可尝试指定域名服务器的IP地址,不走DNS查询。

    摘要 若在电脑上访问某个网站比如CSDN主页 CSDN 专业开发者社区 GitHub主页 GitHub Let s build from here GitHub 通过WIFI或者网线访问很慢 甚至网页打不开 但通过流量访问却很快 访问其他网
  • VSCode出现请更新includePath错误的解决方法

    问题 文件添加 include
  • epoll 与select poll区别

    1 select gt 时间复杂度O n 它仅仅知道了 有I O事件发生了 却并不知道是哪那几个流 可能有一个 多个 甚至全部 我们只能无差别轮询所有流 找出能读出数据 或者写入数据的流 对他们进行操作 所以select具有O n 的无差别
  • ajax跨域post文件上传,ajax跨域上传文件加了xhr报不支持options错误

    用ajax跨域上传文件不加xhr就能请求成功 为了实现进度条功能在ajax里面加了xhr就报错了 ajax url http localhost 823 api FileStream Upload type post contentType
  • python序列和字典

    一 序列 1含义 包含若干个元素 元素有序排列 可通过下标访问一个或多个元素这样的对象 eg 字符串 列表 元组 2 标准类型操作符 expr 1 lt expr 2 3 序列类型操作符 1 in not in 判定一个元素是否在序列中 返
  • 如何复制网上的收费文本

    选中你要复制的内容打开f12开发者工具 查看选中部分地方源代码 鼠标左键打开 直接复制完事 新手博主 请前辈批评指正 丁一
  • JAVA接口实验:卡车要装载一批货物,货物由电视机、计算机和洗衣机组成,卡车需要计算出整批货物的重量。

    卡车要装载一批货物 货物由电视机 计算机和洗衣机组成 卡车需要计算出整批货物的重量 编写能够满足如下条件的程序 定义一个接口 包含计算货物重量的抽象方法 分别定义实现上述接口的用于计算电视机 计算机和洗衣机的类 定义一个卡车类 在其中定义一
  • Android软件开发之获取通讯录联系人 联系人图像

    Android软件开发之获取通讯录联系人信息 十二 发布于2011 10 12 图中选中的数据库 contacts2 db就是系统储存联系人的数据库 我们将它打开看看里面储存了些什么东东 打开contacts db后 发面里面有一堆表 同学
  • Java定时注解@Scheduled的使用,fixedDelay,fixedRate,cron的使用

    Java定时注解 Scheduled的使用 fixedDelay fixedRate cron的使用 问题背景 参数简介 项目创建 测试结果 心得 Lyric 咸咸的汗水 问题背景 项目中经常使用定时任务 spring提供了定时注解 很方便
  • 前端笔试题1

    HTML CSS 题1 1 使用CSS 让该节点不可见 方法越多越好 div class hidden Hi div 使用CSS 让节点不可见的方法有以下几种 把 visibility 属性设置为 hidden 这样元素框不会被绘制 但仍然
  • 【C++】详解声明和定义

    2023年8月28日 周一下午 研究了一个下午才彻底弄明白 写到晚上才写完这篇博客 目录 声明和定义的根本区别 结构体的声明和定义 声明结构体 定义结构体 类的声明和定义 函数的定义和声明 声明函数 定义函数 变量声明和定义 声明变量 定义
  • 人工智能的三个层次:运算智能,感知智能,认知智能

    2016年 人工智能成为产业界和学术界的大热词 年初 李世石与Alpha Go的人机围棋大战吸睛无数 人工智能的话题始料未及地席卷了世界每处 此外 今年也恰逢人工智能学科诞生一甲子 Alpha Go再一次打败人类 受到全世界的瞩目 历经波折
  • android集成友盟推送遇到的问题

    在自身项目集成友盟推送时 参考了官方文档的教程 导入 PushSDK 把下载的 zip 文件解压缩 解压后的文件路径不能有中文 把解压缩后得到的目录下的 PushSDK 当做 Module 导入到自己的工程 在之前的 AndroidMani
  • C++——可变模板参数

    声明 由于对可变模板参数了解资源有限 以下有些观点仅为个人参考手册实践得出的 不要被我个人的观点误导 文章目录 一 基本语法知识 1 基本知识 2 基本语法 二 基本使用方法 1 基本演示 2 参数展开 一 基本语法知识 1 基本知识 C
  • linux文件系统初始化过程(2)---挂载rootfs文件系统

    一 目的 本文主要讲述linux3 10文件系统初始化过程的第一阶段 挂载rootfs文件系统 rootfs是基于内存的文件系统 所有操作都在内存中完成 也没有实际的存储设备 所以不需要设备驱动程序的参与 基于以上原因 linux在启动阶段