引言:根文件系统的noinitramfs已经分析,继续上文未完的initramfs和Android根文件系统分析,这两者有什么关系?

1.initramfs、initrd

对于initramfs,kernel 2.5开始引入,其实质是在内核镜像中附加一个cpio包(cpio一个用于备份、还原的工具,主要用于cpio和tar文件,其实质是文件、目录、节点的描述语言包),在该cpio包中包含了一个小型的文件系统。当内核启动时,会尝试解开这人 cpio包,并且将其中包含的文件系统安装到rootfs中,内核中的一部分初始化代码会放到这个文件系统中,一般为用户空间的init进程。
initamfs的引入可以精简内核的初始化代码,同时是为了更方便地定制内核的初始化过程。这种方式的rootfs是包含在kernel image(即bootimage或secbootimage)之中的。

先看下initramfs的初始化代码:

static int __init populate_rootfs(void)
{char *err = unpack_to_rootfs(__initramfs_start,__initramfs_end - __initramfs_start, 0);
#ifdef CONFIG_BLK_DEV_RAMif (initrd_start) {err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start, 1);if (!err) {printk(" it is\n");unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start, 0);free_initrd();return 0;}printk("it isn't (%s); looks like an initrd\n", err);fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);if (fd >= 0) {sys_write(fd, (char *)initrd_start,initrd_end - initrd_start);sys_close(fd);free_initrd();}
#elseprintk(KERN_INFO "Unpacking initramfs...");err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start, 0);if (err)panic(err);printk(" done\n");free_initrd();
#endif}return 0;
}
rootfs_initcall(populate_rootfs);

根据前文分析,populate_rootfs将会在kernel_init中被调用,主要功能集中在static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)函数中,该函数根据check_only这一参数来确定解压cpio包或者检查是否为cpio包。
其具体实现过程为:

static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) {dry_run = check_only;state = Start;written = write_buffer(buf, len);
}static int __init write_buffer(char *buf, unsigned len) {while (!actions[state]());return len - count;
}static __initdata int (*actions[])(void) = {[Start]     = do_start,[GotHeader] = do_header,
};
static int __init do_start(void) {read_into(header_buf, 110, GotHeader);return 0;
}
static int __init do_header(void) {if (dry_run) {read_into(name_buf, N_ALIGN(name_len), GotName);return 0;}
}

以上函数可以看到如果dry_run为1,即check_only为1时,只做检查是否为cpio包。
继续分析populate_rootfs流程,这里根据宏CONFIG_BLK_DEV_RAM涉及到两种文件包:initramfs和initrd,两者的特点如下:
对于initramfs:

  • cpio-initramfs格式
  • ram filesystem支持
  • 编译时与内核链接成一个文件,链接地址为__initramfs_start
  • 由bootloader加载到内存中,解压后所占空间(__initramfs_end- __initramfs_start)会保留
  • 可以不依赖ram disk
  • 使用方便,不需要额外挂载文件系统,但体积稍大
  • 一般需要有/init可执行文件

对于initrd:

  • 可以是cpio-initrd格式,也可以是image-initrd格式
  • ram filesystem支持
  • 单独编译生成一个文件
  • 由bootloader单独加载到内存中,不在内核镜像地址空间
  • 通过”initrd=initns”命令,可以找到 initrd
  • initrd处理后的空间内存可以被释放
  • initrd是ramdisk镜像文件,必须配置CONFIG_BLK_DEV_RAM支持ram disk
  • 需要配置ram disk分区大小,默认4MB
  • 需要ex2等文件系统驱动支持
  • 需要传入根文件系统地址、大小(与ramdisk大小一致)、ramdisk设备节点

2.解压initramfs、initrd文件

对于这几种格式的文件,populate_rootfs进行了不同处理,主要逻辑为:
1)解压initramfs到根文件系统下,如果initramfs不存在,__initramfs_start和__initramfs_end的值相等,即参数 len=0,unpack_to_rootfs不会做任何处理。
2)对于cpio-initrd,直接将其解压到根目录。
3)对于image-initrd,将其解压成/initrd.image。

处理完成后回到kernel_init中:

