rootfs注册挂载过程分析
参考: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注册挂载过程分析的更多相关文章
- 从linux启动到rootfs的挂载分析
简单的来说,根文件系统包括虚拟根文件系统和真实根文件系统.在Kernel启动的初始阶段,首先去创建虚拟的根文件系统,接下来再去调用do_mount来加载真正的文件系统,并将根文件系统切换到真正的文件系 ...
- Linux--根文件系统的挂载过程分析
前言: 本篇文章以S3C6410公版的Linux BSP和U-Boot来进行分析,文中全部提及的名词和数据都是以该环境为例,全部的代码流程也是以该环境为例来进行分析.哈哈.假设有不对或者不完好的地方, ...
- tiny4412 busybox制作根文件系统rootfs nfs 挂载 ubuntu 14.04
http://blog.csdn.net/liudijiang/article/details/50555429(转) 首先得要有制作好的uboot和linux内核镜像zImage,先烧录到sd卡里, ...
- 文件系统的挂载(2)---挂载rootfs文件系统
一.目的 本文主要讲述linux内核rootfs文件系统的挂载过程,内核版本为3.10. rootfs是基于内存的文件系统,没有实际的存储设备,所有操作都在内存中完成.为了保证linux内核的精简性, ...
- linux文件系统初始化过程(2)---挂载rootfs文件系统
一.目的 本文主要讲述linux3.10文件系统初始化过程的第一阶段:挂载rootfs文件系统. rootfs是基于内存的文件系统,所有操作都在内存中完成:也没有实际的存储设备,所以不需要设备驱动程序 ...
- linux根文件系统的挂载过程详解
一:前言 前段时间在编译kernel的时候发现rootfs挂载不上.相同的root选项设置旧版的image却可以.为了彻底解决这个问题.研究了一下rootfs的挂载过程.特总结如下,希望能给这部份知识 ...
- create rootfs.img using loop device
reference: https://www.thegeekdiary.com/how-to-create-virtual-block-device-loop-device-filesystem-in ...
- 使用jquery的on方法注册事件遇到的坑
1,使用on注册事件 $(selector).on(event,childSelector,data,function) 2,$(selector)中的selector可以是document,那么意味 ...
- Aufs与Devicemapper的关系
Aufs与Devicemapper的应用 Aufs是Docker最初采用的文件系统,由于Aufs未能加入到Linux内核,考虑到兼容性问题,加入了Devicemapper的支持.目前,除少数版本如Ub ...
随机推荐
- Codeforces 1139F(树状数组+扫描线)
题目传送 做法 对于每个人,inc为x,pref为y:对于每道菜,p和s为x,b为y 于是根据题意有\[p[i]<=x<=s[i]\]\[p[i]+b[i]<=x+y\]\[p[i] ...
- 120 Triangle 三角形最小路径和
给出一个三角形(数据数组),找出从上往下的最小路径和.每一步只能移动到下一行中的相邻结点上.比如,给你如下三角形:[ [2], [3,4], [6,5,7], [4,1,8,3]] ...
- Azkaban是什么?(一)
不多说,直接上干货! http://www.cnblogs.com/zlslch/category/938837.html Azkaban是什么? Azkaban是一套简单的任务调度服务,整体包括三 ...
- js 打开新窗口
以前老是用window.open方法打开浏览器新窗口,但是有的浏览器会阻止打开新窗口,一劳永逸的方式是通过js伪造a标签请求打开新窗口,代码如下: var atag = document.create ...
- 在Window上用cmd创建.htaccess文件
Windows 图形下不能直接建立空名字的文件,所以没法直接创建.htaccess文件,不过可以通过命令行创建: cd /path/to/your/dir/ type nul>.htaccess ...
- Sublime Text 3安装AngularJS插件
Sublime Text 3是目前笔者用过的最好用的代码编辑器之一,界面如下图所示: 我们可以用该编辑器开发AngularJS应用,首先需要安装AngularJS提示插件. 需要以下几步: 1.安装P ...
- Android中的ListView属性使用总结
Android中使用ListView控件比较常见,如果能知道常用的一些属性使用,肯定会少很多坑. 1.ListView是常用的显示控件,默认背景是和系统窗口一样的透明色,如果给ListView加上背景 ...
- android 日期 时间
/** * 给定一个日期型字符串,返回加减n天后的日期型字符串 * * @param basicDate * @param nDays * @return */ public static Strin ...
- java 序列化Serializable 详解
Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是 ...
- (三)mybatis之对Hibernate初了解
前言:为什么会写Hibernate呢?因为HIbernate跟Mybatis一样,是以ORM模型为核心思想的,但是这两者有相似的地方也有差异的地方.通过这两种框架的比对,可以对mybatis有着更深的 ...