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

red*_*war 12 btrfs disk-usage

$ 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
?  ~  
Run Code Online (Sandbox Code Playgroud)

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

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

我认为 Ubuntu 使用df已知在内部使用 Btrfs 报告错误并因此失败。当 APT 检查空间时,这对 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
Run Code Online (Sandbox Code Playgroud)

bai*_*ain 23

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

传统的文件系统分为文件和可用空间。很容易计算出有多少空间被使用或空闲:

|--------files--------|                                                |
|------------------------drive partition-------------------------------|
Run Code Online (Sandbox Code Playgroud)

Btrfs 结合了 LVM、RAID 和文件系统。驱动器分为子卷,每个子卷动态调整大小和复制:

|--files--|    |--files--|         |files|         |                   |
|----@raid1----|------@raid1-------|-----@home-----|metadata|          |
|------------------------drive partition-------------------------------|
Run Code Online (Sandbox Code Playgroud)

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

在考虑 Btrfs 中的空闲空间时,我们必须弄清楚我们谈论的是哪个空闲空间——块层,还是文件层?在块层,数据以 1GB 的块分配,因此值非常粗略,可能与用户实际可以使用的空间量没有任何关系。在文件层,无法报告可用空间量,因为空间量取决于它的使用方式。在上面的示例中,存储在复制子卷@raid1上的文件将占用的空间是存储在@home子卷上的相同文件的两倍。快照仅存储随后被修改的文件的副本。用户看到的文件与存储在驱动器上的文件之间不再存在 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% /
Run Code Online (Sandbox Code Playgroud)

对于这个挂载的子卷,df报告一个总大小为 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
Run Code Online (Sandbox Code Playgroud)

每行显示不同数据类型和复制类型的总空间和已用空间。显示的值是存储在驱动器上的数据而不是原始字节,因此如果您使用 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只能再平衡的元数据。

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

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


小智 7

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

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

    btrfs subvolume list /
    
    Run Code Online (Sandbox Code Playgroud)
  2. 最有可能的是快照已填满该卷。删除不需要的快照。保留上次的日期,您确定系统运行正常。

    btrfs subvolume delete <path> 
    
    Run Code Online (Sandbox Code Playgroud)

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

  3. 重新启动即可完成

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

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