您好,欢迎访问三七文档
linux文件系统初始化过程(1)---概述术语表:structtask:进程structmnt_namespace:命名空间structmount:挂载点structvfsmount:挂载项structfile:文件structsuper_block:超级块structdentry:目录structinode:索引节点一、目的linux文件系统主要分为三个部分:文件系统调用;虚拟文件系统(VFS);挂载到VFS的实际文件系统。其中,VFS是核心,linux文件系统的本质就是在内存中创建一棵VFS树。当根目录被创建后,用户就可以使用系统调用在VFS上创建文件、删除文件、挂载各种文件系统等操作。该系列文章主要分析linux3.10文件系统初始化过程,分为三个阶段:1、挂载根文件系统(rootfs);2、加载initrd;3、挂载磁盘文件系统;二、常用数据结构linux文件系统中重要的数据结构有:文件、挂载点、超级块、目录项、索引节点等。每个数据结构的具体实现请参见源代码,这里不再描述。为了直观的表示数据结构之间的关系,请参见图1:图中含有两个文件系统(红色和绿色表示的部分),并且绿色文件系统挂载在红色文件系统tmp目录下。一般来说,每个文件系统在VFS层都是由挂载点、超级块、目录和索引节点组成;当挂载一个文件系统时,实际也就是创建这四个数据结构的过程,因此这四个数据结构的地位很重要,关系也很紧密。由于VFS要求实际的文件系统必须提供以上数据结构,所以不同的文件系统在VFS层可以互相访问。如果进程打开了某个文件,还会创建file(文件)数据结构,这样进程就可以通过file来访问VFS的文件系统了。另外,该图只给出了主要的关系结构,忽略了部分细节。图1三、函数调用关系图2描述了文件系统初始化过程中主要的函数调用关系。linux文件系统初始化过程主要分为三个阶段:1、vfs_caches_init()负责挂载rootfs文件系统,并创建了第一个挂载点目录:'/';2、rest_init()负责加载initrd文件,扩展VFS树,创建基本的文件系统目录拓扑;3、init程序负责挂载磁盘文件系统,并将文件系统的根目录从rootfs切换到磁盘文件系统;图2四、总结linux文件系统初始化过程主要分为三个阶段:挂载rootfs,提供第一个挂载点''/;加载initrd,扩展VFS树;执行init程序,完成linux系统的初始化。下面会详细介绍每个阶段的主要内容。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目录。下面详细介绍sysfs文件系统的挂载过程:1、sysfs_init()调用register_filesystem()注册文件系统类型sysfs_fs_type,并加入到全局单链表file_systems中。sysfs_fs_type定义如下,.mount成员函数负责超级块、根目录和索引节点的创建和初始化工作。173err=register_filesystem(&sysfs_fs_type);174if(!err){175sysfs_mnt=kern_mount(&sysfs_fs_type);176if(IS_ERR(sysfs_mnt)){177printk(KERN_ERRsysfs:couldnotmount!\n);178err=PTR_ERR(sysfs_mnt);179sysfs_mnt=NULL;180unregister_filesystem(&sysfs_fs_type);181gotoout_err;182}2、sysfs_init()-kern_mount()-vfs_kern_mount()创建并初始化structmount挂载点,并使用全局变量sysfs_mnt保存该挂载点的挂载项(mnt成员)。3、kern_mount()调用sysfs_fs_type的.mount成员sysfs_mount()创建并初始化超级块、根目录'/'、根目录的索引节点等数据结构;并且把超级块添加到全局单链表super_blocks中,把索引节点添加到hash表inode_hashtable和超级块的inode链表中。目前,我们可以得出一个重要结论:kern_mount()主要完成挂载点、超级块、根目录和索引节点的创建和初始化操作,可以看成是一个原子操作,这个函数以后会频繁使用。796mnt-mnt.mnt_root=root;797mnt-mnt.mnt_sb=root-d_sb;798mnt-mnt_mountpoint=mnt-mnt.mnt_root;799mnt-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成员函数负责超级块、根目录和索引节点的建立和初始化工作。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中的视图如图3所示:为了突出主要关系,省略了挂载点指向超级块和根目录。从图中看出,rootfs处于进程的命名空间中,并且进程的fs_struct数据结构的root和pwd都指向了rootfs的根目录'/',所以用户实际使用的是rootfs文件系统。另外,rootfs为VFS提供了'/'根目录,所以文件操作和文件系统的挂载操作都可以在VFS上进行了。图3六、总结linux文件系统在初始化时,同时挂载了sysfs和rootfs文件系统,但是只有rootfs处于进程的命名空间中,且进程的root目录和pwd目录都指向rootfs的根目录。至此,linux的VFS已经准备好了根目录(rootfs的根目录'/'),此时用户可以使用系统调用对VFS树进行扩展。linux文件系统初始化过程(3)---加载initrd(上)一、目的本文主要讲述linux3.10文件系统初始化过程的第二阶段:加载initrd。initrd是一个临时文件系统,由bootload负责加载到内存中,里面包含了基本的可执行程序和驱动程序。在linux初始化的初级阶段,它提供了一个基本的运行环境。当成功加载磁盘文件系统后,系统将切换到磁盘文件系统并卸载initrd。如果是嵌入式设备,那么最终的文件系统就是initrd。二、cpio文件格式initrd常用的的文件格式是cpio,cpio格式记录了文件系统的结构和内容。cpio格式具体定义如图1所示:cpio格式的文件由段组成,最后一个段比较特殊,文件名为”TRAILER!!!”。每个段都由文件头、文件名和文件体组成;文件名和文件体的长度由文件头中的name_len和body_len指定,并且文件名和文件体需要按指定字节对齐,所以尾部包含padding。文件头共110个字节,头6个字节固定为070701,剩下字节的含义分别为:索引节点号、文件模式、用户id、组id、链接数、时间戳、文件体长度、主设备号、次设备号、设备号、文件名长度、保留字段。其他详细情况请参见init/initramfs.c文件,这里不再描述。图1三、initrd文件实例为了更直观的理解cpio格式的initrd文件,下面看一个实例。在ubuntu环境中,boot目录下存放着经过压缩的cpio格式文件initrd。将boot目录下的initrd文件拷贝到任意目录下,重名为为initrd.gz,并且使用gunzip解压。这样我们就得到了一个cpio格式的initrd文件,使用vi查看文件内容如图2所示(由于文件太大,只展示了部分内容):简单分析后显示该文件包含了script/nfs-top目录、script/nfs-top/ORDER文件、script/nfs-top/udev文件、run目录、标志cpio结束的TRAILER!!!文件。图2四、解压initrd文件initrd经过gunzip解压后,可以使用cpio工具解压cpio格式的文件。命令如下:1.root:cpio-idmvinitrd解压成功后,使用ls命令查看initrd文件内容如图3所示:bin和sbin目录下包含基本的可执行程序;conf和etc目录下是配置文件;lib目录下是可执行程序使用的动态库;scripts目录下是脚本程序;init程序。initrd必须提供一个init程序,linux在加载完initrd后,会跳转到init程序,由init程序负责后面的初始化工作。图3五、总结本文详细介绍了cpio格式的initrd文件,以及解压后各个目录的含义。initrd文件系统
本文标题:文件系统加载过程
链接地址:https://www.777doc.com/doc-2336573 .html