Support keeping old kernel versions on upgrade
cc @jenneron @craftyguy
We've discussed this idea before, so trying to bring everything together here (I couldn't find an existing issue).
There is the one proposal to essentially bring back support for kernel flavors, so we could have multiple kernel packages installed too. But I think that is entirely orthoganol to this issue.
Currently, when installing a kernel upgrade, if the new kernel has a bug then that's it, you can't downgrade and (if your device is a phone) then you're basically bricked until you get to a computer and manually build a new image.
This is really not great, and we can do better.
I want to keep the scope fairly small here, initially focusing on EFI, and explicitly not using "flavours". The way I'd like for this to work is that on installing a kernel upgrade, the previous two kernels are kept around and offered as alternative boot options by the bootloader.
The "ideal" solution would be to have apk support tracking multiple non-conflicting versions of a package. However this would require a huge amount of work either in apk itself, or in pmaports to maintain several versions of a kernel package. I don't think this kind of generic approach makes sense given the limited usecase.
Instead, I propose introducing a new script in the boot-deploy project: kernel-save
and a new boolean deviceinfo variable (yay!) deviceinfo_keep_old_kernels
. The kernel package should then have pre and post install scripts which run kernel-save pre
and kernel-save post
respectively.
kernel-save pre
- Read
/usr/share/boot-deploy/os-customization
and check a newkeep_old_versions
variable, if unset/0 then just exit, ifdeviceinfo_keep_old_kernels
is not true then exit. - Determine the currently installed kernel version and check the space use of
/lib/modules/linux-$ver
, if enough space then make a copylinux-$ver.save
, otherwise, print an error that there's no free space and suggest to disabledeviceinfo_keep_old_kernels
- check space in
/boot
and make a copy oflinux.efi
,initramfs
,initramfs-extra
, and the current dtb is applicable (copying all dtbs is a big waste of space for no gain here). These copies should have the kernel version appended to them. - Create a new systemd-boot entry (using the boot-deploy-functions implementation) for that kernel version
- Append the kernel version to
/var/cache/boot-deploy.kernel-versions
kernel-save post
- Read
/usr/share/boot-deploy/os-customization
and check a newkeep_old_versions
variable, if unset/0 then just exit, ifdeviceinfo_keep_old_kernels
is not true then exit. - Now that apk has removed
/lib/modules/linux-$ver
, rename the backup copy back - Remove the boot entry, /boot files and modules for the oldest installed version (determined by reading the first entry of
/var/cache/boot-deploy.kernel-versions
) IFF there are more thankeep_old_versions
entries. - Remove the first entry of
/var/cache/boot-deploy.kernel-versions
Hopefully this isn't too much into the weeds... I don't think we should aim to support anything other than EFI/systemd-boot initially. Introducing support for additional bootloaders should be fairly straightforward and can be done by whoever wants it...