linux initramfs,Linux INITRAMFS 与 INITRD「建议收藏」

linux initramfs,Linux INITRAMFS 与 INITRD「建议收藏」initramfs文件生效的过程大致分为四步:第一步:Kernel首先要注册一个RAMFS文件系统类型(实际注册的类型名称是”ROOTFS”,后续我们可以看到它实际上就是”RAMFS”);第二步:然后加载(mount)一个空的rootfs文件系统,类型就是上面提到的RAMFS(ROOTFS);第三步:寻址initramfs文件“XXX.cpio.gz”并解压到已mount的rootfs文件系统中;…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

initramfs文件生效的过程大致分为四步:

第一步:Kernel首先要注册一个RAMFS文件系统类型(实际注册的类型名称是”ROOTFS”,后续我们可以看到它实际上就是”RAMFS”);

第二步:然后加载(mount)一个空的rootfs文件系统,类型就是上面提到的RAMFS(ROOTFS);

第三步:寻址initramfs文件“XXX.cpio.gz”并解压到已mount的rootfs文件系统中;

第四步:寻址用户空间的init,并执行init进程;

第一步和第二步的调用堆栈如下:

init/main.c: start_kernel() ->

fs/dcache.c: vfs_caches_init() ->

fs/namespace.c: mnt_init() {

// The last 2 lines

init_rootfs();

init_mount_tree();

}

在“fs/ramfs/inode.c: init_rootfs()”函数中,注册了”ROOTFS”文件系统类型。通过阅读inode.c源码,发现”ROOTFS”就是”RAMFS”,几乎没有区别。

在“fs/namespace.c: init_mount_tree()”函数中,加载了一个类型为ROOTFS的空root:

mnt

= do_kern_mount(“rootfs”, 0, “rootfs”, NULL);

//第一个rootfs引用文件系统类型ROOTFS,即RAMFS。第二个rootfs为mount entry。

第三步(寻址initramfs文件XXX.cpio.gz,并解压)的调用堆栈如下:

kernel/init/main.c: start_kernel() {

vfs_caches_init();

//

The last line

rest_init();

}

kernel/init/main.c: rest_init() {

kernel_thread(kernel_init, NULL,

CLONE_FS | CLONE_SIGHAND);

}

kernel/init/main.c: kernel_init() {

do_basic_setup();

}

kernel/init/main.c: rest_init() {

do_initcalls();

}

// OK

kernel/init/initramfs.c:populate_rootfs() {

// Decompress the .gz into

‘rootfs’

}

rootfs_initcall(populate_rootfs);

检查populate_rootfs做了什么,它通过__initramfs_start指针和__initramfs_end指针访问XXX.cpio.gz文件,调用函数unpack_to_rootfs函数把源文件解压到rootfs中。gunzip执行解压过程,do_name()/do_copy/do_symlink/do_XXX为解压过程回调函数,在这些do_XXX回调函数中,看到大量使用sys_open/sys_write/sys_XXX函数创建、读写、更改文件和目录及其权限。sys_open/sys_write/sys_read实际上是用户空间open/write/read函数系统调用的实现。

至此,一个完整的rootfs已在目标系统的内存中。

第四步(寻址并运行用户空间INIT进程)的调用堆栈:

init/main.c: kernel_init() {

// At the bottom lines

if (!ramdisk_execute_command)

ramdisk_execute_command = “/init”;

}

kernel/init/main.c: init_post() {

if (ramdisk_execute_command) {

run_init_process(ramdisk_execute_command);

}

}

kernel/init/main.c: run_init_process() {

kernel_execve(init_filename,

argv_init, envp_init);

}

也就是说,只要initramfs文件“XXX.cpio.gz”的根目录下有一个有效的init,或者一个对init有效的链接,Kernel就能启动这个rootfs。那假如说initramfs的rootfs为空(CONFIG_INITRAMFS_SOURCE没有配置或者指向不存在的位置),或者initramfs的rootfs没有有效的“/init”文件。则Kernel会解析commandline,尝试从MTD/UBI之类的NAND分区启动,或者启动INITRAMDISK,或者NFS启动(如果开启了此功能),其调用堆栈如下:

kernel/init/main.c: kernel_init() {

// …

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();

}

// …

}

kernel/init/do_mounts.c:

