SSD 上的 Btrfs,“设备上没有剩余空间”;catch-22 带有 `fstrim` 和 `btrfs balance`;如何恢复?

Kam*_*ski 3 linux ssd trim btrfs

我的 Kubuntu(安装在 下/)的根文件系统是 Btrfs。我不用-o discard作安装选项。这意味着我需要fstrim按需运行

过去我遇到了这个问题:btrfs, no diskspace left。我注意到fstrim -v /几乎没有任何空间被修剪。我的解决方案是btrfs balance start /fstrim. 这是我在那里回答的要点。

今天不一样了。可能是我维护太晚了。这是发生的事情:

# fstrim -v /
/: 24 KiB (24576 bytes) trimmed
# btrfs balance start /
ERROR: error during balancing '/': No space left on device
Run Code Online (Sandbox Code Playgroud)

我删除了几个子卷(快照),btrfs subvolume delete …但没有帮助。我不太记得细节,但我认为以前我可以运行,btrfs balance …因为初步fstrim修剪了至少几个 MiB,不像今天那样小到 24 KiB。现在,这似乎是一种第 22 种情况,其中fstrimbtrfs balance仅在对方先完成工作时才起作用。

作为记录,这些是一些统计数据,表明我实际上有足够的空间:

# df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       112G   43G   68G  39% /

# btrfs fi df /
Data, single: total=108.73GiB, used=41.00GiB
System, single: total=64.00MiB, used=16.00KiB
Metadata, single: total=3.00GiB, used=1.02GiB
GlobalReserve, single: total=352.00MiB, used=0.00B
Run Code Online (Sandbox Code Playgroud)

请注意,在正常操作期间,我还没有“设备上没有剩余空间”。我认为 Btrfs 会不断在已经采用的块中进行新的写入。然而,过去我在 期间打了“没有剩余空间……” apt-get upgrade,然后我用btrfs balance和恢复了fstrim。我不知道什么时候(如果)这再次让我感到震惊。在做重要的事情时,我想在“没有空间……”之前进行维护。

如何从这种情况中恢复fstrim并且btrfs balance不互相阻止?我可以在我正在运行的系统中解决这个问题吗?

事实上我已经解决了这个问题,我的答案如下。问题供以后参考。随意添加另一个解决方案。


附加信息:

$ uname -a
Linux foobar 4.4.0-78-generic #99-Ubuntu SMP […] x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/issue
Ubuntu 16.04.3 LTS \n \l

# dpkg -l | grep btrfs
ii  btrfs-tools  4.4-1ubuntu1  amd64  Checksumming Copy on Write Filesystem utilities
Run Code Online (Sandbox Code Playgroud)

Kam*_*ski 5

是的,您可以从正在运行的系统中恢复。我原来的方法在下面;然而,多亏了 Zan Lynx 的评论,我找到了一种更简单的方法。

我改进的方法

这是提到的评论:

或者,如果您提前考虑,您可以告诉 btrfs 使用小于设备的最大值 btrfs filesystem resize

(与我原来的方法相比,重点是故意在这个特定设备上留出一些可用空间并在那里扩展文件系统,而不是添加一个可能不那么容易的单独设备。)

好消息:我的测试表明我不必提前考虑!即使btrfs balance start /抛出“没有剩余空间……”,我仍然可以缩小文件系统,只要有空间(即所有文件和元数据适合新大小)。这导致以下解决方案:

# btrfs filesystem resize -100M /  # shrink a little...
Resize '/' of '-100M'
# btrfs filesystem resize +100M /  # ... and expand back
Resize '/' of '+100M'
# btrfs balance start /            # should work now
Done, had to relocate 88 out of 88 chunks
# fstrim -v /
/: 67,8 GiB (72753831936 bytes) trimmed
Run Code Online (Sandbox Code Playgroud)

我原来的做法

这是您需要做的(详细说明如下):

  1. 向 Btrfs 文件系统添加一个额外的设备。
  2. btrfs balance start …
  3. fstrim …
  4. 从 Btrfs 文件系统中删除额外的设备。
  5. btrfs balance start …
  6. fstrim …

诀窍是向 Btrfs 文件系统添加一个额外的设备,因此btrfs balance …有一些额外的空间。该设备可能类似于/dev/sdb/dev/sdb3。在这个例子中,我在我的 HDD 上使用了一个常规的 1 GiB 文件(非常重要:我仔细检查了该文件不属于我想要扩展的 Btrfs 文件系统!这可能是致命的)。我认为 RAM 中的文件(例如 in /dev/shm/)应该也可以。

# tmpf=/mnt/hdd/tempfile   # if this file exists, it will be overwritten!
# truncate -s 1G "$tmpf"
# extra=$(losetup -f --show "$tmpf")
Run Code Online (Sandbox Code Playgroud)

现在$extra是喜欢/dev/loop0什么的。

# btrfs device add "$extra" /
Run Code Online (Sandbox Code Playgroud)

此时我不能重新启动我的操作系统。如果我这样做了,它将缺少其根文件系统的一部分,因为没有/dev/loop*将与/mnt/hdd/tempfile. 如果您使用常规设备(或分区)作为额外设备,这不会有问题,因为btrfs device scan在启动期间会检测到它。

# btrfs balance start /
Run Code Online (Sandbox Code Playgroud)

就我而言,这tempfile是一个稀疏文件。在我运行的另一个控制台中watch ls -hls /mnt/hdd/tempfile,我注意到它何时增长到(几乎)全尺寸。这样我就知道何时从 SSD 中移动了一些 Btrfs 块。如有任何疑问,请btrfs ballance …完成;但我调用是btrfs balance cancel /为了节省一些时间。现在让我们回到主控制台。

注意:下面的第一行来自上面btrfs balance start /被中断的命令。

balance canceled by user
# fstrim -v /
/: 26,7 GiB (28696862720 bytes) trimmed
Run Code Online (Sandbox Code Playgroud)

fstrim修剪的方式比以前多了。我不再需要额外的设备了。

# btrfs device delete "$extra" /   # may take a while
# btrfs balance start /            # should work now
Done, had to relocate 88 out of 88 chunks
# fstrim -v /
/: 67,8 GiB (72753831936 bytes) trimmed
Run Code Online (Sandbox Code Playgroud)

就是这样。现在是时候清理了:

# losetup -d "$extra"
# rm "$tmpf"
Run Code Online (Sandbox Code Playgroud)