跳转至内容

Kexec

来自 ArchWiki

Kexec 是一个系统调用,允许您从当前运行的内核加载并启动另一个内核。这对于内核开发者或需要非常快速地重启而无需等待整个 BIOS 启动过程完成的人来说非常有用。请注意,由于使用此方法时设备可能无法完全重新初始化,kexec 可能无法正常工作,但这种情况很少见。

安装

安装 kexec-tools 包。

使用 kexec 重启

手动设置

您可以手动调用 kexec,方法是

# kexec -l /boot/vmlinuz-linux --initrd=/boot/initramfs-linux.img --reuse-cmdline
# kexec -e
警告 直接运行 kexec -e 将不会卸载活动文件系统或正常终止任何正在运行的服务。

也可以手动加载内核,然后让 systemd 为您处理服务关闭和 kexec。

# kexec -l /boot/vmlinuz-linux --initrd=/boot/initramfs-linux.img --reuse-cmdline
# systemctl kexec

systemd

默认情况下,如果使用 systemd-boot 且之前没有使用 kexec -l 手动加载内核,systemd 将加载默认启动加载器条目中指定的内核。例如,在系统更新后重启到新内核,您可以简单地运行

# systemctl kexec

如果您有多个 initrd 条目(例如用于 微码更新),而这些条目当前不受支持,该命令将拒绝执行。

自定义 unit 文件

如果默认行为对您不起作用,或者您希望方便地加载自定义内核,可以将内核加载包装在一个服务 unit 中。创建一个新的 unit 文件 kexec-load@.service,它将加载指定的内核以供 kexec 使用

/etc/systemd/system/kexec-load@.service
[Unit]
Description=load %i kernel into the current kernel
Documentation=man:kexec(8)
DefaultDependencies=no
Before=shutdown.target umount.target final.target

[Service]
Type=oneshot
ExecStart=/usr/bin/kexec -l /boot/vmlinuz-%i --initrd=/boot/initramfs-%i.img --reuse-cmdline

[Install]
WantedBy=kexec.target

然后 启用 您要加载的内核的服务文件(例如,对于 linux,将是 kexec-load@linux.service

确保关机钩子不包含在您的 initramfs 映像中,方法是从 /etc/mkinitcpio.conf 中的 HOOKS 数组中移除它。如果包含,请移除它并 重新生成 initramfs

然后执行 kexec

# systemctl kexec

如果您希望为下一次 kexec 加载不同的内核,例如 linux-lts,请 禁用 当前内核的服务,然后 启用 新内核的服务。

分离 /boot 分区

上述 systemd unit 文件在 /boot 不在根文件系统上时会失败,因为 systemd 可能会在运行 kexec-load unit 文件之前卸载 /boot。另一种方法是加载一个“钩子” unit 文件,该文件在启动时什么也不做,并在终止时调用 kexec。通过使此 unit 文件与 kexec.target 冲突,并且仅与 kexec.target 关联,您可以确保新内核足够早地加载,并且仅在执行 systemctl kexec 命令后加载。这是一个遵循此策略的备用 /etc/systemd/system/kexec-load@.service 文件

[Unit]
Description=hook to load vmlinuz-%i kernel upon kexec
Documentation=man:kexec(8)
DefaultDependencies=no
Requires=sysinit.target
After=sysinit.target

[Service]
Type=oneshot
ExecStart=-/usr/bin/true
RemainAfterExit=yes
ExecStop=/usr/bin/kexec -l /boot/vmlinuz-%i --initrd=/boot/initramfs-%i.img --reuse-cmdline

[Install]
WantedBy=basic.target

请注意,Conflicts=shutdown.target 实际上并非必需,因为 sysinit.target 的严格排序会隐式保证这一点,而 sysinit.target 本身就与 shutdown.target 冲突。

故障排除

系统在 “kexec_core: Starting new kernel” 后挂起或重启

General troubleshooting#Boot problems 中的故障排除信息可能有助于诊断问题。

在某些情况下,系统挂起可能是与 ACPI 相关的问题,可以通过以下方式进行即时检查

# cmdline=$(cat /proc/cmdline)
# cmdline="$cmdline acpi_rsdp=$(grep -m1 ^ACPI /sys/firmware/efi/systab | cut -f2- -d=)"
# echo $cmdline
# ls -al /boot/
# kexec -l /boot/vmlinuz-linux-lts --initrd=/boot/initramfs-linux-lts.img --append="$cmdline"
# systemctl kexec

请根据您运行 ls -al /boot/ 的输出,相应地调整 initramfs 映像和内核的名称。

在 kexec 命令中添加 acpi_rsdp 内核参数已在 [1] 中提出,并且在某些情况下可以解决此问题,而无需通过 acpi=off 完全禁用 ACPI。

无内核模式设置 (Nvidia)

在 kexec 之前需要卸载图形驱动程序,否则下一个内核将无法获得设备的独占控制权。手动实现这一点很困难,因为任何需要 GPU 独占控制权的程序(Xorg、显示管理器)都不能运行。下面是一个 systemd 服务的示例,它将在 kexec 之前卸载 KMS 驱动程序,这就要求您使用 systemctl kexec

/etc/systemd/system/unmodeset.service
[Unit]
Description=Unload nvidia modesetting modules from kernel
Documentation=man:modprobe(8)
DefaultDependencies=no
After=umount.target
Before=kexec.target

[Service]
Type=oneshot
ExecStart=modprobe -r nvidia_drm

[Install]
WantedBy=kexec.target

之后,启用 unmodeset.service

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.