Ubuntu 认为 Btrfs 磁盘已满但事实并非如此

Ubuntu 认为 Btrfs 磁盘已满但事实并非如此
$ cat /etc/fstab
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
UUID=a168d1ac-4e13-4643-976d-6e47ea1732b1 /boot        ext2  defaults                                                                   0 1
/dev/mapper/sda4_crypt                    /            btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@          0 2
/dev/mapper/sda4_crypt                    /tmp         btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@tmp       0 2
/dev/mapper/sda4_crypt                    /run         btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@run       0 2
/dev/mapper/sda4_crypt                    /var/crash   btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@var-crash 0 2
/dev/mapper/sda4_crypt                    /var/tmp     btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@var-tmp   0 2
/dev/mapper/sda4_crypt                    /var/log     btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@var-log   0 2
/dev/mapper/sda4_crypt                    /var/spool   btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@var-spool 0 2
/dev/mapper/sda5_crypt                    /home        btrfs defaults,autodefrag,compress=lzo,inode_cache,space_cache,subvol=@home      0 3
/dev/mapper/750er                         /media/750er ext4  defaults                                                                   0 4
/dev/mapper/cswap                         none         swap  defaults                                                                   0 5
➜  ~  df -h         
Filesystem              Size  Used Avail Use% Mounted on
/dev/mapper/sda4_crypt   38G   12G   13M 100% /
none                    4,0K     0  4,0K   0% /sys/fs/cgroup
udev                    2,0G  4,0K  2,0G   1% /dev
tmpfs                   396M  1,3M  394M   1% /run
none                    5,0M     0  5,0M   0% /run/lock
none                    2,0G  208K  2,0G   1% /run/shm
none                    100M   36K  100M   1% /run/user
/dev/mapper/sda4_crypt   38G   12G   13M 100% /tmp
/dev/sda2               231M   44M  175M  21% /boot
/dev/mapper/sda4_crypt   38G   12G   13M 100% /var/crash
/dev/mapper/sda4_crypt   38G   12G   13M 100% /var/tmp
/dev/mapper/sda4_crypt   38G   12G   13M 100% /var/log
/dev/mapper/sda4_crypt   38G   12G   13M 100% /var/spool
/dev/mapper/sda5_crypt  3,7T  2,4T  1,2T  67% /home
/dev/mapper/750er       688G  276G  377G  43% /media/750er
/dev/mapper/2tb         1,8T  1,7T  141G  93% /media/2tb
➜  ~  sudo btrfs fi df /
Data, single: total=9.47GiB, used=9.46GiB
System, DUP: total=8.00MiB, used=16.00KiB
System, single: total=4.00MiB, used=0.00
Metadata, DUP: total=13.88GiB, used=1.13GiB
Metadata, single: total=8.00MiB, used=0.00
➜  ~  

这是一个 40GB 的分区,上面有很多快照。但它是压缩的,所以我认为 9.46GB/40GB 是准确的。但我的 Ubuntu 失败了,因为它说没有磁盘空间。我遇到了 apt 错误,无法安装程序,我的 mysql 服务器因此无法启动。

并且我知道不要依赖df我只是为了完整性而将其包括在内。

我认为 Ubuntu 使用了df已知会内部错误报告 Btrfs 的版本,因此失败。当 APT 检查空间时,这很有意义。但实际上它无法写入磁盘。

$ sudo time dd if=/dev/zero of=large bs=2G count=1
dd: error writing ‘large’: No space left on device
0+1 records in
0+0 records out
11747328 bytes (12 MB) copied, 1,29706 s, 9,1 MB/s
Command exited with non-zero status 1
0.00user 1.40system 0:01.44elapsed 97%CPU (0avgtext+0avgdata 2098028maxresident)k
160inputs+23104outputs (0major+383008minor)pagefaults 0swaps

答案1

Btrfs 与传统文件系统不同。它不仅仅是将文件名转换为块设备上的偏移量的层,它更像是将传统文件系统与 LVM 和 RAID 相结合的层。与 LVM 一样,它具有在底层设备上分配空间的概念,但实际上并不将其用于文件。

