initramfs详解-----初识initramfs

2023-05-16

为什么需要initramfs

在Linux内核被加载到内存并运行后,内核进程最终需要切换到用户太的进程来使用计算机,而用户进程又存在于外存储设备上,比如systemd进程,通常systemd进程所在的存储设备也是Linux真正的根文件系统所在的位置,我们知道内核源码是没有包含驱动程序的,驱动程序在外存储设备上,那么问题来了,要切换到systemd进程,就需要外存储的驱动,但是没有驱动又没办法访问外存储,这就进入先有鸡还是先有蛋的问题了(那到底是先有鸡还是先有蛋呢:)),这个时候initramfs就闪亮登场了。

为什么不将所有驱动都写入内核而要用initramfs

        第一,除非是一个专用系统,目标系统的硬件平台是固定不变的,否则,对于一个通用操作系统,比如Linux的桌面发行版,将运行在各种不同的硬件平台上。因此,根文件系统可能存储在各种各样的介质上,比如IDE硬盘、SATA硬盘、SCSI硬盘、Flash存储器,以及随着技术的发展,不断出现的新的存储设备。为了能够兼容更多的硬件平台,显然系统需要支持尽可能多的存储设备。但是如果将所有这些设备的驱动全部编译进内核,显然不是一个好办法。因为对于某个特定的硬件平台,可能只需要一个驱动即可,内核中的其他驱动根本用不上,将它们编译进内核只会徒增内核的尺寸、占用内存空间,尤其对于一些内存或者存储介质空间有限的设备,这个问题尤为明显。于是将这些驱动编译为模块,存储在根文件系统中,按需载入内存是一个解决问题的办法。

        第二,根文件系统可能不在一个简单的硬盘上,比如当使用磁盘阵列RAID时,根文件系统可能横跨几个存储设备,或者根文件系统在某个网络设备上。以使用NFS挂载根文件系统为例,除了要支持网卡驱动外,还要进行网络配置,甚至还要进行网络认证。某些根文件系统经过压缩、加密,在挂载前需要解压缩、解密等操作。如果这些都由内核处理,将会使内核变得异常复杂,继而可能导致内核的稳定性、可靠性、灵活性等一系列的问题。因此,将复杂的操作移到用户空间是解决上述问题的一个思路。

        为了解决上述问题,内核开发者们设计了initramfs机制。initramfs是一个临时的文件系统,其中包含了必要的设备如硬盘、网卡、文件系统等的驱动以及加载驱动的工具及其运行环境,比如基本的C库,动态库的链接加载器等等。同时,那些处理根文件系统在RAID、网络设备上的程序也存放在initramfs中。由第三方程序(如Bootloader)负责将initramfs从硬盘装载进内存。bootloader如何将内核与initramfs载入内存,敬请期待,写好后我将连接放到此处

        以驱动硬盘为例,内核就不必再从硬盘,而是从已经加载到内存的initramfs中获取硬盘控制器等相关驱动了,继而可以驱动硬盘,访问硬盘上的根文件系统,从而解决了前面提到的鸡和蛋的矛盾。

        在初始化的最后,内核运行initramfs中的init程序,该程序将探测硬件设备、加载驱动,挂载真正的文件系统,执行文件系统上的/sbin/init,进而切换到真正的用户空间。真正的文件系统挂载后,initramfs即完成了使命,其占用的内存也会被释放。

initramfs原理

在讲解initramfs之前,先介绍initramfs的一个前辈initrd

        在2.4以及更早版本的内核中,内核使用的是initrd。initrd是基于ramdisk技术的,而ramdisk就是一个基于内存的块设备,因此initrd也具有块设备的一切属性。比如initrd容量是固定的,一旦创建initrd时设定了一个大小,就不能再进行动态调整。而且,如同块设备一样,initrd 需要按照一定的文件系统格式进行组织,因此制作initrd时需要使用如mke2fs这样的工具“格式化”initrd,访问initrd时需要通过文件系统驱动。更重要的是,虽然initrd是一个伪块设备,但是从内核的角度看,其与真实的块设备并无区别,因此,内核访问initrd也需使用缓存机制,显然这是多此一举的,因为本身initrd就在内存中。