prepare_namespace() {

// …

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;

// …

mount_root() {

// …

mount_nfs_root();

// …

}

// …

}

再来总结一下INITRAMFS的特点:

lROOTFS和RAMFS文件系统在同一个源码文件“inode.c”中实现,他们基本一致,通过Kernel文档也能说明这一点。同时,这也应证了配置Kernel的时候为什么只需要配置’CONFIG_INITRAMFS_SOURCE’一个选项足也。

lROOTFS文件系统类型的注册,以及rootfs的加载,initramfs的解压加载过程,都是Kernel启动过程的默认行为,menuconfig中没有任何选项可以开关。

l实际上rootfs不仅为INITRAMFS提供服务,它还为INITRAMDISK的加载提供中转服务,这一过程后面会讲到。

linitramfs默认启动“/init”,请确保在那个位置有一个有效的init或者是链接。

linitramfs的处理总是优先于对commandLine中启动参数的处理,因此initramfs和commandline无关。当最终的zImage包含了一个有效的XXX.cpio.gz时,不管bootloader传给kernel什么样的commandline,Kernel都会从initramfs启动,比如:

bootargs=root=/dev/mtdblock5 rootfstype=yaffs2 init=/init

console=ttySAC0,115200

//即使当前mtdblock5有一个完整的yaffs2文件系统并且其’/init’也有效’.当前Kernel也会尝试优先启动initramfs。

bootargs=console=ttySAC0,115200

//即使没有指定root/rootfstype/init选项,当前kernel也会尝试自带的initramfs。

l当initramfs没有有效的root时,Kernel才会根据commandline的配置,尝试从mtd/ubi等NAND分区,或者是从ramdisk设备文件,或者是从nfs服务器加载root。

3. Kernel 2.4 armnommu平台对INITRAMDISK的处理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/169687.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 集成学习-stacking算法

    众所周知,集成学习算法,它将多个弱分类器集成起来,以达到较高的分类准确率。常见的集成学习方法:boosting bagging stacking今天主要讲stacking.Stacking的基本思想将个体学习器结合在一起的时候使用的方法叫做结合策略。对于分类问题,我们可以使用投票法来选择输出最多的类。对于回归问题,我们可以将分类器输出的结果求平均值。…

    2022年4月16日
    65
  • Traits技法[终于解决]

    扮演“特性萃取机”角色,萃取各个迭代器的特性(迭代器的相应类型)模板特例化:提供一份template定义式,而其本身仍为templatization通过classtemplatepartial

    2021年12月18日
    44
  • metrics小常识

    metrics小常识Metrics,我们听到的太多了,熟悉大数据系统的不可能没听说过metrics,当我们需要为某个系统某个服务做监控、做统计,就需要用到Metrics。举个例子,一个图片压缩服务:每秒钟的请求数是多少(TPS)?平均每个请求处理的时间?请求处理的最长耗时?等待处理的请求队列长度?又或者一个缓存服务:缓存的命中率?平均查询缓存的时间?基本上每一个服务、应用都需要

    2025年7月10日
    0
  • USART与UART的区别

    USART(universalsynchronousasynchronousreceiverandtransmitte):通用同步异步收发器USART是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。UART(universalasynchronousreceiverandtransmitter):通用异步收发器异步串行通信口(UART)就是我们在…

    2022年4月3日
    67
  • nginx负载均衡配置详解_负载均衡算法实现

    nginx负载均衡配置详解_负载均衡算法实现1.简单介绍负载均衡如果你的nginx服务器给2台web服务器做代理,负载均衡算法采用轮询,那么当你的一台机器web程序关闭造成web不能访问,那么nginx服务器分发请求还是会给这台不能访问的web服务器,如果这里的响应连接时间过长,就会导致客户端的页面一直在等待响应,对用户来说体验就打打折扣,这里我们怎么避免这样的情况发生呢。这里我配张图来说明下问题。如果负载均衡中其中web2发生这样的…

    2022年10月12日
    0
  • input元素的oninput事件和onchange事件

    input元素的oninput事件和onchange事件input元素的oninput事件和onchange事件1、input元素上绑定事件的三种方式:第一种:直接在元素标签上添加oninput属性,属性值为处理事件函数的调用<inputtype=”text”id=”input”oninput=”handleInput()”></input>functionhandleInput(){ //处理事件代码…

    2022年6月4日
    95

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号