传统的文件系统分为文件和可用空间。很容易计算出已使用或可用的空间量:

|--------files--------|                                                |
|------------------------drive partition-------------------------------|

Btrfs 结合了 LVM、RAID 和文件系统。驱动器被划分为子卷,每个子卷的大小都是动态的,并且都有复制:

|--files--|    |--files--|         |files|         |                   |
|----@raid1----|------@raid1-------|-----@home-----|metadata|          |
|------------------------drive partition-------------------------------|

该图显示分区被划分为两个子卷和元数据。其中一个子卷是重复的(RAID1),因此设备上每个文件都有两个副本。现在我们不仅知道文件系统层有多少可用空间,还知道其下方的块层(驱动器分区)有多少可用空间。元数据也占用了空间。

在考虑 Btrfs 中的可用空间时,我们必须明确我们谈论的是哪个可用空间 - 块层还是文件层?在块层,数据以 1GB 块为单位分配,因此值非常粗略,可能与用户实际可以使用的空间量无关。在文件层,无法报告可用空间量,因为空间量取决于如何使用。在上面的示例中,存储在复制子卷上的文件@raid1将占用相同文件在@家子卷。快照仅存储随后修改的文件的副本。用户看到的文件和驱动器上存储的文件之间不再存在 1-1 映射。

您可以使用以下命令检查块层的可用空间btrfs filesystem show /以及子卷层的可用空间btrfs filesystem df /


# df -h
Filesystem              Size  Used Avail Use% Mounted on
/dev/mapper/sda4_crypt   38G   12G   13M 100% /

对于这个已安装的子卷,自由度报告驱动器总大小为 38G,已使用 12G,剩余 13M。可用空间已使用 100%。请记住,总大小 38G 被划分到不同的子卷和元数据中 - 它并不专属于此子卷。

# btrfs filesystem df /
Data, single: total=9.47GiB, used=9.46GiB
System, DUP: total=8.00MiB, used=16.00KiB
System, single: total=4.00MiB, used=0.00
Metadata, DUP: total=13.88GiB, used=1.13GiB
Metadata, single: total=8.00MiB, used=0.00

每行显示不同数据类型和复制类型的总空间和已用空间。显示的值是驱动器上存储的数据,而不是原始字节数,因此如果您使用 RAID-1 或​​ RAID-10 子卷,则使用的原始存储量是您在此处看到的值的两倍。

第一列显示存储的项目类型(数据、系统、元数据)。第二列显示每个项目是否存储单个副本(单个),或者每个项目是否存储两个副本(DUP)。两个副本用于敏感数据,因此如果一个副本损坏,还有备份。对于 DUP 行,用过的值必须加倍才能得到实际驱动器上使用的空间量(因为btrfs fs df报告存储的数据,而不是使用的驱动器空间)。第三和第四列显示总空间和已用空间。没有自由的列,因为“可用空间”的数量取决于如何使用它。

此驱动器最突出的特点是,您为普通文件分配了 9.47GiB 的空间,其中您已使用了 9.46GiB - 这就是为什么您得到设备上没有剩余空间错误。您已为重复元数据分配了 13.88GiB 的空间,其中您已使用了 1.13GiB。由于此元数据是 DUP 重复的,这意味着实际驱动器上已分配了 27.76GiB 的空间,其中您已使用了 2.26GiB。因此,驱动器中的 25.5GiB 未被使用,但同时也不可用于存储文件。这是“Btrfs 已分配大量元数据”问题。要尝试纠正此问题,请运行btrfs balance start -m /-m参数告诉 btrfs 仅重新平衡元数据。

类似的问题是元数据空间不足。如果输出显示元数据实际上已满(用过的值接近全部的),那么解决方案就是尝试使用命令释放几乎为空 (<5% 使用) 的数据块btrfs balance start -dusage=5 /。然后可以重新使用这些空闲块来存储元数据。

有关更多详细信息,请参阅 Btrfs 常见问题解答:

答案2

