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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java 单例模式实现的5种方式[通俗易懂]

    java 单例模式实现的5种方式[通俗易懂]第一种:饿汉式/***CreatedwithIntelliJIDEA.**@author:宸濯*Date:2021/08/188:21*Description:单例模式的设计(饿汉式)*1.构造方法私有化*2.在静态语句块实例化*3.提供调用实例对象的方法*4.空间换时间,不管有没有调用方法,实例都创建了*Version:V1.0*/publicclassSingletonOne{privatestatic

    2022年8月11日
  • python 写txt换行_python列表写入文件

    python 写txt换行_python列表写入文件将’w’ 改为’a’,是在文件后面写入,不替换原有文件然后 在你需要写入的数据前加上’\n’可实现换行,如图  

    2022年10月2日
  • MYsql 锁表解决办法

    MYsql 锁表解决办法MySQL锁表解决方法一、我的处理过程1、查进程,主要是查找被锁表的那个进程的IDSHOWPROCESSLIST;2、kill掉锁表的进程IDKILL 10866;//后面的数字即时进程的ID网上找了些资料,了解了一下,先分享一下:二、mysql的锁表问题SHOWPROCESSLIST查看数据库中表的状态,是否被锁;killid //杀掉被锁的表===================…

    2022年5月7日
  • rtcm1005报文解析_rtcm1021-1027参数

    rtcm1005报文解析_rtcm1021-1027参数defparse_rtcm1005(rtcm1005):message_num=get_bin_para(rtcm1005[0:12],False,1,0)#协议idstation_id=get_bin_para(rtcm1005[12:24],False,1,0)#基站iditrf_year=get_bin_para(rtcm1005[24:30],False,1,0)#ITRF纪元22222gps_indicat.

    2022年11月2日
  • java mencoder_mencoder java linux[通俗易懂]

    java mencoder_mencoder java linux[通俗易懂]在执行转化的时候只能转化1分钟的影片超过1分钟影片的都不能转化。可是直接输入命令行又能全部转化。高分求解try{Runtimert=Runtime.getRuntime();Processproc=rt.exec(“mencoder”+ol…在执行转化的时候只能转化1分钟的影片超过1分钟影片的都不能转化。可是直接输入命令行又能全部转化。高分求解try{Runtimert=Runtime….

    2022年11月3日
  • c# 字符串转时间的方式

    c# 字符串转时间的方式**第一种方法**stringtimeStr=”2019-08-28″;DateTimetime=Convert.ToDateTime(timeStr);**第二种:**DateTimeFormatInfotimeForInfo=newDateTimeFormatInfo();timeForInfo.ShortDatePattern=”yyyy/MM/dd”;stringtimeStr1=”2018-09-08″;vartime=Convert.

    2022年5月5日

发表回复

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

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