由于initrd太拉胯,于是initram呼之欲出

        鉴于ramdisk机制的种种限制,Linus Torvalds提出了一个想法:能否将cache当作一个文件系统直接挂载使用?基于这个想法,Linus Torvalds基于已有的缓存机制实现了ramfs。ramfs与ramdisk有着本质的区别,ramdisk本质上是基于内存的一个块设备,而ramfs是基于缓存的一个文件系统。因此,ramfs去除了前述块设备的一些限制。比如,ramfs根据其中包含的文件大小可自由伸缩;增加文件时,自动分配内存;删除文件时,自动释放内存。更重要的是,ramfs是基于已有的缓存机制,因此不必再像ramdisk那样需要和缓存之间进行多余的复制一环。

伴随着ramfs的出现,从2.6开始,内核开发人员基于ramfs开发了initramfs替代initrd。那么initramfs是怎样工作的呢?

        当2.6版本的内核引导时,在挂载真正的根文件系统之前,首先将挂载一个名为rootfs的文件系统,并将rootfs的根作为虚拟文件系统目录树的总根。那么为什么要使用rootfs这么一个中间过程呢?原因之一还是为了解决鸡和蛋的问题。内核需要根文件系统上的驱动以及程序来驱动和挂载根文件系统,但是这些驱动和程序有可能没有编译进内核,而在根文件系统上。如果不借助第三方,内核是没有办法挂载真正的根文件系统的。而rootfs虽然名称为rootfs,但是并不是什么新的文件系统,事实上,rootfs就是一个ramfs只不过换了一个名称。换句话说,rootfs是在内存中的,内核不需要特殊的驱动就可以挂载rootfs,所以内核使用rootfs作为一个过渡的桥梁。

        在挂载了rootfs后,内核将Bootloader加载到内存中的initramfs中打包的文件解压到rootfs中,而这些文件中包含了驱动以及挂载真正的根文件系统的工具,内核通过加载这些驱动、使用这些工具,实现了挂载真正的根文件系统。此后,rootfs也完成了历史使命,被真正的根文件系统覆盖(overmount)。但是rootfs作为虚拟文件系统目录树的总根,并不能被卸载。但是这没有关系,前面我们已经谈到了,rootfs基于ramfs,删除其中的文件即可释放其占用的空间。

1、挂载rootfs

        用于不同操作系统的文件系统其物理存储结构是不同的,但是Linux的虚拟文件系统通过为这些文件系统建立中间适配层,实现了Linux对各个文件系统的支持,Linux的虚拟文件系统将文件系统组织为树形结构。在初始化阶段,内核挂载rootfs文件系统,虚拟文件系统从无到有,rootfs的根作为虚拟文件系统这棵大树中的第一个节点,自然成为所有后来创建的节点的祖先。也就是说,虚拟文件系统目录树的根就是rootfs的根,本质上,rootfs就是一个ramfs文件系统。

        通过挂载rootfs,虚拟文件系统的根目录已经建立起来,根目录已经可以容纳文件了。所以,接下来内核解压initramfs的内容到虚拟文件系统的根中,利用initramfs中的内容挂载并切换到真正的根文件系统。

2、解压initramfs到rootfs

        在挂载了rootfs后,内核将Bootloader加载到内存中的initramfs中的文件解压到rootfs中。而这些文件中包含了驱动以及挂载真正的根文件系统的工具,内核通过加载这些驱动、使用这些工具实现挂载真正的根文件系统。

3、挂载并切换到真正的根目录

        将initramfs成功解压后,挂载真正的根文件系统所需的驱动、程序等已经全部俱备,可以挂载真正的根文件系统了,在grub.cfg文件中对应的就是root=XXX。内核将真正的根文件系统挂载到initramfs文件系统中的/root目录下。

        挂载真正的根文件系统后,rootfs中的内容已经没有保留的意义,但是并不能将rootfs卸载,因为rootfs是整个虚拟文件系统的根。因此,为了不占用内存空间,将rootfs中的内容(文件)释放掉即可,然后将真正的根文件系统移动到虚拟文件系统的根(即rootfs的根)下,最后再将进程的文件系统的namespace切换到真正的根文件系统。

initramfs文件基本操作

查看initramfs

lsinitrd

解压initramfs

/usr/lib/dracut/skipcpio initramfs-3.10.0-229.el7.x86_64.img | zcat | cpio -ivd

手动创建initramfs

