Installing Grub completly into the ESP
How to install all Grub files from /boot/grub
into the EFI System Partition.
Backgroud
Installing Linux Mint 21.3 offers the option to install almost everything into LVM – including the root filesystem. Only the EFI System Partition (ESP) is an extra partition. That’s quite nice because I like the flexibility offered by LVM when I grow and shrink my filesystems, shoveling them between the fast NVME and the slower harddisk in the background and much more.
The installation works but there are three little annoying things:
-
The Grub boot menu waits for 30 seconds to boot instead of 5 seconds.
-
After the boot entry is selected this error is displayed:
error: diskfilter writes are not supported. Press any key to continue...
Contrary to the message booting continues after a little while automatically – fortunately.
-
Grub does not remember the last boot entry. Selecting it again and again is just tedious.
It seems that all three things are linked to the same core problem – one
of them by accident, the other two legitimately. The core problem is that
Grub can only read LVM volumes but it cannot write to them. And it wants
to write to /boot/grub/grubenv
at least two things:
-
The selected menu entry when using
GRUB_SAVEDEFAULT=true
, -
Whether the kernel booted successfully or not using the
recordfail
function ingrub.cfg
. This marker is deleted by the systemd unitgrub-common.service
during startup.
So the last two of the three points from above are directly related to that. But the first one, the “accident”?
Well, the templates generating grub.cfg
contain this code in
/etc/grub.d/00_header
(lines 411 ff.):
if [ "$recordfail_broken" = 1 ]; then
cat << EOF
if [ \$grub_platform = efi ]; then
set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30}
if [ x\$feature_timeout_style = xy ] ; then
set timeout_style=menu
fi
fi
EOF
fi
$recordfail_broken
is set to 1
if /boot/grub
is on a readonly filesystem
or in a logical volume as in this case. So the lines between cat << EOF
and
EOF
are written into grub.cfg
. At Grub runtime the check $grub_platform = efi
is always true and hence timeout
is set unconditionally to 30 seconds because
GRUB_RECORDFAIL_TIMEOUT
is not defined by default. That’s interesting
because this assignment is executed even when the boot did not fail at all!
Even better: This code is not in the official Grub sources, so it must have
been added either by Debian, Ubuntu or Mint. And even more funny: The code just
above that insertion seems to deal with failed boots and timeouts already. So
it might be an outdated customization patch.
In summary: That bad handling of timeout
is really an accident.
Solution
Googling the error message leads to a Ask Ubuntu question and a Launchpad bug. These threads they seem to focus on disabling writes in the LVM case and hence suppressing the error.
A better solution to the core problem: Move the complete directory /boot/grub
to a filesystem which Grub can write to. Since this directory is about 6 MB
and does not change often I decided to move it into the ESP where other parts
of Grub are already installed.
Just moving and symlinking the directory will not work – Grub will not find
the main config file /boot/grub/grub.cfg
any more and hence booting will fail.
Welcome to the Grub command line!
The right procedure ist this (as root
, of course):
cd /boot
# make backups
mv grub grub-bak
mv efi/EFI/ubuntu efi/EFI/ubuntu-bak
# prepare location
mkdir -p efi/EFI/ubuntu/grub
ln -s efi/EFI/ubuntu/grub
# install grub & regenerate config
grub-install
update-grub
Some notes about the documentation:
- The documentation of grub-install does not mention that
install_device
can and should be omitted for EFI installations. Although another chapter Installing GRUB using grub-install mentiones it. (Last checked: Grub-2.12)
- The documentation of Grub does not contain hints that the first
configuration file read is
grub.cfg
next togrubx64.efi
– in my case in the folder/boot/efi/EFI/ubuntu
. This file contains the location of the main configuration file/boot/grub/grub.cfg
with the symlink resolved into Grub paths.
Considerations
Some notes about what to move:
-
Complete
/boot
directory: In that case an extra partition mounted (instead of symlinking) might be more appropriate. Because this directory contains one or more kernels and their initrds the required space might be bigger than the usual ESP size. Currently (i.e. Mint 23.1) a set of files for one kernel is just below 140 MB. And there are always several kernels installed!Another disadvantage: If you want to install several Linux distributions each of them should get its own
/boot
partition which should not be a logical volume – obviously. -
Complete
/boot/grub
directory: I think this hits the sweet spot because the complete Grub bootloader is not that big (~6 MB) and changes very little. And the complete bootloader is then installed in one place. -
Only
/boot/grub/grubenv
: Plan A: I fiddled around with symlinks but this did not work. Plan B: Changing the file location per se is not a problem,save_env
andload_env
both support an optional--file
parameter. The problem is that the templates generatinggrub.cfg
have no way to inject that parameter into every call of both commands. And a shell-like “wrapper function” trick does not work because the equivalentcommand
command is missing:function save_env { command save_env --file /somewhere/else "$@" }
And no – managing
grub.cfg
by hand is not an option.
Some notes about where to move:
-
Moving
/boot/grub
to/boot/efi/EFI/ubuntu/grub
allows me to install several Linux distibutions in parallel with the benefit that these distributions don’t share one bootloader. Switching between the distros is done with the usual EFI BIOS mechanism or withefibootmgr(8)
from a running system. Whether the EFI boot selector is easy to use is another story. -
Moving
/boot/grub
to/boot/efi/grub
would also allow me to install several Linux distributions but these would share one Grub bootloader. So either the Grub configuration is managed by only one of these distros or the configuration of all of these distros must be aligned properly. That doesn’t sound plausible to me.
Summary
Much digging, many thoughs but at least a nice solution.