不支持磁盘过滤器写入操作 > 什么会触发这个错误?

离开Grub菜单并在Ubuntu启动画面之前,会出现这个消息。
如何解决问题以清除这个消息?
而这个消息意味着什么?
error:  Diskfilter writes are not supported

系统启动并且似乎运行良好。

1在Ubuntu桌面版15.04中仍未修复... - ThePiercingPrince
1在16.04版本中仍未修复。这种快速修复bug的速度让人难以跟上。 - Paul Tomblin
2个回答

这是一个BUG!

这是在最新版本的Ubuntu Server LTS(Ubuntu Server 14.04 LTS)中出现的一个bug,当你在LVM或RAID分区内创建引导分区(或根分区,当引导分区不存在时)时会发生。

你可以在Ubuntu Launchpad上获取有关此bug的更多信息:Bug #1274320 "Error: diskfilter writes are not supported"

更新:此bug已经在Ubuntu Server 14.04和一些更新的Ubuntu版本中修复。可能只需要运行apt-get upgrade即可。

为什么会出现这个bug?

当系统启动时,GRUB会读取(load_env/boot/grub/grubenv中的数据。这个文件被称为GRUB环境块

来自GRUB手册:

往往能够在每次启动时记住一小部分信息是非常有用的。
在启动时,load_env命令(参见load_env)从中加载环境变量,并且save_env命令(参见save_env)将环境变量保存到其中。
grub-mkconfig使用这个功能来实现GRUB_SAVEDEFAULT。
这种行为可以在/etc/grub.d/00_header中找到(update-grub使用此文件生成/boot/grub/grub.cfg文件)。
if [ -s $prefix/grubenv ]; then
  set have_grubenv=true
  load_env
fi

问题在于save_env语句只适用于简单的安装(无法在RAID或LVM磁盘内运行save_env)。根据GRUB手册的说明:
“出于安全原因,此存储仅在安装在普通磁盘上(无LVM或RAID),使用非校验和文件系统(无ZFS),并使用BIOS或EFI功能(无ATA、USB或IEEE1275)时可用。”
GRUB的recordfail功能使用save_env语句来更新recordfail状态(参见Ubuntu帮助-Grub 2,“上次启动失败或进入恢复模式”部分)。然而,在Ubuntu 14.04(以及最近的Debian版本)中,即使GRUB安装在LVM或RAID中,也会使用save_env语句(在recordfail功能内部)。
让我们看一下/etc/grub.d/00_header中104到124行的内容:
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正确跳过不支持的文件系统(btrfs、zfs等)的recordfail功能,但是它在任何时候都不跳过LVM和RAID

GRUB如何保护自己免受写入RAID和LVM的影响?

为了在文件系统中进行正确的读写操作,GRUB加载适当的模块。

GRUB在RAID分区中使用diskfilter模块(insmod diskfilter),在LVM分区中使用lvm模块。

让我们看一下diskfilter模块的读写实现:

apt-get source grub2
vim grub2-2.02~beta2/grub-core/disk/diskfilter.c

我在这里粘贴代码(从808行到823行)。这个问题中显示的警告出现在第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");
}

`grub_diskfilter_read`函数已经实现(GRUB可以读取RAID文件系统)。然而,`grub_diskfilter_write`函数会引发`GRUB_ERR_NOT_IMPLEMENTED_YET`错误。
为什么使用`quick_boot=0`可以解决这个问题?为什么这是错误的解决方案?
如果你再次查看`/etc/grub.d/00_header`代码,你会发现`recordfail`特性只在`quick_boot=1`时使用。所以,将`quick_boot`从1改为0会禁用`recordfail`特性,并禁止在RAID/LVM分区中进行写操作。
然而,这也会禁用许多其他功能(运行`grep \$quick_boot /etc/grub.d/*`就能看到)。更重要的是,如果有一天你将`/boot/grub`目录移到RAID/LVM之外,`recordfail`特性仍然被禁用。
总结起来,这个解决方案不必要地禁用了一些功能,并且不具有通用性。
正确的解决方案是什么?
正确的解决方案应该考虑在 GRUB 在 LVM 或 RAID 分区内时禁用save_env语句。
一个补丁被提议在Debian Bug Tracker系统中实现这个解决方案。它可以在https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=754921中找到。
这个补丁的思路是:
  • 运行grub-probe --target=abstraction "${grubdir}"命令,以获取GRUB用于读写/boot/grub目录中文件的抽象模块类型;
  • 如果GRUB使用diskfilterlvm模块,则跳过记录失败的save_env语句,在/boot/grub/grub.cfg文件中写入适当的注释;
    • 例如:# GRUB缺少对/dev/md0的写支持,因此禁用了记录失败的支持。
如何应用正确的解决方案?
如果你不想等待Ubuntu/Debian团队在官方代码中应用这个补丁,你可以使用我修改过的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

