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

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

一、目的

    本文主要讲述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()首先建立并初始化目录hashdentry_hashtable和索引节点hashinode_hashtable;然后设置内核可以打开的最大文件数;最后调用mnt_init()完成sysfsrootfs文件系统的注册和挂载。

    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文件系统的挂载过程:

    1sysfs_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 };  
 

 

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

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

 

    3kern_mount()调用sysfs_fs_type的.mount成员sysfs_mount()创建并初始化超级块、根目录'/'、根目录的索引节点等数据结构;并且把超级块添加到全局单链表super_blocks中,把索引节点添加到hashinode_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文件系统的挂载过程:
    1mnt_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 };  

 

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

    3init_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     }   
 

 

    4init_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);  

 

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

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


                   图3
 

六、总结

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

 

相关文章
|
22天前
|
安全 Linux 数据安全/隐私保护
深入Linux操作系统:文件系统和权限管理
在数字世界的海洋中,操作系统是连接用户与硬件的桥梁,而Linux作为其中的佼佼者,其文件系统和权限管理则是这座桥梁上不可或缺的结构。本文将带你探索Linux的文件系统结构,理解文件权限的重要性,并通过实际案例揭示如何有效地管理和控制这些权限。我们将一起航行在Linux的命令行海洋中,解锁文件系统的奥秘,并学习如何保护你的数据免受不必要的访问。
|
1月前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
85 8
|
1月前
|
存储 Linux 文件存储
Linux文件系统
Linux文件系统 一切皆文件 在Linux中,“一切皆文件”的概念意味着系统中的所有资源,包括硬件设备、目录及进程等,均被视为文件。这种设计简化了操作和管理,具体包括: 普通文件:存储数据的常规文件。 目录文件:包含其他文件和子目录的文件。 进程文件:在/proc目录下代表系统中运行的进程。 设备文件:位于/dev目录,代表硬件设备。 网络字节流套接字文件:用于网络通信的数据流。 链接文件:指向另一个文件的符号链接或硬链接。 管道文件:用于进程间通信的文件。
54 7
|
2月前
|
Linux
linux开机挂载镜像
【10月更文挑战第1天】在 Linux 系统中,开机挂载镜像通常涉及几个关键步骤,包括创建挂载点、编辑配置文件以及重新加载配置
101 0
|
3月前
|
存储 Linux 索引
Linux 下最主流的文件系统格式——ext
【9月更文挑战第8天】硬盘被划分为若干相同大小的块(Block),默认大小为4K,便于灵活管理文件数据。文件数据分散存放于这些块中,提高了数据添加、删除和插入的便利性。
|
3月前
|
存储 缓存 Linux
Linux文件系统的功能规划
【9月更文挑战第12天】本文通过类比图书馆,形象地解释了文件系统的组织形式和管理方法。首先,文件系统需按块存储文件,并设有索引区方便查找。其次,热点文件应有缓存层提高效率,文件需分类存储以便管理。最后,Linux内核需记录文件使用情况,通过文件描述符区分不同文件,确保文件操作准确无误。
|
Linux
Linux协议栈(6)——初始化及链路层实现
这篇主要学习链路层在内核协议栈的实现,包括初始化、注册以及接收发送,会涉及相关函数和代码所在位置。 我们知道以太网不仅可以传输IP分组,还可以传输其他协议的分组,接收系统必须能够区分不同的协议类型,以便将数据转发到正确的例程进一步处理。
2887 0
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
107 8
|
1月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
377 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
87 3