[root@ct7_node02 initramfs]# find . | cpio -o -H newc | gzip -9 > /tmp/test.img

 注意:修改完initramfs后,需要删除grub.cfg中的linux16 /vmlinuz-3.10.0-514.el7.x86_64 root=/dev/mapper/cl-root ro biosdevname=0 net.ifnames=0 console=ttyS0,115200n8不相关的内容,否则会导致内核启动失败。

创建一个最基本的initramfs

内核启动后会执行initramfs中的init程序,创建一个init,里面写入bash脚本,脚本添加两行信息,屏幕打印hello信息,并运行bash程序,exec是内核运行程序的函数,bash一般存放在/bin/bash路径,这里保持这个路径,其次是添加bash所依赖的库文件。

[root@ct7_node02 initramfs]# ll
total 4
drwxr-xr-x 2 root root 18 Aug  2 15:14 bin
-rwxr-xr-x 1 root root 49 Aug  2 15:13 init
drwxr-xr-x 2 root root 90 Aug  2 15:17 lib64
[root@ct7_node02 initramfs]# cat init 
#!/bin/bash

echo "Hello Michael"
exec /bin/bash
[root@ct7_node02 initramfs]# tree ./ 
./
|-- bin
|   `-- bash
|-- init
`-- lib64
    |-- ld-linux-x86-64.so.2
    |-- libc.so.6
    |-- libdl.so.2
    `-- libtinfo.so.5

2 directories, 6 files
[root@ct7_node02 initramfs]# 

 通过ldd命令查看bash所依赖的库文件,并将这些文件复制到上面的lib64目录中

[root@ct7_node02 initramfs]# ldd /usr/bin/bash
	linux-vdso.so.1 =>  (0x00007ffcbd4aa000)
	libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f4268c01000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f42689fd000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f426863b000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f4268e31000)
[root@ct7_node02 initramfs]# 
[root@ct7_node02 tmp]# lsinitrd test.img 
Image: test.img: 1.4M
========================================================================
Version: 

Arguments: 
dracut modules:
========================================================================
drwxr-xr-x   4 root     root            0 Aug  2 15:17 .
drwxr-xr-x   2 root     root            0 Aug  2 15:14 bin
-rwxr-xr-x   1 root     root       960392 Aug  2 15:14 bin/bash
-rwxr-xr-x   1 root     root           49 Aug  2 15:13 init
drwxr-xr-x   2 root     root            0 Aug  2 15:17 lib64
-rwxr-xr-x   1 root     root       155064 Aug  2 15:15 lib64/ld-linux-x86-64.so.2
-rwxr-xr-x   1 root     root      2116736 Aug  2 15:15 lib64/libc.so.6
-rwxr-xr-x   1 root     root        19344 Aug  2 15:16 lib64/libdl.so.2
-rwxr-xr-x   1 root     root       174520 Aug  2 15:16 lib64/libtinfo.so.5
========================================================================

将这些文件制作成initramfs并添加到/boot目录下进行测试

同理其他的命令,例如ls、cd、pwd等的相关命令都可通过以上方式添加到initramfs文件中 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

initramfs详解-----初识initramfs 的相关文章

随机推荐

  • 程序包com.sun.xml.internal.bind.v2不存在解决

    程序包com sun xml internal bind v2不存在 导入com sun xml internal 下的包并且没使用时打包也会报这个错误 全局搜索 com sun xml internal bind v2 删除掉import
  • fastjson byte[]转json字符串

    直接JSON toJSONString 会转为 base64字符串 可以使用JSON toJSON param toString 进行转换
  • SVN文件夹红色感叹号

    SVN文件夹红色感叹号 文件夹更新无最新文件 也没提交 解决方案 1右键 svn清理 2 提交 原因 有可能是svn上面有你之前提交的文件 而在你的本地目录里面删除了
  • jetson nano ubuntu 备份系统至u盘/移动硬盘

    jetson nano ubuntu备份系统至u盘 移动硬盘 1 df h 查看 信息2 挂载u盘2 1 fat322 2 ntfs2 3 挂载被占用 3 刷系统4 解除挂载 1 df h 查看 信息 一般都是 dev sda dev sd
  • 安装 cuda 从装系统开始

    勾选这个选项后就可以跳过安装驱动的环节了 设置root密码 sudo passwd root 安装openssh server 开xshell sudo apt get update sudo apt get install openssh
  • mac用完移动硬盘后 windows识别不出 解决方案

    cmd 运行 chkdsk F f
  • Cannot find reference ‘imread‘ in ‘__init__.py‘

    Cannot find reference imread in init py 前言 本人java开发 只是用python解决部分问题 可能解决方案不专业或者有问题 请自己判断 毕竟我只是简单处理下图片 解决方案 方案一 pip insta
  • RobotMaster资料汇总

    1 软件 xff1a 软件可以去网上下载 xff0c 或者去淘宝购买 xff0c 还包安装 不过基本上都是在虚拟机上操作 xff0c 只有在XP系统下可以直接安装 若是正版软件 xff0c 则会包含正确的安装教程 其中包括 xff1a MA
  • 代码改变生活-使用You-Get下载bilibili的视频【三】

    本文为博主原创 xff0c 未经许可严禁转载 本文链接 xff1a https blog csdn net zyooooxie article details 112167893 我自己都想不到 xff0c 这个分享做到了第三篇 xff0c
  • Python脚本之ZIP文件压缩、解压

    本文为博主原创 xff0c 未经许可严禁转载 本文链接 xff1a https blog csdn net zyooooxie article details 114632112 最近在翻看Python的官方文档 xff0c https d
  • 对文本和数据进行处理之awk编程

    转载地址 xff1a 点击打开链接 awk 是一种编程语言 xff0c 用于在Linux unix下对文本和数据进行处理 数据可以来自标准输入 stdin 一个或多个文件 xff0c 或其它命令的输出 它支持用户自定义函数和动态正则表达式等
  • Ubuntu20.04在vsCode配置opencv

    一 下载opencv xff1a https opencv org releases 我下载的为opencv4 5 4版本 xff0c 可以直接下载 zip文件 xff0c 可以选择其他版本 Sources版本即为 zip版本 xff1a
  • UISearchController使用中的几个坑和一个知识点

    坑1 点击搜索框后 xff0c 搜索框上移到屏幕之外了 不多说了 xff0c 都是坑 因为我之前设置了 UINavigationBar appearance 61 false 把这个去掉好了 坑2 搜索时搜索框和UITableview中间有
  • 深度学习环境搭建(四)之 CUDNN安装

    安装完CUDA Driver和CUDA后 xff0c 还需要安装CUDNN xff0c NVIDIA用于深度学习GPU加速的库 1 下载CUDNN 访问官网链接 xff0c 根据CUDA版本和Ubuntu版本选择CUDNN的版本 前面使用的
  • NMAP 六种端口状态解读

    NMAP 简介 nmap 是一款功能非常强大的扫描工具 xff0c 不仅能对端口扫描 xff0c 还可以在扫描中指定自定义的标志位 xff0c 对自己的 IP 地址进行隐藏伪装为别的 IP 地址 xff0c 还可以根据 nmap 数据库 x
  • IP ID idle 扫描

    IP ID idle 扫描简单介绍 在1998年的时候 xff0c 一个名叫 Antirez 的工程师 xff0c 发现了这种扫描技术 xff0c 攻击者可以通过不直接向目标主机发送报文的形式 xff0c 进行端口扫描 xff0c 而是通过
  • CentOS下编译Linux内核

    前言 编译内核是一项很简单的事情 xff0c 但却是进入Linux内核世界的第一步 xff0c 想要开发内核代码 xff0c 想要了解内核的运行机制 xff0c 第一步就是编译Linux内核 xff0c 以下是在centos7 5环境下编译
  • CentOS下快速升级gcc版本

    前言 很多时候由于gcc版本过低问题 xff0c 导致我们举步维艰 xff0c 从gcc官网下载源码编译又比较费时费力 xff0c 今天我就给大家分享一个快速升级gcc的方法 升级到gcc 6 3 xff1a devtoolset 6已经结
  • Linux带宽测试

    iperf是linux下一款非常实用的测带宽工具 xff0c 是C S模型的 xff0c 支持使用TCP和UDP测试 xff0c 可以测试带宽 xff0c 丢包 xff08 丢包指的是UDP的丢包 xff0c TCP丢包会重传 xff09
  • initramfs详解-----初识initramfs

    为什么需要initramfs 在Linux内核被加载到内存并运行后 xff0c 内核进程最终需要切换到用户太的进程来使用计算机 xff0c 而用户进程又存在于外存储设备上 xff0c 比如systemd进程 xff0c 通常systemd进