非常感谢您提供的错误参考。希望您能理解,我觉得nux的解决方案更具说服力。;) - Run CMD
6嗨@ClassStacker,我总结了答案!它很长,很多人都很难理解:p 虽然还是很长,但至少我按照部分进行了组织。现在你只需要查看感兴趣的部分即可。 - Rarylson Freitas
8哇,谢谢你。如果有一个“本月最佳答案”的功能,我会投票给你的。此外,你应该获得一个“不废话”奖项。这种文章真正提供了价值,并且使这个网站网络与论坛之间产生了巨大的区别。 - Run CMD
1很遗憾,我受到了这个错误的影响,报告中提供的修复方法以及在编辑“00_header”文件中尝试的方法都没有起作用。我不想禁用“quick_boot”来解决这个问题。 - douggro
@douggro 我不确定为什么编辑过的 00_header 文件(如此处推荐)不起作用。我知道仅仅因为它对我(和 Rarylson Freitas)有效,并不意味着它一定适用于每个人。但是你确定给了旧的和新的 00_header 正确的权限,并运行了 update-grub 吗?(如果你只是直接编辑了 00_header,则不需要 chmod,但 update-grub 仍然是必要的。) - Eliah Kagan
@EliahKagan 我完全按照指示进行操作,包括更改权限和更新 grub。问题一直存在,但似乎软件更新解决了这个问题。 - douggro
@douggro,我“受影响”了,而且我的系统已经是最新的。所以不,脚本还没有更新。但从我们能看到的来说并不重要,这只意味着 grub 中的 save_env 没有任何作用。那又怎样? - Alexis Wilke
我错误地说更新修复了这个错误 - 它仍然存在。进一步的调查发现,我在00_header文件中引入了一个语法错误,在文件的第106行多了一个cat <<EOF语句。删除了那个语句后,错误消失了。也许我在修复后没有正确运行update-grub,但现在它已经正常工作了。 - douggro
@RarylsonFreitas:非常棒的回答。给你一些声望!感谢你写了一个出色的回答。继续努力,保持好的工作。 - 0xC0000022L
补丁在Ubuntu 14.04.2中不再起作用。应用补丁并重新启动后,仍然出现错误。 - Cerin
在我的情况下,解决方法是在/etc/rc.local中执行命令:"rm /boot/grub/grubenv"。 - ggrandes
这个补丁解决了我在Ubuntu 14.04.2 LTS上的问题,即使重启了几次,它依然有效。 - gerlos
有趣的是,最近升级到14.04后,这个问题又重新出现了。为了解决它,我不得不回滚到5月24日的00_header备份。 - Paul Tomblin
嗨@PaulTomblin。最近,在Ubuntu 14.04中更新了00_header文件,以修复另一个错误(不同的错误)。在这种情况下,我通常会保留我的当前文件,并手动检查新文件(*-dpkg或类似名称),以合并新的改进。更多信息请参见:https://raphaelhertzog.com/2010/09/21/debian-conffile-configuration-file-managed-by-dpkg/。好消息是,我更新了我的解决方法,现在它既修复了这个错误,也修复了最近的Ubuntu更新错误。 - Rarylson Freitas
如果您从未修改过文件,它就不会生成-dpkg.orig或其他任何东西。这就是为什么我不得不找一个旧的备份。 - Paul Tomblin
@RarylsonFreitas 我终于找时间重新启动来测试了,尽管/boot/grub/grub.cfg中写着function recordfail { set recordfail=1 # GRUB缺乏对lvm的写入支持,因此禁用了recordfail支持。 },但我仍然遇到了错误。 - Paul Tomblin
我在15.04版本仍然遇到这个错误。根据Launchpad的记录,官方修复将会在wily(15.10)版本中发布。 - nwellnhof
谢谢 @nwellnhof。我已经更新了帖子,加入了你的信息! - Rarylson Freitas
这是谷歌为该文件生成的一个短链接:https://goo.gl/5CJr2h - Stanislav
我遇到了同样的问题(Ubuntu 14.04)。这个bug已经修复了,我只需要运行"apt-get update"来安装grib-pc版本2.02~beta2-9ubuntu1.7,问题就解决了。 - dalf
哇,太棒了。这个回答堪称所有*交流平台上最好的回答之一。我在寻找解决Manjaro(一款Arch衍生版本)上的错误时找到了它,并且帮助我解决了问题。如果你了解这些发行版文档的声誉,你很可能会把这当作是一种称赞 :). - Red_Tractor
37年过去了,这个问题还存在吗? - Typewar
我有一个后续问题,评论栏位容纳不下,所以我提了一个新的问题:https://askubuntu.com/questions/1409016/diskfilter-writes-are-not-supported-want-to-understand-changes-in-patched-file - Amedee Van Gasse
9年过去了,这个问题仍然存在!我使用的是Ubuntu 22.04,并安装了低延迟内核(sudo apt install linux-lowlatency-hwe-22.04)来解决音频问题。然而,Ubuntu仍然想要启动默认内核。我在某个地方读到,启用GRUB_SAVEDEFAULT=true并将GRUB_DEFAULT=saved更改为应该解决此问题。但这并没有解决问题,每次重新启动时我都会收到这个错误。不过似乎并没有引起任何问题。我将恢复那些GRUB的更改,希望能清除这个错误,或者尝试@nux发布的解决方案。 - AnthonyK

我认为这个错误是由于RAID或LVM分区引起的。
对于这个问题的临时修复方法:
编辑:/etc/grub.d/10_linux
将'quick_boot="1"'替换为'quick_boot="0"'
然后:
sudo update-grub

谢谢,它完美地运作了。是的,我正在使用LVM来管理所有卷。 - RCF
谢谢你提供的解决方案。它帮我省了很多工作。有没有一点背景信息也可以吗? - Run CMD
@ClassStacker 如果你想从nux那里获取更多信息,你需要编辑你的评论以(@nux)开头。如果你在问我,你正在寻找什么类型的背景? - RCF
2@RCF-U14.04 1) 不,我不必这样做。只需点击“添加评论”->“帮助”,了解到“帖子作者将始终收到您的评论通知”。2) 我想知道(来自nux的回答)为什么这个方法可以解决问题,尤其是考虑到Rarylson Freitas给出的详细答案。但如果你能回答这个问题,随时都可以这样做。 - Run CMD