参考:Linux Filesystem: 解析 Linux 中的 VFS 文件系统机制

主要代码,

init_rootfs();
init_mount_tree();

1.init_rootfs()解析

init_rootfs()
-->bdi_init(&ramfs_backing_dev_info);
/*
注册过程实际上将表示各实际文件系统的 struct file_system_type 数据结构的实例化,
将rootfs_fs_type加入到static struct file_system_type *file_systems为首的单链表。
*/
-->register_filesystem(&rootfs_fs_type);

struct backing_dev_info结构是显示设备信息的描述符,定义如下:

static struct backing_dev_info ramfs_backing_dev_info = {
.ra_pages = , /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK |
BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
};

2.init_mount_tree()解析

init_mount_tree() 这个函数为 VFS 建立了根目录 "/"

init_mount_tree()
-->struct vfsmount *mnt = do_kern_mount("rootfs", , "rootfs", NULL);
/*
1.根据“rootfs”在static struct file_system_type *file_systems链表中
找到代表文件系统的file_system_type结构体
*/
-->struct file_system_type *type = get_fs_type("rootfs");
-->struct vfsmount *mnt = vfs_kern_mount(type, , "rootfs", NULL);
/*2.从mnt_cache缓存分配vfsmount结构体并初始化*/
-->struct vfsmount *mnt = alloc_vfsmnt(name);
-->type->get_sb(type, , "rootfs", NULL, mnt);
即rootfs_get_sb(type, , "rootfs", NULL, mnt);
-->get_sb_nodev(type, MS_NOUSER, NULL, ramfs_fill_super,mnt);
-->struct super_block *s = sget(type, NULL, set_anon_super, NULL);
/*2.分配并初始化super_block结构体*/
-->struct super_block *s = alloc_super(type);
-->set(s, NULL);
即set_anon_super(s,NULL)
/*设置super_block结构体的s_dev成员*/
-->s->s_dev = MKDEV(, dev & MINORMASK);
-->s->s_type = type;
-->strlcpy(s->s_id, type->name, sizeof(s->s_id));
/*系统中所有的super_block结构体都连接到super_blocks为首的list_head链表*/
-->list_add_tail(&s->s_list, &super_blocks);
/*属于file_system_type指定文件系统的super_block结构体都连接到type->fs_supers链表*/
-->list_add(&s->s_instances, &type->fs_supers);
-->s->s_flags = MS_NOUSER;
-->fill_super(s, NULL, )
即ramfs_fill_super(s, NULL, )
-->sb->s_op = &ramfs_ops;
/*3.分配inode结构体并初始化*/
-->struct inode *inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, );
-->struct inode * inode = new_inode(sb);
-->设置inode成员
/*4.分配dentry并初始化,“/”*/
-->struct dentry *root = d_alloc_root(inode);
-->static const struct qstr name = { .name = "/", .len = }
-->struct dentry *res = d_alloc(NULL, &name);
-->res->d_sb = inode->i_sb;
-->res->d_parent = res;
-->d_instantiate(res, inode);
-->list_add(&res->d_alias, &inode->i_dentry);
-->res->d_inode = inode;
-->s->s_flags |= MS_ACTIVE;
-->simple_set_mnt(mnt, s);
-->mnt->mnt_sb = s;
-->mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
/*
为系统最开始的进程(即 init_task 进程)准备它的进程数据块中的namespace 域,
主要目的是将 do_kern_mount() 函数中建立的 mnt 和 dentry 信息记录在了 init_task 进程的进程数据块中,
这样所有以后从 init_task 进程 fork 出来的进程也都先天地继承了这一信息
*/
-->struct mnt_namespace *ns = kmalloc(sizeof(*ns), GFP_KERNEL);
-->list_add(&mnt->mnt_list, &ns->list);
-->ns->root = mnt;
-->mnt->mnt_ns = ns;
-->struct path root.mnt = ns->root;
struct path root.dentry = ns->root->mnt_root;
-->set_fs_pwd(current->fs, &root);
set_fs_root(current->fs, &root);

3.在根目录下增加目录

