术语表:

struct task:进程

struct mnt_namespace:命名空间

struct mount:挂载点

struct vfsmount:挂载项

struct file:文件

struct super_block:超级块

struct dentry:目录

struct inode:索引节点

一、目的

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系统的初始化。下面会详细介绍每个阶段的主要内容。

挂载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树进行扩展。

转载于:https://www.cnblogs.com/alantu2018/p/8447303.html

linux文件系统 - 初始化(一)相关推荐

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

    一.目的 内核加载完initrd文件后,为挂载磁盘文件系统做好了必要的准备工作,包括挂载了sysfs.proc文件系统,加载了磁盘驱动程序驱动程序等.接下来,内核跳转到用户空间的init程序,由ini ...

  2. Linux 文件系统剖析

    Linux 文件系统剖析 按照分层结构讨论 Linux 文件系统 M. Tim Jones, 顾问工程师, Emulex Corp. 简介: 在文件系统方面,Linux® 可以算得上操作系统中的 &q ...

  3. 文件系统:Linux文件系统剖析

    查看原文:http://www.ibm.com/developerworks/cn/linux/l-linux-filesystem/ 在文件系统方面,Linux® 可以算得上操作系统中的 " ...

  4. 简述Linux 文件系统的目录结构

    转自:http://www.linuxsir.org/main/node/189 作者:北南南北 来自:LinuxSir.Org 摘要: Linux文件系统是呈树形结构,了解Linux文件系统的目录结 ...

  5. Linux 文件系统的目录结构

    1. / 文件系统的入口,最高一级目录: 2. /bin 基础系统所需要的命令位于此目录,是最小系统所需要的命令,如:ls, cp, mkdir等. 这个目录中的文件都是可执行的,一般的用户都可以使用 ...

  6. linux 如何赋值目录,Linux文件系统之目录的建立

    一:前言 在用户空间中,建立目录所用的API为mkdir().它在内核中的系统调用入口是sys_mkdir().今天跟踪一下 函数来分析linux文件系统中目录的建立过程. 二:sys_mkdir() ...

  7. Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

    提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么是Linux设备模型呢? 一.Linux 设备模型 1.设备模型概述 从2.6版本开始,Linux开发团队便为内核建立起一个统一 ...

  8. linux简介ubuntu,Linux文件系统简介(基于Ubuntu)

    1. 查看Linux文件系统 (1)使用ls命令可以查看Ubuntu系统的的典型布局. 命令:$ ls /  显示: (2)要想看到更详细的目录层次结构,则应安装和使用tree命令来显示根目录或基本目 ...

  9. 关闭linux系统中读写页缓存,Linux文件系统FAQ

    Linux文件系统FAQ 2010年03月25日 最近实验室搞了一些列讲座,阿福师兄关于文件系统的讲座帮我弄清楚了一些以前不清楚的问题,以问答的形式对文件系统常见的问题进行了总结. Q: 文件系统如何 ...

  10. linux flush 文件,Linux文件系统学习:io的plug过程-blk_flush_plug_list的情况

    在上篇文章中我们看到 if (plug) { if (!request_count) trace_block_plug(q); else { if (request_count >= BLK_M ...

最新文章

  1. DWM1000 长距离模块讨论
  2. Iterator接口和for...of循环
  3. Nginx 多进程模型是如何实现高并发的?
  4. java和python的语法有什么区别?
  5. 谷歌大中华区总裁李开复今日离职
  6. 一个项目中说系统分为表现层、控制层、逻辑层、DAO层和最终数据库五层架构...
  7. python实现二分查找算法_两种方法实现Python二分查找算法
  8. 关键字Restrict
  9. android蓝牙串口arduino源码,android – Arduino:使用串口和软件串口与蓝牙模块
  10. suse11 mysql 5.7_SUSE Linux系统中单实例二进制方式安装MySQL 5.7.22
  11. SharePoint专家新闻轮转器WebPart----亲測力推之Web部件
  12. Hadoop 开源调度系统zeus
  13. c语言注释部分两侧的分界符号分别是,C语言习题及解答.doc
  14. 【2017-7-17】动软代码生成器 数据库连接 配置失败 解决方法
  15. 红黑树 一张导图解决红黑树全部插入和删除问题 包含详细操作原理 情况对比
  16. Matlab如何多行添加注释和取消注释
  17. python 办公自动化 视频教程_Python自学爬虫/办公自动化视频教程
  18. 计算机路由器无线级联配置,不同品牌无线路由器 无线级联 配置案例
  19. react redux mysql_实现React-redux的基本功能
  20. 手机浏览器java_三款最热java手机浏览器横评(组图)

热门文章

  1. 上海GDD(谷歌开发者大会),第一天总结
  2. 提示overwrite是什么意思_Linux Shell 提示符#和$表示什么意思?
  3. 红旗Linux职称考试模块,计算机职称考试红旗Linux Desktop 6.0考试大纲
  4. php和dart交互,Flutter 之和原生交互
  5. android js模板下载地址,template.js
  6. 怎么判断间隙过渡过盈配合_圆柱销有2个标准,选型注意材料和热处理,特别是销孔的配合关系...
  7. python中home定义是什么_关于python中的module你需要了解的
  8. shell 执行qt生成文件_QT-窗口打印debug信息,本地日志保存,以及执行shell脚本并且把信息打印在窗口...
  9. Google Docs API 发布,自动化文档处理
  10. 怎么将windows上的文件传到Ubuntu