It's a BUG!
This is a bug that occurs in the most recent version of Ubuntu Server LTS (Ubuntu Server 14.04 LTS), when you create the boot partition (or the root partition, when the boot partition doesn't exists) inside a LVM or a RAID partition.
You can get more info about this bug in Ubuntu Launchpad: Bug #1274320 "Error: diskfilter writes are not supported".
Update: This bug will be fixed in Ubuntu Server 15.10 (Wily) using the same workaround proposed here, but we still need to apply the workaround in previous Ubuntu servers (for example, in Ubuntu 14.04) :(.
Why does this bug occur?
When the system is booting, GRUB reads (load_env
) data in /boot/grub/grubenv
. This file is called GRUB Environment Block.
From the GRUB Manual:
It is often useful to be able to remember a small amount of information from one boot to the next.
[...]
At boot time, the load_env command (see load_env) loads environment variables from it, and the save_env (see save_env) command saves environment variables to it.
[...]
grub-mkconfig
uses this facility to implementGRUB_SAVEDEFAULT
This behavior can be founded in /etc/grub.d/00_header
(update-grub
uses this file to generate the /boot/grub/grub.cfg
file):
if [ -s $prefix/grubenv ]; then
set have_grubenv=true
load_env
fi
The problem is that the save_env
statement only works in simple installations (you can't run save_env
inside a RAID or LVM disk). From the GRUB manual:
For safety reasons, this storage is only available when installed on a plain disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and using BIOS or EFI functions (no ATA, USB or IEEE1275).
The GRUB recordfail feature uses the save_env
statement to update the recordfail state (see Ubuntu Help - Grub 2, "Last Boot Failed or Boot into Recovery Mode" section). However, in Ubuntu 14.04 (and in recent Debian versions), the save_env
statement (inside the recordfail feature) is used even if GRUB is installed in a LVM or a RAID.
Let's see the lines from 104 to 124 in /etc/grub.d/00_header
:
if [ "$quick_boot" = 1 ]; then
[...]
case "$FS" in
btrfs | cpiofs | newc | odc | romfs | squash4 | tarfs | zfs)
cat <<EOF
# GRUB lacks write support for $FS, so recordfail support is disabled.
[...]
if [ -n "\${have_grubenv}" ]; then if [ -z "\${boot_once}" ]; then save_env recordfail; fi; fi
GRUB correctly skips the recordfail feature when using unsupported filesystems (btrfs, zfs, etc), but it doesn't skip LVM and RAID at any moment.
How does GRUB protect itself from writing inside RAID and LVM?
To read/write correctly in a filesystems, GRUB loads an appropriate module.
GRUB uses the diskfilter module (insmod diskfilter
) in RAID partitions, and the lvm module in LVM partitions.
Let's see the read/write implementation of the diskfilter module:
apt-get source grub2
vim grub2-2.02~beta2/grub-core/disk/diskfilter.c
I'm pasting the code here (lines from 808 to 823). The warning showed in this question appears at line 821:
static grub_err_t
grub_diskfilter_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf)
{
return read_lv (disk->data, sector, size, buf);
}
static grub_err_t
grub_diskfilter_write (grub_disk_t disk __attribute ((unused)),
grub_disk_addr_t sector __attribute ((unused)),
grub_size_t size __attribute ((unused)),
const char *buf __attribute ((unused)))
{
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"diskfilter writes are not supported");
}
The grub_diskfilter_read
function is implemented (and GRUB can read RAID filesystems). However, the grub_diskfilter_write
function raises a GRUB_ERR_NOT_IMPLEMENTED_YET
error.
Why does using quick_boot=0
solve the problem? And why is it the wrong solution?
If you look one more time in the /etc/grub.d/00_header
code, you will see that the recordfail featured is only used when quick_boot=1
. So, changing quick_boot
from 1 to 0 disables the recordfail feature, and disables writes in the RAID/LVM partition.
However, it'll disable many other features too (run grep \$quick_boot /etc/grub.d/*
and you'll see). More yet, if one day you change your /boot/grub
directory to outside the RAID/LVM, the recordfail feature will still disabled.
Summarily, this solution unnecessarily disables features, and it's not generic.
What is the correct solution?
The correct solution should consider disable the save_env
statements when GRUB is inside LVM or RAID partitions.
One patch was proposed in the Debian Bug Tracker system to implement this solution. It can be found in: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=754921
The idea behind this patch is:
- Run a
grub-probe --target=abstraction "${grubdir}"
command to get what kind of abstraction modules GRUB uses to read/write files in the/boot/grub
directory; - If GRUB uses the
diskfilter
orlvm
module, skip the recordfailsave_env
statement and write an appropriated comment in the/boot/grub/grub.cfg
file;- For example,
# GRUB lacks write support for /dev/md0, so recordfail support is disabled.
- For example,
How to apply the correct solution?
If you don't want to wait for this patch be applied by the Ubuntu/Debian guys in the official code, you can use my patched 00_header
:
# Download
wget https://gist.githubusercontent.com/rarylson/da6b77ad6edde25529b2/raw/99f266a10e663e1829efc25eca6eddb9412c6fdc/00_header_patched
# Apply
mv /etc/grub.d/00_header /etc/grub.d/00_header.orig
mv 00_header_patched /etc/grub.d/00_header
# Disable the old script and enable the new one
chmod -x /etc/grub.d/00_header.orig
chmod +x /etc/grub.d/00_header
# Update Grub
update-grub