linux文件系统初始化过程(2)---挂载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()首先建立并初始化目录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树进行扩展。

 

时间: 2024-10-22 18:47:49

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

linux文件系统初始化过程(1)---概述

术语表: struct task:进程 struct mnt_namespace:命名空间 struct mount:挂载点 struct vfsmount:挂载项 struct file:文件 struct super_block:超级块 struct dentry:目录 struct inode:索引节点   一.目的     linux文件系统主要分为三个部分:文件系统调用:虚拟文件系统(VFS):挂载到VFS的实际文件系统.     其中,VFS是核心,linux文件系统的本质就是在内存

linux文件系统初始化过程(5)---加载initrd(下)

一.目的     linux把文件分为常规文件.目录文件.软链接文件.硬链接文件.特殊文件(设备文件.管道文件.socket文件等)几种类型,分别对应不同的新建函数sys_open().sys_mkdir().sys_symlink().sys_link().sys_mknod().     系统初始化阶段成功加载initrd后,调用这些接口函数创建各种文件,因此这些函数在linux文件系统初始化过程中起到了重要作用,本文将详细描述这些接口函数的实现过程.     这些接口函数主要在fs/nam

linux文件系统初始化过程(6)---执行init程序

一.目的     内核加载完initrd文件后,为挂载磁盘文件系统做好了必要的准备工作,包括挂载了sysfs.proc文件系统,加载了磁盘驱动程序驱动程序等.接下来,内核跳转到用户空间的init程序,由init完成创建磁盘设备文件.加载磁盘文件系统.从rootfs切换到磁盘根文件系统等工作.     由于在不同的linux发行版中,init的实现方式差异很大,不能将所有的发行版都分析一遍,因此本文选取ubuntu12.04发行版来描述如何从rootfs切换到磁盘根文件系统.   二.创建磁盘设备

linux文件系统初始化过程(3)---加载initrd(上)

一.目的       本文主要讲述linux3.10文件系统初始化过程的第二阶段:加载initrd.     initrd是一个临时文件系统,由bootload负责加载到内存中,里面包含了基本的可执行程序和驱动程序.在linux初始化的初级阶段,它提供了一个基本的运行环境.当成功加载磁盘文件系统后,系统将切换到磁盘文件系统并卸载initrd.     如果是嵌入式设备,那么最终的文件系统就是initrd.     二.cpio文件格式       initrd常用的的文件格式是cpio,cpio

Linux有问必答-如何创建和挂载XFS文件系统

Linux有问必答-如何创建和挂载XFS文件系统 问题: 我听说一个牛X的文件系统XFS,打算在我的磁盘上试试XFS.那格式化和挂载XFS文件系统的Linux命令是什么呢? XFS是高性能文件系统,SGI为他们的IRIX平台而设计.自从2001年移植到Linux内核上,由于它的高性能,XFS成为了许多企业级系统的首选,特别是有大量数据,需要结构化伸缩性和稳定性的.例如,RHEL/CentOS 7 和Oracle Linux将XFS作为默认文件系统,SUSE/openSUSE已经为XFS做了长期支

linux文件系统初始化过程(4)---加载initrd(中)

一.目的     上文详细介绍了CPIO格式的initrd文件,本文从源代码角度分析加载并解析initrd文件的过程.     initrd文件和linux内核一般存储在磁盘空间中,在系统启动阶段由bootload负责把磁盘上的内核和initrd加载到指定的内存空间中:然后,再由内核读取和解析initrd文件,在VFS(目前只有rootfs的根目录)中新建目录.常规文件.符号链接文件以及特殊文件:这样VFS就从根目录"/"成长为一棵枝繁叶茂的大树了.   二.函数调用过程      

Linux中自动挂载Windows文件系统分区的常用方法

在PC机上安装了双系统,Linux有时候需要用到Windows的资源,所以选择D盘在Linux启动时自动挂载.方法比较简单,就是修改/etc/fstab文件.首先介绍一下/etc/fstab文件格式. /etc/fstab文件配置了所有文件系统和磁盘设备的挂载选项.每种文件系统和磁盘设备都对应独立的行,行中每个选项用空格或者TAB隔开.每行格式如下: fs_spec[tab]fs_file[tab]fs_type[tab]fs_option[tab]fs_dump[tab]fs_pass 1 f

简单讲解Linux的文件系统及相关的挂载命令

  Linux文件系统 和windows的C盘D盘E盘的概念一样,这个"文件系统"或者叫"组织体系"是软件级别的,是linux系统"内在"的体系,就像你脑子里的一个"想法",并无需依赖于任何的实际一样. :idea: linux的系统组织方式是--整个系统从根开始,按树形目录依次向下逐渐扩大,分类存放不同用途的文件,/读作"斜线",英文slash;当其写作一个路径时,第一个/表示根,即root,其他的/表示

Linux系统挂载NTFS文件系统

  今天尝试并成功的将一块500G的移动硬盘挂载到了RHEL5的系统上,甚感欣慰.想到也许以后自己或其他同学们会有类似经历,于是尽量细致的记录于此.     无论是一块安装了Windows/Linux双系统的硬盘,还是通过USB连接的移动硬盘/U盘,都是可以挂载到Linux系统中的.不过由于Windows本身常用的文件系统包括fat32和NTFS,因此还是需要区别的.废话少说,进入正题.系统环境如下:操作系统-- RHEL5,详细版本为:Red Hat Enterprise Linux Se