How to chainload another kernel with kexec inside a LUKS2 + LVM2 partition?
I have a Debian 11 installation with the following partition layout:
path | format | mount point |
---|---|---|
/dev/nvme0n1p7 |
ext4 (no encryption) |
/boot (Debian 11) |
/dev/nvme0n1p8 |
dm-crypt LUKS2 |
LVM2 (named vg_main ) |
/dev/mapper/vg_main-lv_swap |
swap |
– |
/dev/mapper/vg_main-lv_debian |
ext4 |
/ (Debian 11) |
/dev/mapper/vg_main-lv_ubuntu |
ext4 |
/ (Ubuntu 22.04) |
The /boot
for Ubuntu, lives inside its root file system (/dev/mapper/vg_main-lv_ubuntu
).
I’d like to kexec the Ubuntu kernel after booting the Debian kernel that lives in the unencrypted /boot
partition that unlocks the LUKS2
partition.
I’d like to use the systemd kexec strategy described here.
Is there a way to pass any specific kernel parameter to Debian 11 (that I will do in a specially created GRUB2
entry for this) to tell systemd to simple kexec the Ubuntu 22.04 kernel?
Solution:
Worked as per @telcoM suggestion, with just few adjustments:
/etc/systemd/system/ubuntu-kexec.target
[Unit]
Description=Ubuntu kexec target
Requires=sysinit.target ubuntu-kexec.service
After=sysinit.target ubuntu-kexec.service
AllowIsolate=yes
/etc/systemd/system/ubuntu-kexec.service
[Unit]
Description=Ubuntu kexec service
DefaultDependencies=no
Requires=sysinit.target
After=sysinit.target
Before=shutdown.target umount.target final.target
[Service]
Type=oneshot
ExecStart=/usr/bin/mount -o defaults,ro /dev/mapper/vg_main-lv_ubuntu /mnt
ExecStart=/usr/sbin/kexec -l /mnt/boot/vmlinuz --initrd=/mnt/boot/initrd.img --command-line="root=/dev/mapper/vg_main-lv_ubuntu resume=UUID=[MY-UUID-HERE] ro quiet splash"
ExecStart=/usr/bin/systemctl kexec
[Install]
WantedBy=ubuntu-kexec.target
You might want to set up a ubuntu-kexec.target
which would be essentially a stripped-down version of multi-user.target
, with basically:
[Unit]
Description=Kexec an Ubuntu kernel from within an encrypted partition
Requires=basic.target #You might get by with just sysinit.target here
Conflicts=rescue.service rescue.target
Wants=ubuntu-kexec.service
After=basic.target rescue.service rescue.target ubuntu-kexec.service
AllowIsolate=yes
This would invoke a ubuntu-kexec.service
, which you would create to run your kexec command.
The kernel parameter would then be: systemd.unit=ubuntu-kexec.target
, similar to how rescue.target
or emergency.target
can be invoked when necessary.
The idea is that ubuntu-kexec.target
will pull in basic.target
(or even just sysinit.target
) to get the filesystems mounted, and then pull in the ubuntu-kexec.service
which runs the actual kexec
command line.
As far as I know, you can specify just one systemd.unit=
option, and since you need to specify "boot as usual up to sysinit.target
/basic.target
, then pull in ubuntu-kexec.service
, you’ll need a unit of type *.target
to specify all the necessary details.