static int __init kernel_init(void * unused)
{do_basic_setup();/** check if there is an early userspace init.  If yes, let it* do all the work*/if (!ramdisk_execute_command)ramdisk_execute_command = "/init";if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {ramdisk_execute_command = NULL;prepare_namespace();}init_post();

对于initramfs和cpio-initrd的情况,如果虚拟文件系统中存在ramdisk_execute_command指定的文件:
(该文件由cmdline传递,如cmdline=”initrd=0x31000000,0x200000 root=/dev/ram rw init=/linuxrc console=ttySAC0 mem=64M”)
则直接转向init_post()来执行,否则执行函数prepare_namespace()。

在init_post()中,会执行传入的ramdisk_execute_command,所以该文件必须是一个可执行文件,在Android系统中为用户空间的init进程,也可以为init.sh shell脚本。此后,会切换到实际根目录文件系统,后边分析Android的init进程时也加以说明。
run_init_process(ramdisk_execute_command);

如果为image-initrd的情况,会调用 prepare_namespace

/** Prepare the namespace - decide what/where to mount, load ramdisks, etc.*/
void __init prepare_namespace(void)
{int is_floppy;if (root_delay) {printk(KERN_INFO "Waiting %dsec before mounting root device...\n",root_delay);ssleep(root_delay);}/** wait for the known devices to complete their probing** Note: this is a potential source of long boot delays.* For example, it is not atypical to wait 5 seconds here* for the touchpad of a laptop to initialize.*/wait_for_device_probe();md_run_setup();if (saved_root_name[0]) {root_device_name = saved_root_name;if (!strncmp(root_device_name, "mtd", 3) ||!strncmp(root_device_name, "ubi", 3)) {mount_block_root(root_device_name, root_mountflags);goto out;}ROOT_DEV = name_to_dev_t(root_device_name);if (strncmp(root_device_name, "/dev/", 5) == 0)root_device_name += 5;}if (initrd_load())goto out;/* wait for any asynchronous scanning to complete */if ((ROOT_DEV == 0) && root_wait) {printk(KERN_INFO "Waiting for root device %s...\n",saved_root_name);while (driver_probe_done() != 0 ||(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)msleep(100);async_synchronize_full();}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (is_floppy && rd_doload && rd_load_disk(0))ROOT_DEV = Root_RAM0;mount_root();
out:sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".");
}

这段代码有不少注释供理解,总体思路为:
等待/dev下的块设备驱动注册完毕,该设备由cmdline指定,然后提取image-initrd虚拟根文件系统VFS到根目录下,然后挂载根文件系统的设备到/root,并将真实根文件系统顶层目录移动到/目录下,最后将当前目录作为根目录,这样就从虚拟根文件系统切换到真实的根文件系统。
疑问1:那虚拟的根文件系统还存在吗?
疑问2:如何访问image-initrd这个文件内容?
对于问题2,需要查看代码rd_load_image("/initrd.image"),这里会将initrd.image的内容写入”/dev/ram”,如果/真实根文件系统配置为/dev/ram的话,则直接使用initrd作为真实根文件系统。
对于问题1,答案是存在,内核用/old和old_fd保存了虚拟根文件系统的切换环境。

好了,关于VRFS和RRFS就梳理到这儿,当然还有许多细节值得推敲,这里提到了关于Android根文件系统,也开始慢慢切入正题。

虚拟根文件系统与真实根文件系统相关推荐

  1. 文件系统-- 安装根文件系统阶段(安装rootfs文件系统)

    文件系统注册了之后,当我们需要使用的时候,就可以挂载了. 在安装普通文件系统之前,必须先挂载根文件系统.根文件系统首先是一种文件系统,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所mou ...

  2. go移植linux内核书名叫啥,嵌入式 Linux根文件系统移植之Linux文件系统简介-Go语言中文社区...

    学号:16020311003    姓名:杨虎成 [嵌牛导读]Linux支持多种文件系统,文件系统接口实现为分层的体系结构,将用户接口层.文件系统实现和操作存储设备的驱动程序分隔开 [嵌牛鼻子]Lin ...

  3. Linux虚拟文件系统:数据结构与文件系统注册、文件打开读写

    数据结构 超级块 - super_block 索引节点 - inode 目录项 - dentry 文件结构 - file 虚拟文件系统实现 注册文件系统 - register_filesystem 打 ...

  4. linux虚拟文件系统(四)-文件系统挂载操作分析

    ext4文件系统挂载 大家可以使用以下命令挂载一个u盘到 /mnt目录下: mount -t ext4 /dev/sda1 /mnt 其中mount这个应用程序就是使用了mount函数进行系统调用,其 ...

  5. html访问手机文件系统,eMMC真能优化成UFS?谈谈手机闪存的文件系统

    1文件系统有啥用? [PConline 资讯]最近,由于某些手机混用eMMC和UFS闪存,因此关于手机储存器的话题,关注度一下子飙高.和UFS闪存相比,eMMC的性能更弱,同一型号的手机混用这两种规格 ...

  6. linux虚拟文件系统(一)-文件系统架构

    文件系统层次分析 由上而下主要分为用户层.VFS层.文件系统层.缓存层.块设备层.磁盘驱动层.磁盘物理层 用户层:最上面用户层就是我们日常使用的各种程序,需要的接口主要是文件的创建.删除.打开.关闭. ...

  7. Linux文件系统(一)文件系统基本概念

    文件系统基本概念 1.文件系统概述 2.文件系统的类型 (1)ext系列 (2)Reiserfs 3. Ubuntu文件系统的结构 (1)概述 (2)路径 (3)主要文件夹及其作用 /bin/ /sb ...

  8. linux裸设备文件系统,Linux当中的文件系统

    1. 设备专用文件(设备文件) 设备专用文件与系统的某个设备相对应.在内核中,每种设备类型都有阈值向对应的设备驱动程序,用来处理设备的所有I/O请求.可以将设备划分为字符设备和块设备两种. 每个设备文 ...

  9. linux卸载文件系统什么意思,Linux文件系统的安装和卸载

    本文介绍Linux文件系统的安装和卸载如何控制,以及当中需要了解的原理和注意事项.阅读本文之后,您将会了解如何安装您的 Linux 文件系统:配置和使用可移动 USB.IEE 1394 或其他设备:正 ...

最新文章

  1. 分享:Hadoop的Python框架指南
  2. USB-Flash MX-程序员2004合订本
  3. f12控制台如何查看consul_Consul初探-从安装到运行
  4. SAP License审计说明及合并
  5. CommunityServer 2.0 RTM时间是:2006-02-17 --Scott Watermasysk今天中午
  6. C# 操作office知识点汇总
  7. 捷克 签证_一位捷克开发人员构建了可在您的浏览器中直接运行的语音合成器
  8. java I O类大全_Java I/O最简单的几个类
  9. 有三角形的即时通讯源码?
  10. Kaggle新赛 | 医学影像插管分类,总奖池 5 万美金
  11. 三星如何抄袭苹果 产品对比一目了然
  12. 电脑硬件检测_硬盘检测工具哪个好?在win10中这样检查磁盘健康状态就对了
  13. 【FFMPEG系列】之查看FFMPEG版本号
  14. 2019 年一千多万条数据遭泄露!
  15. 2014年国际IT外包10大事件
  16. [JAVA]预面试笔记
  17. python3实现国密SM4算法
  18. 步进电机之步进电机驱动器使用说明
  19. erdas几何校正_遥感图像的几何校正
  20. Websphere 学习(二)

热门文章

  1. 执行svn sync命令做svn同步时遇到Failed to get lock on destination repos, currently held by ...错误
  2. vue前端UI框架,一点都不圆润,盘它!
  3. 互联网企业做手机吃“软”饭:靠应用服务谋利
  4. JAVA开发面试题_网络_操作系统_JAVA基础_JVM虚拟机
  5. el-dialog的坑
  6. NSString使用stringWithFormat拼接
  7. Silver Cow Party (POJ - 3268 )
  8. apache限制下载文件大小
  9. 成佩涛——iPviking:在线黑客攻击可视化地图
  10. 你知道这些游戏配音软件吗