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 ...
随机推荐
- 网络流--Dinic(自用,勿看)
注意:这是一篇个人学习笔记,如果有人因为某些原因点了进来并且要看一下,请一定谨慎地阅读,因为可能存在各种奇怪的错误,如果有人发现错误请指出谢谢! https://www.luogu.org/probl ...
- Jasper_crosstab_group_dataset_Error incrementing crosstab dataset
Error detail: net.sf.jasperreports.engine.JRException: net.sf.jasperreports.engine.JRRuntimeExceptio ...
- sftp 常用命令 以及 以及与 scp 的比较
1.scp 不能容忍网络闪断,因此一旦出现网络闪断,那么scp 命令就会异常退出 sftp 可以容忍网络闪断,而且具备断电续传,因此sftp 适用于网络更慢的环境, 2. sftp 是一个交互式文件传 ...
- 灰度共生矩阵GLCM分析
纹理分析是对图像灰度(浓淡)空间分布模式的提取和分析.纹理分析在遥感图像.X射线照片.细胞图像判读和处理方面有广泛的应用.关于纹理,还没有一个统一的数学模型.它起源于表征纺织品表面性质的纹理概念,可以 ...
- Hibernate框架关系映射一对多双向关联
直入主题,首先大配置常规配置, 这里住要说关联关系,大配置不多少,而且jar包默认添加好,笔者用的是idea2016. 然后我们知道关联关系主要是在小配置添加节点来配置属性.个人认为关联映射,就是对应 ...
- 解决Unsupported major.minor version 51.0报错问题
问题产生原因:计算机环境变量的jdk版本与eclipse使用的jdk版本不一致 解决方法: 1.查看计算机环境变量的jdk版本 2.查看eclipse项目java compiler的方法:在项目点右键 ...
- (九)maven之聚合多模块
聚合项目 一些开源项目,都会把自己的源代码公开到github之类的网站上,我们通过下载其代码,在本地执行maven install,可以把代码编译成jar包安装到本地仓库.而一个项目通常有多个模块,比 ...
- JAVA初级必须要搞懂的事项(希望对新手有所帮助)
1 安装JDK=> (1,下载JDK,安装,一般目录为C:\Program Files\Java中:2,通过Dos命令测试JDK是否安装=>java –version命令查看 ...
- iview 验证 trigger: 'blur,change', 同时加两个,省的每次还想input 还是 select
iview 验证 trigger: 'blur,change', 同时加两个,省的每次还想input 还是 select dataRuleValidate: { name: [{ required: ...
- syslog(),closelog()与openlog()--日志操作函数 (1)
文章出处:http://blog.csdn.net/xx77009833/archive/2010/07/30/5776383.aspx 为了满足某些目的,进行日志记录是很有必要的. 在典型的 LIN ...