Ryan Rueger

ryan@rueg.re / me.jpg
$ curl -L rueg.re/pgp | gpg --import -

Regenerating `initramfs` from another snapshot with `mkinitcpio`

I was hit by an unfortunate bug recently, in which a bundled ssl library overrode the system wide version rendering my system unbootable. I could not even get into early userspace because the initramfs generated with this library could not cryptsetup open my encrypted root partition.

This is usually a moment in which those who have a (btrfs/zfs/lvm) system, can calmly rollback their system and go on with their day. At some point in the future, they can try to upgrade again, and hope the problem is fixed.

(This is a good example to illustrate why /boot along with the initramfs files should be kept under rollback control, otherwise snapshots using older kernels would still not be bootable, because you would still be using the new initramfs.)

Suppose we want to fix the issue directly: we need to know how to regenerate an initramfs from a system root that is not the current one (/).

Suppose our snapshots look like this

/btrfs/@root
/btrfs/snapshots/@good_snapshot-1
/btrfs/snapshots/@good_snapshot-2
/btrfs/snapshots/@good_snapshot-3

After the update, /btrfs/@root is broken (because /btrfs/@root/boot/initramfs-linux.img is broken) and suppose we are currently booted into /btrfs/snapshots/@good_snapshot-3. What it means for us to be “booted into” /btrfs/snapshots/@good_snapshot-3 is that the snapshot /btrfs/snapshots/@good_snapshot-3 is mounted to / just after the root partition is unlocked in the boot process.

Reading the manual of mkinitcpio we see that we need the options

-g, --generate filename
   Generate a CPIO image as filename. Default: no; this means nothing will
   be written to the filesystem unless this option is specified.

-r, --moduleroot root
  Specifies the root directory to find modules in, defaulting to /

-k, --kernel kernelversion
  Use kernelversion, instead of the current running kernel. This may be a
  path to a kernel image (only supported for x86-based architectures), a
  specific kernel version or the special keyword none. In the latter case,
  no kernel modules are added to the image.

The option -g will tell mkinitcpio where to save the initramfs, we want this to be generated in the root of the currently broken snapshot /btrfs/@root/boot/initramfs-linux.img. Moreover, we want mkinitcpio to read all module information from /btrfs/@root and not / (which is currently mounted to /btrfs/snasphots/@good_snapshot-3), so we pass this to the -r option. Finally, we want mkinitcpio to read the correct kernel version (image) from disk to create the initramfs, so we need to pass -k /btrfs/@root/boot/vmlinuz-linux to mkinitcpio. Now that the initramfs has been regenerated, we can re-install our bootloader entries and boot into /btrfs/@root as usual.

This is another example where Unified Kernel Images (UKI’s) can really save you: after regenerating the initramfs, we can simply re-create a bootable UKI1 to create a bootable system. We need not worry about bootloaders getting confused with archived snapshots and live systems.


  1. and if necessary create a new EFI entry with efibootmgr ↩︎