Linux 下用系统调用 sys_mkdir 来在 VFS 目录树中增加新的节点。为配合路径搜索,引入了下面一个数据结构:

struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};
/*
这个数据结构在路径搜索的过程中用来记录相关信息,起着类似"路标"的作用
其中前path.dentry记录的是要建目录的父目录的信息
last,flags,last_type三项记录的是所查找路径的最后一个节点(即待建目录或文件)的信息。
*/
struct nameidata {
struct path path;
struct qstr last;
unsigned int flags;
int last_type;
unsigned depth;
char *saved_names[MAX_NESTED_LINKS + ]; /* Intent data */
union {
struct open_intent open;
} intent;
};

4.在 VFS 树中挂载文件系统

这一过程可简单描述为:将某一设备(dev_name)上某一文件系统(file_system_type)安装到VFS目录树上的某一安装点(dir_name)。它要解决的问题是:将对 VFS 目录树中某一目录的操作转化为具体安装到其上的实际文件系统的对应操作。

比如说,如果将 hda2 上的根文件系统(假设文件系统类型为 ext2)安装到 "/dev" 目录上(此时,"/dev" 目录就成为了安装点),那么安装成功之后应达到这样的目的,即:对 VFS 文件系统的 "/dev" 目录执行 "ls" 指令,该条指令应能列出 hda2 上 ext2 文件系统的根目录下所有的目录和文件。

记住:对目录或文件的操作将最终由目录或文件所对应的 inode 结构中的 i_op 和 i_fop 所指向的函数表中对应的函数来执行。所以,不管最终解决方案如何,都可以设想必然要通过将对 "/dev" 目录所对应的 inode 中 i_op 和 i_fop 的调用转换到hda2 上根文件系统 ext2 中根目录所对应的 inode 中 i_op 和 i_fop 的操作。

初始过程由 sys_mount() 系统调用函数发起,该函数原型声明如下:
long sys_mount(char * dev_name, char * dir_name, char * type,unsigned long flags, void * data);
参数 char *type 为标识将要安装的文件系统类型字符串,对于 ext2 文件系统而言,就是"ext2"。

为了更好地理解这一过程,用一个具体的例子来说明:我们准备将来自主硬盘第 2 分区(hda2)上的 ext2 文件系统安装到前面创建的 "/dev" 目录中。那么对于 sys_mount() 函数的调用便具体为:

sys_mount("hda2","/dev ","ext2",…)
/*
将来自用户内存空间(user space)的参数拷贝到内核空间后,
便调用 do_mount() 函数开始真正的安装文件系统的工作
*/
-->do_mount()
-->/*调用 path_lookup() 函数来得到安装点的相关信息,
如同创建目录过程中叙述的那样,该安装点的信息最终记录在 struct nameidata 类型的一个变量当中,
为叙述方便,记该变量为nd
*/
/*调用 do_add_mount() 函数来向 VFS 树中安装点 "/dev " 安装一个实际的文件系统。*/
-->do_add_mount()
/*建立一新的安装区域块*/
-->do_kern_mount()
-->graft_tree()
-->将 do_kern_mount() 函数返回的一 struct vfsmount 类型的变量加入到安装系统链表中
-->将新分配的 struct vfsmount 类型的变量加入到一个hash表中

