当前位置: 首页>>技术教程>>正文


不支持Diskfilter写入>什么触发这个错误?

, , ,

问题描述

离开Grub菜单和Ubuntu启动画面之前会出现此消息。

如何解决问题以清除消息?

那是什么意思?

error:  Diskfilter writes are not supported

系统启动,似乎工作得很好。

最佳解决办法

这是一个BUG!

当您在LVM或RAID分区内创建启动分区(或根分区,当启动分区不存在时)时,这是在最新版本的Ubuntu Server LTS(Ubuntu Server 14.04 LTS)中发生的错误。

您可以在Ubuntu Launchpad中获得有关此错误的更多信息:Bug #1274320 “Error: diskfilter writes are not supported”

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

为什么会发生这个错误?

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

从GRUB手册:

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

此行为可以在/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手册:

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).

GRUB记录失败功能使用save_env语句更新记录失败状态(请参见Ubuntu Help – 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

在使用不受支持的文件系统(btrfs,zfs等)时,GRUB可以正确地跳过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代码,您将看到记录失败功能仅在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 lacks write support for /dev/md0, so recordfail support is disabled.

如何应用正确的解决方案?

如果你不想等待这个补丁被官方代码中的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

次佳解决办法

我认为这个错误是因为raid或LVM分区而发生的。

对于此问题的临时修复:

编辑:/etc/grub.d/10_linux

替换'quick_boot="1"' with 'quick_boot="0"'

然后 :

sudo update-grub

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/739.html,未经允许,请勿转载。