Kexec
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 条目(例如用于 Microcode 更新),而当前不支持这些条目,则该命令将拒绝执行。
自定义单元文件
如果默认行为不适合您,或者您希望方便地加载自定义内核,您可以将内核加载包装到一个服务单元中。创建一个新的单元文件 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 分区
如果 /boot
不在根文件系统上,则上述 systemd 单元文件将失败,因为 systemd 很可能在运行 kexec-load 单元文件之前卸载 /boot
。另一种方法是加载一个“钩子”单元文件,该文件在启动时不执行任何操作,并在终止时调用 kexec。通过使此单元文件与 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
Conflicts=
。
故障排除
系统在 “kexec_core: Starting new kernel” 后挂起或重启
通用故障排除#启动问题上的故障排除信息可能有助于诊断问题。
在某些情况下,系统挂起可能是 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 镜像和内核的名称。
在 [1] 中建议将 acpi_rsdp
内核参数添加到 kexec 命令行,并且可能在某些情况下解决问题,而无需通过 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