简短回答:Btrfs 分区元数据被 df 等标准磁盘实用程序显示为“已使用”。

  1. 检查问题音量。例如:/

    btrfs subvolume list /
    
  2. 很可能快照正在填满卷。删除不需要的快照。保留上次确定系统运行正常的快照。

    btrfs subvolume delete <path> 
    

    其中路径来自前一个命令子卷列表,其中显示“快照”。

  3. 重新启动即可完成

问题的原因可能是您的发行版或包管理器每次更新系统时都会制作快照。

注意:如果磁盘已满,平衡命令将失败,因为没有可用空间可以平衡。

答案3

就我而言,即使我删除了文件和快照,磁盘使用率也不会下降。

btrfs 平衡(数据和元数据)无法正常工作并出现错误“设备上没有剩余空间”

btrfs balance start -m /
ERROR: error during balancing '/': No space left on device
There may be more info in syslog - try dmesg | tail

尽管实际数据使用量低于 RAID1 的三分之一,但 RAID1 显示两个磁盘都已满负荷。

# btrfs fi sh
Label: none  uuid: 61a20f1a-c133-11e6-964b-d3bac0c48bbd
    Total devices 2 FS bytes used 153.94GiB
    devid    1 size 455.76GiB used 455.76GiB path /dev/sda2
    devid    2 size 455.76GiB used 455.76GiB path /dev/sdb2


# btrfs filesystem df /
Data, RAID1: total=452.73GiB, used=151.51GiB
System, RAID1: total=32.00MiB, used=80.00KiB
Metadata, RAID1: total=3.00GiB, used=2.42GiB
GlobalReserve, single: total=512.00MiB, used=0.00B

解决方案:丢弃空块,不需要额外的空间:

btrfs balance start -dusage=0 /

btrfs balance start -musage=0 /

来源:https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-balance#ENOSPC

选择:我的解决方案是缩小磁盘看:https://unix.stackexchange.com/questions/239765/how-to-fix-btrfs-superblock-error-after-resize-shrink-btrfs-couldnt-get-super

btrfs filesystem resize 1:430g /
btrfs filesystem resize 2:430g /

(命令需要时间,请检查系统日志以查看重新定位块)

之后调整大小:

btrfs filesystem resize 1:450g /
btrfs filesystem resize 2:450g /

此后,btrfs 平衡(元数据)再次起作用:

btrfs balance -m /

然后 btrfs 平衡数据(重新定位使用率低于 33% 的数据块):

btrfs balance -dusage=33 /

答案4

一般来说,在涉及 btrfs 时不要相信命令 df。让我们举一个非常简单的例子。假设在 500 GiB 分区上有一个 btrfs。您创建一个子文件夹 foo,并向其添加 300 GiB 的数据。然后,您创建另一个子文件夹 bar,并向其添加 198 GiB。如果开销可以忽略不计,df 将正确显示您有 2 GiB 的可用空间。

您的祖母刚刚给您 64 GiB 的家庭视频要您添加。因此,您决定删除子文件夹 foo。现在 df 可能仍显示您有 2 GiB 可用。如果您尝试使用 SAMBA 从 Windows 计算机复制视频数据,则可能会出现空间不足错误。但如果您登录到本地计算机,则可以成功复制 64 GiB 而不会出现任何错误。

至少我上次尝试时,SMBD(Samba)使用 df 告诉 Windows 磁盘有多大,以及有多少可用空间。如果空间不足,Windows 不会复制文件,因此会抛出错误。但由于 df 不知道如何检查 btrfs,它只会报告列为未分配的集群数量作为可用空间。但实际上,已分配了 300 GiB 的集群,但未使用。所以你真的有 302 GiB 的可用磁盘空间。

现在的解决方案是,您可以配置 samba 以使用 btrfs filesystem df 命令,或者定期使用 btrfs balance start 并反复尝试,直到找到满足您需求的正确选项。由于我已经配置 samba 以使用我自己的命令来报告子挂载上的可用空间,因此我选择了第一个选项,但第二个选项更简单。

不幸的是,现在有许多应用程序(例如 docker)会使用 df 抛出错误,类似于 samba 的方式。因此,大多数人都会定期重新平衡文件系统。这确实可以提高整体性能。但是,当您想立即复制文件时,这也很耗时。

相关内容