RAID and Ubuntu Server 14.04 LTS error: diskfilter writes are not supported

It’s a bug, which I realized a couple of months ago when setting up the Ubuntu Server 14.04 LTS on the RAID, and which Canonical should correct in the next update, I hope. You can read more about this bug here Bug #1274320 “Error: diskfilter writes are not supported

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 implement GRUB_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 <

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 yourself 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 or lvm module, skip the recordfail save_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.

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 http://www.alexbod.com/wp-content/uploads/2015/05/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