嵌入式 initramfs 与外部 initramfs 执行 init 的区别?

嵌入式 initramfs 与外部 initramfs 执行 init 的区别?

我正在构建一个非常小的 Linux 系统,仅由内核 (v4.1-rc5) 和填充了 busybox (v1.23.2) 的 initramfs 组成。它在大多数情况下工作正常,但我观察到无论我使用嵌入式 initramfs 还是外部 initramfs,/init 中命令执行的行为都有所不同。

/init 脚本是:

#!/bin/sh

dmesg -n 1

mount -t devtmpfs none /dev
mount -t sysfs none /sys
mount -t proc none /proc
echo "Welcome"
while true
do
    setsid cttyhack /bin/sh
done

然后我要么将内核 .config 中的 CONFIG_INITRAMFS_SOURCE 选项设置为包含 initramfs 的所有文件夹的目录,要么运行

find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz

来建造它。

然后,当我编译内核时,无论是否设置了 CONFIG_INITRAMFS_SOURCE,我最终都会得到系统的两个变体:

  1. 嵌入 initramfs 的 bzImage

  2. bzImage + rootfs.cpio.gz(外部initramfs)

当我现在开始使用那些qemu

qemu-system-x86_64 -enable-kvm -kernel bzImage

或者

qemu-system-x86_64 -enable-kvm -kernel bzImage -initrd rootfs.cpio.gz

我得到以下行为差异:

使用版本 2(外部 initramfs)一切正常,显示“欢迎”并且我收到提示。然而,对于版本 1(嵌入式 initramfs),我收到警告

unable to open an initial console

未显示“欢迎”,但我收到提示。

据我了解该过程,这两个版本的 initramfs 应该包含相同的文件,因为我从相同的文件夹构建它(或让内核构建它)。

我想知道是否有人可以帮我解释这种行为?

* 更新 *

正如 mikeserv 在评论中所说,内核默认包含一个最小的嵌入式 initramfs。当使用外部时,它仍然存在,但如果您嵌入自己的,则会被覆盖。我发现与规范相反,这确实不是空的,而是包含一个 dev 文件夹、一个根文件夹和 /dev/console 设备。然后,当使用外部 initramfs 时会使用该设备,但如果您嵌入自己的设备,则会被覆盖。因此,mknod -m 622 initramfs_src/dev/console c 5 1在嵌入您自己的设备时,您必须在 initramfs 源中包含 /dev/console 设备。

非常感谢 mikeserv、frostschutz 和 JdeBP 帮助我解决这个问题!

答案1

它们真的一模一样吗?

您可以在 bzImage 中找到或从 bzImage 中提取内置的图像/usr/src/linux/usr/initramfs_data.cpio.gz,如下所述:https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging

如果您使用内置的并将其用作外部的,它可以工作吗?

如果仍然不同,内核本身是否相同? (/proc/config.gz两者比较)

应该有一些区别。我不知道内核关心 initramfs 来自哪里。我宁愿怀疑qemu在传递参数时使用不同的设置-initrd......

顺便说一句,/init对我来说,你看起来就像是在产卵无限的贝壳。setsid不是exec。我错了吗?

答案2

您可能还对 Buildroot 2018.02 如何处理这个问题感兴趣。

每当您使用 initramfs ( BR2_TARGET_ROOTFS_INITRAMFS=y) 或 initrd ( BR2_TARGET_ROOTFS_CPIO=n) 时,它都会将以下内容添加/init到您的 rootfs 中https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/init

#!/bin/sh
# devtmpfs does not get automounted for initramfs
/bin/mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
exec /sbin/init "$@"

副本是由https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/cpio.mk:

# devtmpfs does not get automounted when initramfs is used.
# Add a pre-init script to mount it before running init
define ROOTFS_CPIO_ADD_INIT
    if [ ! -e $(TARGET_DIR)/init ]; then \
        $(INSTALL) -m 0755 fs/cpio/init $(TARGET_DIR)/init; \
    fi
endef

了解 init 路径/init用于 initramfs 也很有用,与/sbin/init其他情况不同:什么会导致将 init=/path/to/program 传递给内核而不是像 init 一样启动程序?

相关内容