一、目的
本文主要讲述linux内核rootfs文件系统的挂载过程,内核版本为3.10。
rootfs是基于内存的文件系统,没有实际的存储设备,所有操作都在内存中完成。为了保证linux内核的精简性,很多与内核不强相关的功能(设备驱动等)都放在了initrd中,而rootfs文件系统最重要的作用就是为initrd提供了挂载目录:root根目录。
initrd挂载完成后,内核运行第一个进程init,init进行一系列的初始化操作,包括加载磁盘设备驱动程序和磁盘文件系统,最后把内核的根目录从rootfs的根目录切换到磁盘文件系统的根目录。
二、主要函数调用过程
下面给出挂载rootfs文件系统的主要函数调用关系(图中红色部分),便于后面的分析。
三、分析vfs_cache_init()
vfs_cache_init()首先建立并初始化目录hash表dentry_hashtable和索引节点hash表inode_hashtable;然后设置内核可以打开的最大文件数;最后调用mnt_init()负责sysfs和rootfs文件系统的建立和挂载。
四、挂载sysfs文件系统
sysfs文件系统主要用来展示linux驱动模型,sysfs先于rootfs挂载是为了全面展示linux驱动设备做好准备。
mnt_init()调用sysfs_init()创建并挂载sysfs文件系统,然后调用kobject_create_and_add()创建“fs”目录。
下面详细介绍sysfs文件系统的挂载过程:
1、sysfs_init()调用register_filesystem()注册sysfs文件系统类型sysfs_fs_type,并加入到全局单链表file_systems中。sysfs_fs_type定义如下,mount成员函数负责超级块、根目录和索引节点的建立和初始化工作。
2、sysfs_init()调用kern_mount()挂载文件系统,kern_mount()调用vfs_kern_mount()创建并初始化挂载点数据结构structmount,并使用全局变量sysfs_mnt保存该挂载点的挂载项(mnt成员)。
3、kern_mount()调用sysfs_fs_type的成员函数sysfs_mount()创建并初始化超级块、根目录“/”、根目录的索引节点等数据结构;并且把超级块添加到全局单链表super_blocks中,把索引节点添加到hash表inode_hashtable和超级块的inode链表中。
4、vfs_kern_mount()初始化sysfs_mnt挂载点的根目录和超级块。
5、mnt_init()调用kobject_create_and_add()创建“fs”目录。
通过以上步骤,sysfs文件系统在VFS中的视图如下:其中超级块处在super_blocks单链表中;为了提高查找效率,索引节点处在名为inode_hashtabld的hash表中;超级块链接起所有属于该文件系统的索引节点;目录项指向各自的索引节点;挂载点指向超级块和根目录。
五、挂载rootfs文件系统
mnt_init()调用init_rootfs()注册rootfs文件系统,然后调用init_mount_tree()挂载rootfs文件系统。
下面详细介绍rootfs文件系统的挂载过程:
1、mnt_init()调用init_rootfs()注册rootfs文件系统类型rootfs_fs_type,并加入到全局单链表file_systems中。rootfs_fs_type定义如下,mount成员函数负责超级块、根目录和索引节点的建立和初始化工作。
2、init_mount_tree()调用vfs_kern_mount()挂载rootfs文件系统,详细的挂载过程与sysfs文件系统类似,不再熬述。
3、init_mount_tree()调用create_mnt_ns()创建命名空间,并设置该命名空间的挂载点为rootfs的挂载点,同时将rootfs的挂载点链接到该命名空间的双向链表中。
4、init_mount_tree()设置init_task的命名空间,同时调用set_fs_pwd()和set_fs_root()设置init_task任务的当前目录和根目录为rootfs的根目录”/”。
通过以上分析,我们发现sysfs和rootfs的区别在于:虽然系统同时挂载了sysfs和rootfs文件系统,但是只有rootfs处于init_task进程的命名空间内,也就是说系统当前实际使用的是rootfs文件系统。
此时,sysfs和rootfs在VFS中的视图如下:为了突出图中主要的关系,省略了挂载点指向超级块和根目录的关系。
从图中看出,只有rootfs处于进程的命名空间中,并且进程的fs_struct数据结构的root和pwd都指向了rootfs的根目录”/”,所以此时用户的所有文件操作,实际只在rootfs文件系统上生效,而sysfs并不参与。
六、总结
linux文件系统在初始化时,同时挂载了sysfs和rootfs文件系统,但是只有rootfs处于进程的命名空间中,且进程的root目录和pwd目录都指向rootfs的根目录。至此,linux的VFS已经准备好了根目录(rootfs的根目录”/”),此时用户就可以使用系统调用进行文件和目录的各种操作,对rootfs文件树进行扩展。