rootfs注册挂载过程分析的更多相关文章

  1. 从linux启动到rootfs的挂载分析

    简单的来说,根文件系统包括虚拟根文件系统和真实根文件系统.在Kernel启动的初始阶段,首先去创建虚拟的根文件系统,接下来再去调用do_mount来加载真正的文件系统,并将根文件系统切换到真正的文件系 ...

  2. Linux--根文件系统的挂载过程分析

    前言: 本篇文章以S3C6410公版的Linux BSP和U-Boot来进行分析,文中全部提及的名词和数据都是以该环境为例,全部的代码流程也是以该环境为例来进行分析.哈哈.假设有不对或者不完好的地方, ...

  3. tiny4412 busybox制作根文件系统rootfs nfs 挂载 ubuntu 14.04

    http://blog.csdn.net/liudijiang/article/details/50555429(转) 首先得要有制作好的uboot和linux内核镜像zImage,先烧录到sd卡里, ...

  4. 文件系统的挂载(2)---挂载rootfs文件系统

    一.目的 本文主要讲述linux内核rootfs文件系统的挂载过程,内核版本为3.10. rootfs是基于内存的文件系统,没有实际的存储设备,所有操作都在内存中完成.为了保证linux内核的精简性, ...

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

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

  6. linux根文件系统的挂载过程详解

    一:前言 前段时间在编译kernel的时候发现rootfs挂载不上.相同的root选项设置旧版的image却可以.为了彻底解决这个问题.研究了一下rootfs的挂载过程.特总结如下,希望能给这部份知识 ...

  7. create rootfs.img using loop device

    reference: https://www.thegeekdiary.com/how-to-create-virtual-block-device-loop-device-filesystem-in ...

  8. 使用jquery的on方法注册事件遇到的坑

    1,使用on注册事件 $(selector).on(event,childSelector,data,function) 2,$(selector)中的selector可以是document,那么意味 ...

  9. Aufs与Devicemapper的关系

    Aufs与Devicemapper的应用 Aufs是Docker最初采用的文件系统,由于Aufs未能加入到Linux内核,考虑到兼容性问题,加入了Devicemapper的支持.目前,除少数版本如Ub ...

随机推荐

  1. [软件工程基础]2017.11.01 第五次 Scrum 会议

    具体事项 燃尽图 每人工作内容 成员 已完成的工作 计划完成的工作 工作中遇到的困难 游心 #8 掌握 Laravel 框架 #10 搭建可用的开发测试环境:#9 阅读分析 PhyLab 后端代码与文 ...

  2. asp.net mvc 中使用 iframe 加载相应的静态html页面进行显示

     <iframe src='<%=ResolveUrl("~/Content/HTML_file/Agreement.html")%>' <%@ Page ...

  3. 访问者模式和php实现

    访问者模式: 表示作用于某个对象结构中的各个元素的操作.它使你可以在不改变各个元素类的前提下定义作用于这些元素的操作. 角色: 1)抽象访问者:为该对象结构中具体元素角色声明一个访问操作接口.该操作接 ...

  4. HDU4405 Aeroplane chess(期望dp)

    题意 抄袭自https://www.cnblogs.com/Paul-Guderian/p/7624039.html 正在玩飞行棋.输入n,m表示飞行棋有n个格子,有m个飞行点,然后输入m对u,v表示 ...

  5. 从零开始利用vue-cli搭建简单音乐网站(三)

    1.利用router-link在组件之间传递数据 如上图,MainPage.vue中主要有8个推荐曲目数据,主要实现方式是建立好主页面模板,然后用v-for循环获取返回的music对象,然后分别绑定曲 ...

  6. 倒计时器 CountDownTimer

    使用介绍 开发中经常会遇到一些和倒计时有关的场景,比如发送验证码的按钮,会在点击发送后,显示倒计时间,倒计时结束后才能够刷新按钮,再次允许点击.为了不阻塞软件的运行,又要实时刷新界面,我们通常会用到 ...

  7. COGS 2280. [HZOI 2015]树白黑

    ★★   输入文件:B_Tree.in   输出文件:B_Tree.out   简单对比时间限制:2 s   内存限制:512 MB [题目描述] 给定一棵有根树,树根为1,一开始这棵树所有节点均为白 ...

  8. vijos 1524 最小监视代价

    背景 看到Vijos上此类型的题目较少,特地放一道上来给大家练练. 描述 由于yxy小朋友做了一些不该做的事,他被jzp关进了一个迷宫里.由于jzp最近比较忙,疏忽大意了一些,yxy可以在迷宫中任意走 ...

  9. DataModel doesn't have preference values

    mahout和hadoop实现简单的智能推荐系统的时候,出现了一下几个方面的错误 DataModel doesn't have preference values 意思是DataModel中没有找到初 ...

  10. 玄学C语言之scanf,printf

    #include <bits/stdc++.h> using namespace std; int main() { int a,c,d; ]; scanf("%d." ...