Btrfs - Arch Linux 中文维基

跳转到内容

# Btrfs

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 Btrfs，最近一次同步于 2025-09-20，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

相关文章

- 文件系统
- Snapper
- Timeshift
- Yabsnap

译自 Introduction — BTRFS Documentation：

  Btrfs 是为 Linux 开发的现代写时复制（CoW, Copy-on-Write）文件系统，旨在提供高级功能，同时也注重容错、修复及便于管理。

注意：与其它一些文件系统类似，Btrfs 仍在持续开发中，因此某些特定的功能可能尚未成熟到可以满足日常使用。要检查特定使用场景是否会受到影响，可查阅 Btrfs 官方文档的状态页面（英文）及本文的#已知问题部分。

## 准备

安装用户空间工具 btrfs-progs包，这是执行基本操作所必需的。

若需要从 Btrfs 文件系统启动（即内核和 initramfs 位于 Btrfs 文件系统），请检查引导加载程序是否支持 Btrfs。

## 创建文件系统

下文展示如何创建一个新的 Btrfs 文件系统。若要将一个 ext3/4 文件系统转换为 Btrfs，请参考 #从 ext3/4 转换。若要使用无分区的配置，请参考 #无分区 Btrfs 磁盘。

查阅 mkfs.btrfs(8) 以获取更多信息。

Btrfs 文件系统可建立在一个或多个设备上。此处“设备”是指 Linux 块设备，例如整个磁盘、分区、LVM 逻辑卷、回环设备、网络块设备等。

### 单设备文件系统

要在分区 `/dev/分区名` 上创建一个 Btrfs 文件系统，执行：

    # mkfs.btrfs -L 自定义卷标 /dev/分区名

Btrfs 文件系统中，元数据的默认节点大小（nodesize）为 16 KiB 和系统页大小之中较大者，而数据的默认扇区大小等于系统页大小（自动检测）。如需为元数据指定更大的节点大小（必须是扇区大小的整数倍，最大允许 64 KiB），可通过 `-n` 选项来设置，如下例使用 32 KiB 的节点大小：

    # mkfs.btrfs -L 自定义卷标 -n 32k /dev/分区名

注意：根据 mkfs.btrfs(8) § OPTIONS 手册页内容：“较小的节点大小会增加碎片化，但B树变得更高，从而能够减少锁竞争。较大的节点大小则能使数据更加紧凑并降低碎片化程度，但在更新元数据块时需要更多昂贵的内存操作。”

### 多设备文件系统

警告：

- Btrfs 的 RAID 5 和 RAID 6 模式存在致命缺陷，除非用来做丢失数据无所谓的测试，否则不应当用于任何场景。这里有已知问题和部分绕过方案的列表。 查阅 btrfs(5) § RAID56 STATUS AND RECOMMENDED PRACTICES 以获取最新动态。
- 默认情况下，systemd 会为 `/var/log/journal` 目录禁用写时复制（CoW），这在 RAID 1 上会导致数据损坏（参见 #禁用写时复制）。要避免这种情况，请创建一个空文件 `/etc/tmpfiles.d/journal-nocow.conf`，用来覆盖 `/usr/lib/tmpfiles.d/journal-nocow.conf`（参阅 tmpfiles.d(5) § CONFIGURATION DIRECTORIES AND PRECEDENCE）。

Btrfs 可以在多个设备上创建 RAID。Btrfs 支持的 RAID 级别包括 RAID 0、RAID 1、RAID 10、RAID 5 和 RAID 6（详情参阅下文 #profile）。Btrfs 的 RAID1 profile 仅保存两个副本，内核 5.5 版本引入了 RAID1c3 和 RAID1c4，分别对应带有3和4个副本的 RAID 1 级别。可以使用 `-d` 和 `-m` 参数分别为数据和元数据配置 RAID 级别。默认情况下，数据只有一份（ `single`），元数据则镜像存储（`raid1`）。这相当于 JBOD 配置——多个磁盘会被看做成一个文件系统，但文件不冗余。更多有关如何创建一个 Btrfs RAID 卷的信息请参阅 Btrfs Wiki: 在多个设备上使用 Btrfs。

    # mkfs.btrfs -d single -m raid1 /dev/分区1 /dev/分区2 ...

必须在 `/etc/mkinitcpio.conf` 中加入 `udev`、`systemd` 或 `btrfs` 钩子之一才能使用多设备 Btrfs 文件系统。查阅 mkinitcpio#常用钩子以获取更多信息。

创建好文件系统之后，建议使用下面的命令扫描并注册多设备 Btrfs 文件系统，这样在挂载多设备文件系统时就仅需指定其中的一个设备：

    # btrfs device scan

注意：

- 可以之后再将设备添加到多设备文件系统中，详情请参见 Btrfs Wiki 上的这篇文章。
- 多个设备可以大小各异。但如果使用 RAID 配置存储数据，当一个磁盘的大小比其他的加起来都大时，多出的空间并不会被使用。要确定多设备 Btrfs 的可用空间，可以使用 Btrfs 磁盘使用计算器确定。
- 有些引导加载程序不支持多设备文件系统，比如 Syslinux。
- Btrfs 不会自动从速度最快的设备读取，因此混合使用不同类型的磁盘会导致性能表现不稳定。详情请参阅 Stack Overflow 上的这个回答。

#RAID 小节中有关于维护多设备上的 Btrfs 文件系统的建议。

#### profile

Btrfs 使用 profile 这个概念来表示镜像、奇偶校验和分条，对应 RAID 术语中的“RAID 级别”（若适用）。在同一个 Btrfs 文件系统中，元数据的 profile（mkfs.btrfs(8) 的 `-m` 选项）和数据的 profile（mkfs.btrfs(8) 的 `-d` 选项）可以不一样。

一些重要的 profile：

single
  没有镜像、分条和奇偶校验，让多个设备映射到单个文件系统中。在 mdadm 术语中被叫做 `LINEAR`。
RAID0
  没有镜像、分条和奇偶校验，但允许并行访问设备。不像传统的 mdadm RAID 那样要求设备大小相同。
RAID1
  镜像，没有分条和奇偶校验，允许在一个设备失效的情况下恢复数据。

更多 profile 请参阅手册 mkfs.btrfs(8) § PROFILES。

## 配置文件系统

### 写时复制（CoW）

默认情况下 Btrfs 总是对所有文件使用写时复制（CoW）。写入操作不会原地覆盖数据，而是将修改后的数据块写入新位置，同时更新元数据指向新位置。请参阅 Btrfs Sysadmin 相关章节了解实现细节以及其优缺点。

#### 禁用写时复制

警告：在 Btrfs 中禁用写时复制会禁用数据校验和 [1] [2]，禁用数据校验和会使 Btrfs 无法得知这些文件是否损坏。与 RAID 1（包括 profile 中的 `RAID1`、`RAID1c3` 与 `RAID1c4`）结合使用时，断电或其他原因导致的数据损坏可能会造成副本间的数据不同步。

使用 `nodatacow` 选项挂载文件系统可禁用其上新文件的写时复制特性。注意这只会影响新建的文件，而不会影响已有的文件。`nodatacow` 参数会禁用压缩与数据校验和，参阅 btrfs(5) 以了解细节。

注意：

- 根据 btrfs(5) § MOUNT OPTIONS：“在单个文件系统中，无法让一些子卷使用 `nodatacow` 参数挂载，而其他的使用 `datacow` 参数挂载。第一个被挂载子卷的挂载参数将会应用于其他所有子卷。”
- 即使已禁用写时复制，在特定情况下写时复制仍然会被使用，详见下文#仍然会触发写时复制的情况。

要禁用空文件或目录中新文件（同上，不会影响其中已有文件）的写时复制特性，请使用下面的命令：

    $ chattr +C 目录或文件路径

注意：译自 BTRFS documentation: Attributes：“在目录上设置此属性时，所有新建的文件将继承该属性。由于实现限制，此标志只能在空文件上设置或取消。”
提示：为目录中已存在的所有文件禁用写时复制可以使用下面的方法：

    $ mv /path/to/dir /path/to/dir_old
    $ mkdir /path/to/dir
    $ chattr +C /path/to/dir
    $ cp -a --reflink=never /path/to/dir_old/. /path/to/dir
    $ rm -rf /path/to/dir_old

需要保证这个过程中未使用涉及到的数据。关于此处 `--reflink=never` 参数的使用，详见下文 #对复制的影响。

##### 仍然会触发写时复制的情况

具有 +C 属性的文件仍然允许有超过一个引用（例如使用 `cp` reflink 的副本与 Btrfs 中的快照），此时写时复制依然会生效。

本文或本章节的语言、语法或风格需要改进。参考：帮助:风格

原因：子章节嵌套过多。（在en:Talk:Btrfs讨论）

###### 对复制的影响

使用 `cp` 复制文件时，+C 属性并非由源文件决定，而取决于目标路径——要么从上级目录继承，要么由文件系统是否使用 `nodatacow` 参数挂载决定。当源文件与目标文件都具有/不具有 +C 属性时，能够通过 reflink 进行复制，否则不能。实际行为依赖于 `--reflink` 参数，有以下三种结果：

- 使用 `--reflink=auto` 参数（默认情况）：若 +C 属性相同，则使用 reflink；否则进行深拷贝。
- 使用 `--reflink`（或 `--reflink=always`）参数：若 +C 属性相同，则使用 reflink；否则操作失败。
- 使用 `--reflink=never` 参数：总是进行深拷贝。

总的来说，如果确实要避免写时复制，必须显式地使用 `--reflink=never` 参数（若目标路径没有 +C 属性，先创建一个有 +C 属性的目录/空文件再覆盖它）。有关 `--reflink` 参数的更多信息请参阅 cp(1)。

###### 对快照的影响

如果为禁用了写时复制的文件创建快照，快照会锁定当前文件的数据块，因此首次写入该文件的块时会触发写时复制。但文件仍保留 +C 属性，故后续对同一文件块的写入仍为原地操作，直至下次创建快照。

频繁快照会减弱 +C 属性的效果，因为在每次快照后的第一次写入都会触发写时复制。要避免这种情况，可以把所有禁用写时复制的文件放在一个单独的子卷中并避免为该子卷创建快照。

### 压缩

Btrfs 支持自动的透明压缩，这不仅能缩减文件体积，还能通过减少写入放大来显著延长闪存介质的使用寿命，详见 Fedora:Changes/BtrfsByDefault#Compression、[3] 与 [4]。在某些情况下（例如单线程、重文件 I/O 时），压缩可以提升性能，而在其他场景中（如多线程和/或大文件I/O的CPU密集型任务），性能则会明显受影响。采用快速的压缩算法（`zstd` 和 `lzo`）通常性能也就越好。一些基准测试提供了详细的对比数据。

#### 压缩类型

Btrfs 支持的压缩算法有 `zlib`（即 zlib 库提供的 DEFLATE 压缩算法）、`lzo`（即 LZO）和 `zstd`（即 zstd 实现的 Zstandard 压缩算法）。其中 `lzo` 无压缩级别，而 `zlib` 和 `zstd` 可调整压缩级别（`zlib`：1～9；`zstd`：-15～-1、1～15，需为整数），级别越高压缩效果越好而所需时间越长。改变压缩级别对 CPU 和 I/O 吞吐的影响不一样，因此在变更前后最好进行检查和性能测试。关于压缩类型的更多信息，可参阅 btrfs(5) § COMPRESSION。

警告：如果使用 `zstd` 算法（尤其是 -15～-1 级别），使用较旧的内核或 btrfs-progs包 的系统可能不能读取或修复该文件系统。

#### 启用压缩

##### 为文件系统启用

挂载时指定 `compress=算法[:级别]` 挂载选项，对于文件系统中每次写入，Btrfs 将自动考虑是否启用压缩。其中的 `算法` 处可以填写 `zlib`、`lzo`、`zstd` 或 `no`（即不压缩），可选的 `级别` 处填写压缩级别，不填写或填写 0 时取默认值 3（`lzo` 不适用）。使用该选项时，Btrfs 会检测文件写入的数据的首个数据块经压缩后体积是否缩小。如果缩小，则压缩本次写入的全部内容，否则文件会被标记为 `NOCOMPRESS`，整个写入过程及该文件后续的所有写入过程都不会触发压缩 [5]。这是为了防止等待所有待写入数据完全交付给 Btrfs 并进行尝试压缩后，磁盘才开始执行写入操作。

注意：

- 压缩挂载选项会在同一文件系统的所有挂载点（包括不同子卷与 bind 挂载）之间共享 [6]。
- 若文件的一次写入无法压缩，此后写入均不会进行压缩。

或者，您可以在 Btrfs 子卷上设置压缩属性，并且无论它如何挂载，它都会持久化并应用，使用 `btrfs property set / compression alg`，其中 `alg` 可以是 `zstd` 或 `zstd:n`，其中 `n` 是压缩级别。

这篇文章的某些内容需要扩充。

原因：下文陈述的有关试验测试的结果缺少引用来源，且此处关于百分比的原文表述并不准确（故译文不一定正确）。 (在 Talk:Btrfs 中讨论)

若改用 `compress-force=算法[:级别]` 挂载选项，Btrfs 会检查每次写入的每个数据块并分别决定是否压缩。在多个混合用途系统上进行的经验测试表明，使用 `compress-force=zstd` 相比使用 `compress=zstd` 能显著提高空间节省率（从 10% 提升到 20%），但这会导致 CPU 占用率无端（略微）升高且拖长写入所需时间。官方 Btrfs 指导手册不推荐使用该选项。

使用 `compress-force` 也会限制 extent 的最大大小，从而增加碎片化。[1]

只有在添加以上两个挂载选项之一后新建或修改的文件才会被自动压缩。

提示：在新的 Btrfs 上安装 Arch Linux 时，如果需要将其压缩后存储，需要在系统安装前就使用 `compress` 选项挂载，例如：`mount -o compress=zstd /dev/sdxY /mnt/`，并注意在其 fstab 中为根目录文件系统指定相同的 `compress` 挂载选项。

##### 为现有文件启用

要为现有文件启用压缩，可使用 `btrfs filesystem defragment -c算法` 命令，`算法` 处可选填为 `zlib`、`lzo` 或 `zstd`，使用 `-L` 选项指定压缩级别，否则使用默认值 3（`lzo` 不适用）。例如，执行以下命令可用 `zstd` 的 1 压缩级别重新压缩所有文件：

    # btrfs -v filesystem defragment -r -czstd -L1 /

警告：defragment 操作会断开 #写时复制（CoW）数据（包括通过 `cp` 复制的文件、#快照和#去重数据等）之间的 reflink，产生独立的文件，可能显著增加空间使用量 [7]。

使用上面的方式压缩文件不会被持久化，其他写入操作将应用原有压缩设置。

以下两种方式可以持久性启用对单个文件的压缩：

    $ chattr +c 文件

    $ btrfs property set 文件 compression zstd

前一条命令使用的是从 ext2 文件系统继承的文件属性旧接口，灵活性不足，只能够使用默认的 `zlib` 压缩算法。后一条命令则可以指定压缩算法，但指定压缩级别尚未实现，因此采用默认值 3（`lzo` 不适用）。

#### 查看压缩类型和压缩率

compsize包 接收一个包含文件或目录（可为整个 Btrfs 文件系统）的列表，输出其使用的压缩类型以及实际压缩率（压缩后大小/压缩前大小）。压缩前大小可能与其他程序（如 du(1)）显示的数值不一致，因为每个 extent 都会被统计且只统计一次⸺即使有多个 reflink，或其部分内容已不再使用但尚未被垃圾回收。

`-x` 选项可限制在单一文件系统内执行，这在类似于 `compsize -x /` 的场景中非常有用，可以避免程序因尝试访问非 Btrfs 的子目录而导致整个运行的失败。

### 子卷

“Btrfs 子卷是可独立挂载的 POSIX 文件树，而不是也不能看作是块设备。大多数其他 POSIX 文件系统只有一个可挂载根，而 Btrfs 不仅整个卷（称作‘顶层子卷’）可以挂载，每个子卷也可独立挂载；一个 Btrfs 卷可以包含不止一个文件树⸺包含一个‘文件森林’。Btrfs 子卷可以理解为一个 POSIX 文件命名空间。”[8]

每个 Btrfs 文件系统都有一个 ID 为 5 的顶层子卷。这个子卷不能被移除或被其他子卷替代。顶层子卷在文件系统中的路径为 `/`，其他子卷则嵌套在顶层子卷之下。子卷（不包括顶层子卷）可以在文件系统中移动，其路径可以发生变化，但子卷 ID 不可更改。

默认情况下，挂载文件系统时会挂载顶层子卷。可以通过选项来挂载指定子卷。

子卷的主要用途之一是#快照。

更多详细信息请参阅以下链接（英文）：

- Btrfs 文档
- Btrfs Wiki SysadminGuide#Subvolumes
- Btrfs Wiki Trees

#### 创建子卷

要创建子卷，必须先挂载该 Btrfs 文件系统以使其要创建的路径可以访问（挂载根子卷或者上级子卷）。

    # btrfs subvolume create 路径/子卷名

例如，在 `/mnt` 所在子卷下创建子卷 `@sub`（路径为 `/mnt/@sub`）：

    # btrfs subvolume create /mnt/@sub

注意：

- 使用 `-p`（`--parents`）选项可以自动创建不存在的父目录。
- Btrfs 中子卷名可以是任何有效的目录名，以 `@` 符号开头只是timeshift包的命名约定。
- 如果顶层子卷没有挂载，而你想在其内部创建子卷，可以通过指定 `subvolid=5` 来临时挂载它。参见 #挂载子卷。

#### 列出子卷

查看`路径`所属文件系统的所有子卷列表：

    # btrfs subvolume list -t 路径

使用 `-t` 选项会显示更易读的表格视图。

#### 删除子卷

删除子卷：

    # btrfs subvolume delete 子卷路径

如果子卷包含其他子卷，需要添加 `-R`（`--recursive`）选项来递归删除包含的所有子卷。子卷也可以当作常规目录删除（使用 `rm -r`、`rmdir`；但这样会比较慢）。

#### 挂载子卷

使用`subvol=子卷路径（相对于顶层子卷）`或`subvolid=子卷ID`选项来挂载子卷。通过在文件系统的顶层创建各种子卷，然后将其挂载到适当的挂载点，可以模拟传统的文件系统分区。

例如，以下将顶层子卷挂载到 `/mnt/` 并创建两个名为 `subvol_root` 和 `subvol_home` 的子卷。当顶层子卷被卸载时，新的子卷将被挂载到 `/mnt/` 和 `/mnt/home/`：

    # mount device /mnt/ -o subvolid=5
    # btrfs subvolume create /mnt/subvol_root/
    # btrfs subvolume create /mnt/subvol_home/
    # umount /mnt/
    # mount -o subvol=/subvol_root device /mnt/
    # mount -o subvol=/subvol_home --mkdir device /mnt/home/

使用 `subvol` 挂载选项引用子卷时，需要使用相对于“顶层子卷”的路径。

提示：

- 子卷 ID 可通过#列出子卷显示。
- 不将顶层子卷作为 `/` 挂载会使更改子卷布局的更加简单。因此，考虑创建一个子卷来作为 `/` 挂载（用以存放你的系统文件）。

注意：译自 btrfs(5) § MOUNT OPTIONS：“大多数挂载选项适用于整个文件系统，因而只有第一个挂载的子卷的选项才会生效。这是由于尚未实现分子卷的选项处理，将来情况可能会改变。这意味着（例如）你无法使用挂载选项为每个子卷单独设置 `nodatacow`、`nodatasum` 或 `compress`。这最终应该会被修复，但事实证明在 Linux VFS 框架内正确实现是困难的。”

有关目前及计划可以为每个子卷单独应用的挂载选项，请参阅 Btrfs Wiki FAQ。

提示：最好使用 `subvol=/path/to/subvolume` 来挂载，而不是使用 subvolid，因为在恢复 #快照 时，subvolid 可能会发生变化，从而需要更改挂载配置。

请参阅 Snapper#建议的文件系统布局、Btrfs SysadminGuide#Managing Snapshots 和 SysadminGuide#Layout，了解使用子卷的文件系统布局的例子。

有关 Btrfs 特有的挂载选项的完整列表，请参阅 btrfs(5) § BTRFS SPECIFIC MOUNT OPTIONS。

#### 将子卷挂载为 /

如果要将子卷挂载为 `/`，要么#更改默认子卷，要么在 `rootflags` 内核参数中指定挂载子卷的选项（一些引导加载程序可以自动添加，例如 GRUB 的 `grub-mkconfig` 命令），并编辑 `/etc/fstab`。建议使用 `subvol=子卷路径` 而不是 `subvolid` 来挂载，因为后者可能在恢复#快照之后发生变化，如果不同时更改挂载选项，系统将不能启动。

如果你计划使用其中一种同步和备份程序，建议不要更改默认子卷，因为它会在恢复除默认子卷之外的其他子卷的快照时导致问题。例如，Timeshift会相对于文件系统的默认子卷创建一个路径`timeshift-btrfs`来存储快照，并且建议为根和家目录使用一个单独的非默认子卷。

#### 更改默认子卷

如果没有提供 `subvol` 与 `subvolid` 选项，将挂载默认子卷。要将指定子卷设置为所在文件系统的默认子卷，执行：

    # btrfs subvolume set-default 子卷路径

或者使用：

    # btrfs subvolume set-default 子卷ID 路径

将`路径`所在文件系统的默认子卷设置为 ID 为`子卷ID` 的子卷。

提示：子卷ID可通过#列出子卷显示。

使用 `btrfs subvolume set-default` 更改默认子卷后，顶层子卷需要使用 `subvol=/` 或 `subvolid=5` 挂载选项挂载 [9]。

注意：

- GRUB 的 `grub-mkconfig` 脚本不遵守 Btrfs 的默认子卷设置⸺如果 `/` 是顶层子卷，始终不会指定 `subvol=/` 或 `subvolid=5` 挂载选项，可能导致无法启动；如果 `/` 非顶层子卷，始终会指定相应的 `subvol` 选项，导致无法仅通过设置默认子卷回退（bug 报告）。目前可以通过手动修改 `grub.cfg` 中 `rootflags` 内核参数解决（参见 #挂载子卷），或者使用工具自动在 GRUB 中为快照创建启动项（参见 #引导进入快照）。另外，如果 `grub.cfg` 的实际位置发生改变，例如包含 `/boot` 的子卷改变，需要再次运行 `grub-install`。详见这个论坛帖子。
- 如果你打算使用某个同步和备份程序，不推荐更改默认子卷，以免在恢复非默认子卷的快照时出现问题。例如Timeshift会在默认子卷下创建路径`timeshift-btrfs`来储存快照，为/和/home使用单独的非默认子卷比较好。

### 配额

磁盘配额的概念在Unix世界有着悠久的传统。传统配额基于文件所有权，通过限制用户拥有的所有文件的总大小来控制空间使用。Btrfs采用了与传统Unix系统不同的配额设计理念，不支持传统的基于用户或用户组的配额功能，这是因为其现代存储特性（如#快照、#写时复制（CoW）、#去重和#压缩）使得传统配额的空间计算变得极其复杂且不准确 [10]。作为替代，Btrfs 采用基于子卷的配额机制，现提供两种实现机制⸺传统的#配额组和较新的#简单配额（在2023年底发布的6.7版本内核中引入）来实现类似的空间管理效果。虽然增加了管理复杂性，但提供了更灵活和精确的存储控制能力，且不用分区即可限制目录大小，支持动态调整配额。

注意：挂载Btrfs文件系统（或其中任一子卷）后才可以管理配额。

#### 配额组

警告：

尽管Btrfs 配额组（quota group，简称 qgroup）在常规使用中被认为是稳定的，但启用配额组功能，尤其是在频繁创建大量快照的环境中，仍可能导致性能下降，特别是在删除快照时。配额组统计会引入额外的元数据开销，并可能在高强度快照工作负载下影响系统响应速度。

近期的内核改进（5.15及后续版本）已修复诸多历史问题，但某些限制依然存在，特别是在深度嵌套的子卷或复杂的配额组层级结构等高级应用场景中。2016年就写在这里的建议⸺启用配额组前需审慎评估具体使用场景，至今仍然适用。请务必查阅最新的 Btrfs 文档获取当前详细信息。值得注意的是，为了解决配额组的性能问题，Btrfs引入了#简单配额功能，提供了灵活性略差但性能更优的替代方案。

Btrfs精确的配额支持是通过子卷之上的配额组实现的。配额组使用配额组ID（qgroupid）表示，格式为`层级/ID`。子卷的层级是0，`0/` 可以省略，而子卷对应的 `ID` 就是子卷的 ID，例如 `0/5` 表示顶层子卷的配额组，也可以用子卷路径代替 `0/ID` 的表示方式。配额组形成“树”状层级结构，但一个配额组可以有多个父配额组 [11]。叶子配额组层级为0，即子卷直接对应的配额组。所有更高层级配额组的 `ID` 可以自由指定。高层级配额组包含低层级配额组，相同层级之间不可嵌套，但层级不表示嵌套深度。例如，可以为 `5/100` 配额组分配子配额组 `0/5`。

##### 总引用空间和独占引用空间

每个配额组主要追踪两个数值：总引用空间（total referenced space）和独占引用空间（exclusively referenced space）。其中总引用空间是指所有能够从配额组内访问到的数据占用的存储空间，独占引用空间是指只被配额组所属的子卷引用（而不被该配额组以外的子卷引用）的数据所占用的存储空间。

##### 启用/禁用配额组

使用以下命令为`路径`所在文件系统启用配额组：

    # btrfs quota enable 路径

将 `enable` 改为 `disable` 以禁用配额组。

警告：禁用配额组会销毁当前所有配额组并解除其关系。

##### 创建/销毁配额组

子卷对应的0层级配额组始终会自动创建。即便子卷在启用配额前创建，启用配额时也会自动创建相应配额组。同样，#删除子卷时子卷对应的配额组也会被删除，并自动解除与原包含有这一配额组的高层级配额组的关系。

使用以下命令在`路径`所在文件系统创建配额组`层级/ID`：

    # btrfs qgroup create 层级/ID 路径

将 `create` 改为 `destroy` 以销毁配额组。销毁配额组类似于使用 `rm -d` 删除目录⸺如果配额组存在子配额组，必须先解除关系；如果仅存在父配额组，关系会自动解除。

注意：子卷对应的配额组不能直接删除，而应该通过直接删除子卷来自动删除。

##### 分配/删除子配额组

使用以下命令将`路径`所在文件系统的`子配额组`分配到`父配额组`，注意`父配额组`必须比`子配额组`层级更高：

    # btrfs qgroup assign 子配额组 父配额组 路径

将 `assign` 改为 `remove` 以解除这一关系。

注意：分配/解除分配子配额组后可能需要 #配额重扫描，这在当前版本中会自动触发，但可能造成性能消耗，详见#配额重扫描章节。

##### 限制/取消限制配额组

可以限制配额组的总引用空间或独占引用空间，或同时限制两者。例如，使用以下命令在`路径`所在文件系统中限制`配额组`的总引用空间不超过 1 GiB：

    # btrfs qgroup limit 1G 配额组 路径

注意：如果已#启用压缩，Btrfs目前仅支持限制压缩后的数据占据的空间。

其中`配额组`若省略，则会尝试将`路径`解释为子卷路径。添加选项 `-e`（到 `limit` 之后）改为限制独占引用空间。将`大小限制`改为`none` 以取消限制。

##### 列出配额组

使用以下命令列出`路径`所在文件系统的所有配额组：

    # btrfs qgroup show 路径

注意：由于 `btrfs qgroup show` 使用的是磁盘中的数据，可能需要 `sync` 后才能显示准确的统计数据。为此可以添加 `--sync` 选项（到 `show` 之后），先对`路径`所在文件系统执行强制同步操作。

输出的“Path”列可能显示一些特殊值，含义如下：

- `<toplevel>`：顶层子卷对应的配额组。
- `<under deletion>`：该配额组对应子卷已被删除（其目录已移除），但子卷元数据尚未完全清理。

提示：可以使用 `btrfs subvolume sync 路径 子卷ID` 等待`路径`所在文件系统中子卷完全删除（可以指定多个子卷 ID；若一个也没有指定则等待当前文件系统中所有待删除子卷删除完毕）。但请注意先卸载该子卷。

- `<squota space holder>`：（仅适用于 #简单配额）该配额组对应子卷已完全删除但相关统计信息仍保留。这是由于简单配额只将extent归属于首次分配它的子卷，而该子卷已完全删除但extent仍被其他子卷引用。

根据需求，可以添加一些显示选项（到 `show` 之后）。常用的选项有：

- `-p`：显示父配额组。
- `-c`：显示子配额组。
- `-r`：显示总引用空间限制。
- `-e`：显示独占引用空间限制。
- `-f`：仅列出`路径`所在子卷对应的配额组。
- `-F`：仅列出`路径`所在子卷对应的配额组及包含这些配额组的高层级配额组。

更多选项请参阅 btrfs-qgroup(8) § show。

##### 配额重扫描

配额重扫描（quota rescan）会读取文件系统中所有extent的元数据，据其更新各配额组的统计值。

Btrfs的配额组可以处理许多复杂的extent共享和不再共享场景（包括子卷、子配额组的删除），同时保持总引用空间与独占引用空间的准确计数。但当配额组关系发生变化（手动 #分配/解除分配子配额组）时，由于记录的数据不足（仅记录总引用空间与独占引用空间，而未明确记录哪些extent属于共享或独占），通常需要在整个文件系统内配额重扫描，此时配额组会被标记为“inconsistent”（不一致），即需要配额重扫描的状态。

目前实现中唯一的例外是配额组的总引用空间等于独占引用空间（即所有数据都为独占）时，仅需要在父配额组的总引用空间与独占引用空间上同时加上/减去该配额组的引用空间，不需要重新扫描配额。

自4.19版本内核起，手动#分配/解除分配子配额组时会自动触发配额重扫描（除了以上例外情况）。但考虑到其开销较大、同时只能进行一个操作、无法等待重扫描结束后再返回，可以在 `assign`/`remove` 之后添加 `--no-rescan` 选项以避免自动触发重扫描，转而在之后再手动触发。

提示：使用 `--no-rescan` 选项#分配/解除分配子配额组后，若需要配额重扫描，会显示相应警告。也可以通过#列出配额组显示警告。

使用以下命令手动触发重新扫描`路径`所在文件系统的配额：

    # btrfs quota rescan 路径

命令运行后立即返回，添加 `-w`（`--wait`）选项（到 `rescan` 之后）以等待重新扫描结束（即使已开始）再返回。使用 `-W`（`--wait-norescan`）选项仅等待当前正在运行的重新扫描结束。使用 `-s`（`--status`）选项返回当前进度。

#### 简单配额

#配额组可以处理许多复杂的extent共享和不再共享场景（包括子卷、子配额组的删除），同时维护总引用空间与独占引用空间的准确计数，但这种灵活性是有代价的：许多计算操作具有全局性，即当extent引用关系变更后，会影响到引用该extent的所有配额组的统计值。这可能导致事务提交速度下降并引发不可接受的延迟，尤其在快照数量激增的情况下更为明显。

为解决配额组的这一局限，Btrfs还支持另一套配额规则体系：简单配额（simple quota，简称squota）。简单配额复用了配额组的API和层次结构模型，但不追踪共享与独占使用情况。相反，简单配额将所有extent归属于首次分配它的子卷。通过引入少量新的元数据记录，这样所有核算决策都能在涉及数据块本身的分配或释放操作的局部完成，完全避免了复杂且耗时的反向引用解析过程。

简单配额需要在文件系统级别启用，在启用配额组的命令中添加 `-s`（`--simple`）选项（到 `enable` 之后）即可。注意若配额组已经开启，需要先禁用配额组再启用简单配额，否则不会生效 [12]。由于其简单的计算方法，简单配额模式下不需要（也不能）进行#配额重扫描。除了这两点外，简单配额的操作方式与配额组完全相同，但显示与限制使用的所谓“总引用空间”和“独占引用空间”都是通过上文所述方法（将所有extent归属于首次分配它的子卷）计算得到的值。由于简单配额需要记录首次分配extent的子卷，因此仅对启用后写入的extent生效，若在非空文件系统中启用简单配额，刚启用时统计值会是0，因此只有在空子卷启用简单配额限制后再写入数据，才能确保统计准确。

### 提交间隔

Btrfs 默认设置 30 秒的事务提交（commit）间隔，即每 30 秒将新数据从内存同步到永久存储。可通过 `commit` 挂载参数（单位为秒）更改，例如修改 fstab：

    LABEL=arch64 / btrfs defaults,noatime,compress=lzo,commit=120 0 0

Btrfs 层面的周期性提交并非事务提交的唯一机制，该操作也可通过 `sync` 命令显式触发，或通过影响全局文件系统状态的其他命令间接触发，事务提交的机制还包括基于各类阈值或策略（如控制组）进行刷新的内核机制，这超出了本文的范围，因此不再赘述。

### 固态硬盘数据块异步丢弃

TRIM 或丢弃（discard）数据块是指文件系统通知固态硬盘哪些数据块不再使用的操作，从而固态硬盘能够在空闲时擦除（回收）这些数据块，避免等到需覆盖时再进行。内核 6.2 版本起默认启用异步丢弃功能：extent在释放事务提交后不会立即触发丢弃其包含的数据块，而是由独立的工作线程分组后统一进行，从而改善提交延迟。

异步丢弃可以与定期 TRIM 一同使用 [13]。

有关 TRIM 的更多信息，请参阅固态硬盘#TRIM。

## 使用

### 查看空间使用情况

因为不能同时考虑文件和元数据的使用情况，df(1) 之类的通用用户空间工具在 Btrfs 上并不能准确地报告剩余空间大小。推荐使用 `btrfs filesystem usage` 来查看空间使用情况，例如：

    # btrfs filesystem usage /

或者使用 `btrfs filesystem df` 快速检查已分配空间及其使用情况，无需 root 权限：

    $ btrfs filesystem df /

注意：对于 #多设备文件系统，在 `RAID5` 或 `RAID6` #profile 与其它 profile 共存于同一文件系统时（例如，元数据使用 `DUP` 而数据使用 `RAID5`），`btrfs filesystem usage` 和 `btrfs filesystem df` 显示出的空间使用情况不准确 [14]。

更多信息可参阅 [15]。

因为不考虑 #写时复制（CoW）和透明 #压缩，du(1) 和 ncdu(1) 之类的文件空间使用情况分析工具的数据也不准确。可考虑改用 btduAUR 或 compsize 等支持 Btrfs 特性的工具。

### 碎片整理

文件碎片整理是指尝试通过让文件包含的extent分布更加连续，合并小的extent，从而更有效地存储文件的过程。

由于 Btrfs 的 #写时复制（CoW）设计，修改文件时使用的新数据块在物理设备上可能与原数据块相距很远，造成文件的碎片化。碎片化在机械硬盘上是严重的问题，因为移动磁头到较远位置会导致延迟。对于现代没有这种延迟的设备（如固态硬盘）来说，这不再是问题，但进行碎片整理仍有意义，可以减少追踪分散extent所需的元数据大小。

可以安全地碎片整理使用中的文件数据，但更难达到最优分布。

警告：碎片整理会断开#写时复制（CoW）数据（包括通过 `cp` 复制的文件、#快照和#去重数据等）之间的 reflink，产生多份独立的数据，可能显著增加空间使用量 [16]。

#### 手动

使用 `btrfs filesystem defragment` 命令手动进行碎片整理，例如碎片整理根目录下的文件（不进入子卷、挂载点及到目录的软链接）：

    # btrfs filesystem defragment -r /

注意：不使用 `-r` 参数则碎片整理不会递归进行，但会对某些内部树⸺区段树（extent tree）和子卷树⸺进行碎片整理。这种设计容易引发混淆，未来版本可能会取消。
提示：可以使用 `-c`、`-L` 参数指定压缩方式，参见压缩章节中 #为现有文件启用部分。

#### 自动

使用挂载参数 `autodefrag` 启用自动碎片整理，参见 btrfs(5) § MOUNT OPTIONS。

### scrub

scrub文件系统或设备是指验证其中所有数据和元数据的过程，能够检测数据校验和错误、基本超级块错误、基本元数据块头错误以及磁盘读取错误。

注意：运行中的检修任务会阻止系统挂起，详见该讨论。

#### 手动启动

使用以下命令在后台启动 scrub 任务（此处“设备”指 Linux 块设备）：

    # btrfs scrub start 路径或设备

如果指定路径，则 scrub 路径所在的文件系统；如果指定设备，则 scrub 该设备。

注意：在使用镜像块组 #profile（如 RAID1）的 #多设备文件系统上，scrub 操作还会通过从其他副本复制已验证完好的数据来自动修复任何损坏。

检查该任务的运行状态：

    # btrfs scrub status /

也可以通过启动 `btrfs-scrub@.service` 来手动运行 scrub (使用同样的转移后路径)，相较 (以 root 用户身份运行) `btrfs scrub`，这么做的优点是输出内容会记录在 Systemd 日志中。

#### 自动

btrfs-progs包 软件包带有 `btrfs-scrub@.timer` 系统单元，用来每月运行 scrub 命令。通过添加挂载点的参数来启用它，例如`btrfs-scrub@-.timer` (`/`) 或者 `btrfs-scrub@home.timer` (`/home`)。你可以使用`systemd-escape -p /path/to/mountpoint`来转义路径，参见systemd-escape(1)。

### balance

‘balance 将会通过分配器再次传递文件系统中的所有数据。它主要用于在添加或删除设备时跨设备重新平衡文件系统中的数据。如果有设备出现故障，balance 将为指定的冗余 RAID 级别重新生成缺失的副本’[17]。参阅上游的 FAQ。

在单设备文件系统上，balance 对于（临时）减少分配但未使用（元）数据块的数量也是有用的。有时候这对于解决 "filesystem full" 故障来说也是必须的。为减少无法分配出元数据块组的可能，不建议对元数据进行 balance 操作，可指定如 `-dusage=30`只对数据块组操作。

    # btrfs balance start --bg /
    # btrfs balance status /

### 交换文件

注意：

Btrfs 与 Linux 交换子系统的实现导致一些限制 [18]：

- 不支持在跨设备的文件系统上使用交换文件
- 数据 #profile 需为 `single`
- 不能为含有正在使用中的交换文件的子卷创建快照
- 交换文件必须预分配（即无空洞）
- 必须单独为交换文件 #禁用写时复制（即交换文件必须有 `+C` 属性）

其中后两个对交换文件的限制 `btrfs filesystem mkswapfile` 命令会自动处理。

交换文件的介绍参见 Swap#交换文件。

在 Btrfs 中创建交换文件的正确方法是首先创建一个子卷存储交换文件，因为随后无法为该子卷创建快照。例如创建 `/swap` 子卷：

    # btrfs subvolume create /swap

提示：考虑直接在顶层子卷下 #创建子卷，然后 #挂载子卷到 `/swap`（或其他可访问路径）。

在 `/swap/` 中创建一个 4 GiB 的交换文件 `swapfile`：

    # btrfs filesystem mkswapfile --size 4g --uuid clear /swap/swapfile

`--size` 选项指定交换文件大小，默认为 2 GiB，最小 40 KiB。

启用交换文件：

    # swapon /swap/swapfile

最后编辑 fstab，添加交换文件的配置：

    /etc/fstab

    /swap/swapfile none swap defaults 0 0

更多信息参见 fstab#用法。

有关删除交换文件等更多信息请参阅 Swap#交换文件。

提示：若要使用休眠功能，除了配置交换文件外，还需要完成电源管理/挂起与休眠中描述的额外步骤。

### RAID

Btrfs 提供对 RAID #多设备文件系统的原生支持。相较于使用 mdadm，其显著优势包括自修复冗余阵列和在线数据平衡。更多信息请参见该 Btrfs Wiki 页面。Btrfs SysadminGuide 提供了一些更具技术性的背景信息。

警告：奇偶校验 RAID（RAID 5/6）代码中存在多个严重的数据丢失漏洞。更多信息请参阅 Btrfs 文档的 RAID 5/6 页面（英文）以及 linux-btrfs 邮件列表中关于此问题的错误报告。2020 年 6 月，有用户在上述邮件列表中整理发布了当前问题的完整清单及实用的恢复指南。

### 快照

"快照是和其它子卷共享数据和元数据的简单子卷, 利用了 btrfs 的写时复制特性。" 详见 Btrfs Wiki SysadminGuide#Snapshots 和 the Btrfs documentation。

要创建一个快照:

    # btrfs subvolume snapshot source [dest/]name

`source`为要创建快照的对象，`[dest/]name`为快照安放路径。

加入 `-r` 参数可以创建一个只读快照. 为只读快照创建一个快照可以获得一个只读快照的可写入版本.

注意：

- 将一个只读快照通过`btrfs property set -f -ts '/path/to/snapshot' ro false`原位转换为可写快照是可能的。但并不推荐这样做，因为之后任何增量发送/接受（send/receive）操作会造成问题。创建一个新的可写快照可以预防这类问题。
- 快照不是递归包含的，这意味着子卷内的子卷在快照里是空目录。

### 发送和接收

可以通过 `send` 命令发送一个快照,通常会与 btrfs 中的 `receive` 组成管道.例如将快照 `/root_backup` (也许是`/`的备份) 发送到 `/backup`:

     # btrfs send /root_backup | btrfs receive /backup

只能发送只读快照,上面的命令在将子卷复制到外部设备 (例如备份驱动器) 时会很有用。

接受结束后将创建对应子卷，无需手动再创建。

还有一个例子创建了`/mnt/arch-v2/subvolumes/@var`子卷：

    # btrfs send --proto 2 --compressed-data '/mnt/arch/snapshots/@var' | btrfs receive '/mnt/arch-v2/subvolumes/'

参数`--proto 2`和`--compressed-data`在本例中能够更有效地发送快照（假设数据可压缩）。

也可以只发送两个快照间发生变化的部分,例如如果你已经发送了快照 `root_backup` ,然后又建立了一个新的只读快照 `root_backup_new` ,可以这样完成增量发送:

     # btrfs send -p /root_backup /root_backup_new | btrfs receive /backup

现在你 `/backup` 的快照会是 `root_backup_new`。

参阅 Btrfs Wiki 上关于增量备份的页面 (英文) 获得更多信息 (例如使用工具自动化这一过程)。

### 去重

使用写时复制，Btrfs 能够复制文件或整个子卷而无需实际复制数据。但是，无论何时更改文件，都会创建一个新的“真正的”副本。重复数据删除更进一步，通过主动识别含有相同内容的数据块并将它们通过 CoW 合并到同一个extent内。

专用于 Btrfs 分区去重的工具包括 duperemove包和bees包。也许你还希望基于文件的级别对数据进行重复数据删除，比如 rmlint-git包、rdfind包、jdupesAUR 或者 dduper-gitAUR。有关这些程序的可用功能的概述和其他信息，请参阅上游 Wiki 条目 (英文)。

### 调整大小

警告：为避免数据丢失，确保在调整大小前备份好你的数据。

你可以增加文件系统的大小到设备的最大可用空间，或到一个指定大小。确保你在尝试增加文件系统大小前设备或逻辑卷有足够空间。 当指定一个设备上的文件系统到指定大小时，不论增加或减少，确保新的大小满足下面的条件：

- 新的大小必须大于已有数据的大小，否则会导致数据损失。
- 新的大小必须等于或小于当前设备的可用空间。

注意：如果你还计划减小文件系统所在的逻辑卷大小，请先减小文件系统大小后再尝试减小逻辑卷的大小。

将文件系统扩展到设备的最大可用大小：

    # btrfs filesystem resize max /

将文件系统扩展到特定大小：

    # btrfs filesystem resize size /

将 `size` 替换为你需要的大小（按字节计算）。也可以为大小指定单位，如K（千字节），M（兆字节）或G（吉字节）。 或者也可以通过在大小前添加前缀指定增加（+）或减少（-）的变化量：

    # btrfs filesystem resize +size /
    # btrfs filesystem resize -size /

## 已知问题

一些在尝试之前应该知道的限制。

### 加密

Btrfs 暂未内置加密支持，但当前正进行一项基于 Fscrypt（英语：Fscrypt） 的加密集成工作 [19]。

不过用户仍可在运行 `mkfs.btrfs` 前加密分区，具体参见 dm-crypt/加密整个系统。另一种方案是采用栈式文件系统加密。

### 检查 btrfs 文件系统问题

`btrfs check` 工具目前有一些已知问题，在继续深入阅读了解之前，您不应该直接运行它, 参见 #检查 Btrfs 文件系统小节。

## 提示和技巧

### 无分区 Btrfs 磁盘

警告：这种配置不建议用于启动设备，推荐设置一个单独的EFI 系统分区和Btrfs分区。 此外，GRUB 强烈反对安装GRUB到无分区磁盘。

Btrfs 能占用整个存储设备，使用子卷模拟分区表来替代 MBR 或 GPT 分区表。虽然无分区磁盘不需要使用其它方法创建分区，然后在一个分区上创建 Btrfs 文件系统，但在单个磁盘上使用无分区配置存在一些限制：

- 不能在同一磁盘上的不同分区上创建其它的文件系统。
- 受上一条影响，无法在该磁盘上创建EFI 系统分区。需要额外的储存设备用于 UEFI 启动。

运行下面的命令把整个设备的分区表替换成 Btrfs:

    # mkfs.btrfs /dev/sdX

如果设备上存在分区表，则需要使用：

    # mkfs.btrfs -f /dev/sdX

例如， 指定`/dev/sda` 而不是 `/dev/sda1`。后一种形式会格式化现有的分区而不是替换掉原有的分区表。由于根分区是 Btrfs 文件系统，请确保已将 `btrfs` 编译进内核, 或者将 `btrfs` 放入 Mkinitcpio#模块（MODULES）中并且重新生成 initramfs。

像使用普通的 MBR 分区表存储设备一样安装引导加载程序, 参考 Syslinux#手动安装或 GRUB/技巧和窍门#安装到分区上或者无分区磁盘上。 如果你的内核因为 `Failed to mount /sysroot.` 错误无法启动, 请在 `/etc/default/grub` 里添加 `GRUB_PRELOAD_MODULES="btrfs"` 并重新生成 GRUB 配置文件 。

### 从 Ext3/4 转换

警告：Btrfs 的邮件列表中报告了多起转换不完整/损坏/失败的案例。在开始之前请确定您有可用的备份并且愿意承担丢失数据的风险。 参见Btrfs维基的Convert页。

从安装 CD 启动，然后转化分区：

    # btrfs-convert /dev/partition

挂载转换后的分区并修改 `/etc/fstab` 文件，指定分区类型 (type 为 btrfs，并且 fs_passno[最后一列] 要修改为0，因为 Btrfs 在启动时并不进行磁盘检查)。 还要注意的是分区的 UUID 将有改变，所以使用 UUID (指定分区) 时，请更新 fstab 中相应的条目。 `chroot` 到系统并重建你的引导加载程序（如果对此过程不熟悉，参考从现有 Linux 发行版安装 Arch Linux )。 如果转换了根文件系统，还需要在 chroot 环境中重建初始化内存盘以确保系统正确启动。

注意：

- 如果转换过程中有任何异样，不管是无法挂载新转换的 Btrfs 文件系统或是无法往其中写入数据，只要备份子卷 `/ext2_saved` 还在，就可以进行回滚。请使用 `btrfs-convert -r /dev/partition` 命令进行回滚，这将会丢弃任何对新转换 Btrfs 文件系统的更改。
- 如果挂载已转换的 ext 分区时出现如下错误：`ERROR: dev extent devid 1 physical offset XXX len XXX is beyond device boundary XXX`，那么在分区末尾预留一些空闲空间后，转换可能会成功。请先回滚转换，然后使用 `resize2fs` 将分区缩小 50000 个块，再扩大 5000 个块（从而创建出 45000 个空闲块）。然后再次尝试转换。参见 上游 bug 报告。

确认没有问题后，通过删除 `ext2_saved` 备份子卷完成转换的最后一步。请注意，如果没了它 (备份子卷)，你将没办法还原回 ext3/4 文件系统。

    # btrfs subvolume delete /ext2_saved

最后通过数据平衡回收空间。

别忘了先前安装的一些应用需要额外设置来适配Btrfs。

注意：Ext3/4 转换到 Btrfs 的过程很耗时。一个普通机械硬盘上的4TB文件系统转换耗时可高达10小时。

### 从 NTFS 转换

使用 ntfs2btrfsAUR 或 ntfs2btrfs-gitAUR 转换NTFS分区。 卸载目标文件系统并运行转换，并指定确切的压缩和校验和类型：

    # ntfs2btrfs -c zstd -h crc32c /dev/partition

如果转换后一切正常，你可以删除原本用于恢复原始文件系统的 `image/ntfs.img` 。

#### 转换后

警告：只有在确认不会恢复到原始文件系统后，才执行这些步骤，因为它们会使得恢复变得不可能，即使你保留了恢复文件。

可以在将现有文件系统转换为 Btrfs 后采取一些步骤使文件数据更连续。

    # btrfs filesystem defrag -v -r -f -t 32M /mnt/filesystem

#Balance 使 Btrfs 元数据更加紧凑

### 损坏恢复

警告：`btrfs check` 工具有一些已知问题，参见 #检查 Btrfs 文件系统 小节。

btrfs-check 不能在一个已挂载的文件系统上工作。为了能够在不从 Live USB 启动的情况下使用 btrfs-check，需要将其添加到初始内存盘：

    /etc/mkinitcpio.conf

    BINARIES=(btrfs)

然后重新生成 initramfs。

之后如果启动时出现问题，则可以使用该实用程序进行修复。

注意：如果 fsck 进程必须使空间缓存 (和/或其他缓存？) 无效 (invalidate cache)，那么随后的引导会挂起一段时间，这是正常的（进程可能会给出关于 btrfs-transaction 挂起的控制台消息）。系统应该在一段时间后从中恢复正常。

查阅 btrfs-check(8) 以获取更多信息。

### 引导进入快照

要引导进入快照，因为快照可以像子卷那样被挂载，所以请像挂载子卷为根分区那样进行同样的流程 (已交代于#挂载子卷为根挂载点的一段中)。

- 如果使用 GRUB，则可以在 grub-btrfs包 或 grub-btrfs-gitAUR 的帮助下，在重新生成配置文件时使用 Btrfs 快照自动填充启动菜单。

- 如果使用 rEFInd，则可以在 refind-btrfsAUR 的帮助下，启用 `refind-btrfs.service`后，在重新生成配置文件时使用 Btrfs 快照自动填充启动菜单。

- 如果使用 Limine（英语：Limine），可安装 limine-snapper-syncAUR。该工具在启用 `limine-snapper-sync.service` 后，每当 Snapper 列表变更时，将自动在启动菜单中生成快照条目。详情参见 Lamine#Btrfs 的 Snapper 快照集成（英语：Limine#Snapper snapshot integration for Btrfs）。

### 搭配 systemd-nspawn 使用 Btrfs 子卷

可查阅 systemd-nspawn#使用Btrfs子卷作为容器的根和 systemd-nspawn#在 systemd-nspawn 中运行 docker 等文章。

### 减少访问时间元数据的更新

由于Btrfs的写时复制性质，访问文件就能够触发元数据的写时复制。减少访问时间的更新频率可能会消除这种不希望的硬盘使用并提高性能。参见Fstab#atime 参数

### 增量备份到外置设备

下列包利用 `btrfs send` 和 `btrfs receive` 将备份增量发送到外置设备上。 参考它们的文档来查看实现，功能和需求的不同。

- btrbk — Btrfs子卷的快照和远程备份工具

  https://github.com/digint/btrbk || btrbk包

- snap-sync — 使用Snapper快照并备份到外置设备或远程机器

  https://github.com/wesbarnett/snap-sync || snap-sync包

下列工具运行备份snapper快照到非Btrfs文件系统。

- snapborg — 一个类似borgmatic的工具，将snapper快照与borg包整合起来

  https://github.com/enzingerm/snapborg || snapborgAUR

### 自动快照

要管理并自动创建快照，你可以使用像Snapper，Timeshift或Yabsnap这样的快照管理器。

### 自动通知

桌面通知能帮助您及时察觉严重的 Btrfs 问题，相较于完全不提供通知，能提供更好的问题感知。

btrfs-desktop-notificationAUR 为以下事件提供桌面通知：

- 启动进入任何只读快照或系统时
- dmesg 日志中出现 Btrfs 警告、错误或致命消息

更多信息及配置方法，请参见 https://gitlab.com/Zesko/btrfs-desktop-notification .

### 空间缓存v1正在被弃用

如果你的 Btrfs 文件系统是用旧的默认设置创建的，你可能会在你的系统日志中看到类似的警告:

    BTRFS warning (device sdb4): space cache v1 is being deprecated and will be removed in a future release, please use -o space_cache=v2

将 Btrfs 空间缓存从旧版 v1 格式转换为新版 v2 格式并解决此警告. 你可以修改分区挂载选项，在 fstab 中包含 `space_cache=v2` 或者手动进行转换：

    # umount /dev/partition
    # mount /dev/partition -o rw,space_cache=v2 /mnt
    # umount /mnt

注意：在此转换后，Btrfs会在文件系统上设置一个compat-ro功能标志。因此，该文件系统可能无法再被非常旧的Btrfs内核实现挂载。

## 疑难解答

请查阅 Btrfs 疑难解答和Btrfs 常见问答集（英文）以获得排除一般问题的信息。

### 启动缓慢

有时，大于4TB的Btrfs卷需要较长时间才能挂载，从而导致系统启动变慢。 将群组树更改为块组树有助于解决该问题：

    # btrfstune --convert-to-block-group-tree /dev/device

### GRUB

#### 分区偏移

注意：当您试图将 `core.img` 嵌入到已分区磁盘上时，可能会发生偏移问题。这意味着可以将 GRUB 的 `corg.img` 直接嵌入到无分区磁盘 (例如 `/dev/sdX`) 上的 Btrfs 存储池中。

GRUB 可以引导启动 Btrfs 分区，但是因为模块可能会比其它文件系统大，`grub-install` 生成的 `core.img` 文件超过了 MBR 与第一个分区之间的空间大小 (63 扇区/31.5KiB)。最新版的 `fdisk` 和 `gdisk` 等磁盘工具会通过第一个分区前空出 1-2MiB 的空间来避免此问题。

#### 根丢失

本文或本章节的事实准确性存在争议。

原因： Suggests editing a non-configuration file manually.（在 Talk:Btrfs#Should not suggest to edit files in /usr/share 中讨论）

当从一个RAID配置的系统中启动用户可能会遇到错误：`error no such device: root`。编辑`/usr/share/grub/grub-mkconfig_lib`，移除行`echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"`中的两个引号。重新生成grub的配置文件，后系统应该能够正常启动。

警告：不建议覆盖软件包提供的文件，因其会在下次更新时被覆盖。

### 挂载超时

有时（尤其在大型 RAID1 阵列上）系统启动时会出现挂载超时的现象，并带有如下日志信息：

    Jan 25 18:05:12 host systemd[1]: storage.mount: Mounting timed out. Terminating.
    Jan 25 18:05:46 host systemd[1]: storage.mount: Mount process exited, code=killed, status=15/TERM
    Jan 25 18:05:46 host systemd[1]: storage.mount: Failed with result 'timeout'.
    Jan 25 18:05:46 host systemd[1]: Failed to mount /data.
    Jan 25 18:05:46 host systemd[1]: Startup finished in 32.943s (firmware) + 3.097s (loader) + 7.247s (kernel)>
    Jan 25 18:05:46 host kernel: BTRFS error (device sda): open_ctree failed

这可以通过 fstab 中特定的 systemd 挂载选项 `x-systemd.mount-timeout` 提供系统以更长的超时时间来轻松解决。例如：

     UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /data  btrfs  rw,relatime,x-systemd.mount-timeout=5min  0 0

### 出现 BTRFS: open_ctree failed 错误

本文或本章节的事实准确性存在争议。

原因： 内容过时。自从systemd和udev都使用systemd-udevd后，用systemd替换udev钩子没有任何意义。（在 Talk:Btrfs 中讨论）

截至 2014 年 11 月，一个似乎存在于 systemd 或 mkinitcpio 中的 Bug 可能会导致在 `mkinitcpio.conf` 中使用 `btrfs` 钩子（hook）的用户在启动多设备文件系统的 Btrfs 卷时遇到以下错误：

    BTRFS: open_ctree failed
    mount: wrong fs type, bad option, bad superblock on /dev/sdb2, missing codepage or helper program, or other error

    In some cases useful info is found in syslog - try dmesg|tail or so.

    You are now being dropped into an emergency shell.

一种解决办法是，在`/etc/mkinitcpio.conf`中，将 `HOOKS` 中的 `btrfs` 移入 `MODULES` 中，然后重新生成 initramfs 并重新启动。

另外，如果在挂载 RAID 卷组缺少某个卷时，也有可能会发生这个错误。这种情况下，需要把 `degraded` 加入到 `/etc/fstab` 中；如果根目录在卷组上，需要同时加入内核参数 `rootflags=degraded`。

接上文，截至 2016 年 8 月，针对这一问题，一个可能的解决方案是在 `/etc/fstab` 中仅靠单个硬盘来挂载阵列，然后让 Btrfs 自动发现并追加其它硬盘。UUID 和 LABEL 等基于组的标识符似乎是导致出现错误的原因。比如说，由“disk1”（磁盘 1） 和“disk2”（磁盘 2）组成的双设备 RAID1 阵列会被分配到一个 UUID。但是请在 `/etc/fstab` 中只使用 `/dev/mapper/disk1` 来指定磁盘阵列，而不要使用 UUID。更多解释，参见这个博客文章。

另一个可能的解决方法是在 mkinitcpio.conf 中移除 `udev` 钩子并替换为 `systemd` 钩子。此时 `btrfs` 不应出现在 `HOOKS` 或 `MODULES` 列表中。

请查阅原论坛讨论和 FS#42884 获得更多的讨论内容和信息。

### 检查 Btrfs 文件系统

本文或本节内容已经过时。

原因： "大开发阶段"状态已经过时。 (在Talk:Btrfs讨论)
警告：Btrfs（特别是 `btrfs check` 命令工具）仍处在大开发阶段，强烈建议在加上 `--repair` 参数运行 `btrfs check` 前先做一个备份，并提前查阅 btrfs-check(8)。

btrfs-check(8) 可以检查并修复一个未挂载的 Btrfs 文件系统。但是由于它尚未开发完成，它并不能修复某些错误（即使这些错误没有导致文件系统无法挂载）。

### 持续的硬盘活动

自内核版本6.2开始， mount(8) 默认启用 `discard=async` 选项。 这个设置被报告会造成硬盘的持续活动（甚至是待机状态下），因为丢弃队列填充的速度快于其处理速度。这会造成电源使用增加，特别是NVMe设备。

到了内核版本6.3后，问题的解决办法是将`iops_limit`默认值从100改为1000。在旧版内核上，你可以手动设置到一个需要的值，例如：

    # echo 1000 > /sys/fs/btrfs/uuid/discard/iops_limit

其中`uuid`是btrfs文件系统的UUID。限制值`1000`需要通过实验进行调整。

要在启动时设置该参数，可能要用到Systemd#systemd-tmpfiles - 临时文件，例如创建下列文件：

    /etc/tmpfiles.d/btrfs-discard.conf

    w /sys/fs/btrfs/uuid/discard/iops_limit - - - - 1000

或者在fstab中使用`nodiscard`挂载选项禁用异步丢弃功能，使用定期TRIM来替代。

### Device total_bytes should be at most X but found Y

若驱动器从其他计算机迁移或设备顺序变更，且报告的大小差异极小（至多几MB），可能是启用了 HPA（主机保护区域）。

可使用 hdparm包 验证 HPA 是否启用：

    # hdparm -N 设备

输出将显示两个数值：可见扇区数与实际扇区数。若两者不同则表明HPA已启用。

若主板强制设置此功能且固件未提供关闭选项，唯一解决方案是收缩受影响文件系统。此操作最易在原始计算机或未应用HPA的机器上执行。

### 设备空间不足

博客文章《解决Btrfs文件系统空间不足问题》建议并解释了以下检查步骤：

1. 立即清理空间（删除历史快照）
2. 文件系统是否真满？元数据和/或数据块分布不均（运行 `btrfs balance`）
3. 文件系统是否真满？数据块分布不均
4. 文件系统是否真满？元数据分布不均
5. 因空间不足无法执行平衡操作（运行 `btrfs balance` 前，先用 `btrfs device add` 临时添加设备如U盘或环回设备）

另可参阅 btrfs 元数据满了怎么办 - 依云's Blog。

有关 ENOSPC（“磁盘空间不足”）的最新处理指南，请参阅 ENOSPC - No available disk space | Forza's Ramblings。

## 另请参阅

- 官方网站
  - Btrfs 文档
  - 已归档的 Btrfs 百科
- 性能相关
  - Btrfs on raw disks?
  - Varying leafsize and nodesize in Btrfs
  - Btrfs support for efficient SSD operation (data blocks alignment)
  - Is Btrfs optimized for SSDs?
  - Lzo vs. zLib
- 杂项
  - Funtoo:BTRFS Fun
  - Avi Miller presenting Btrfs at SCALE 10x, January 2012.
  - Summary of Chris Mason's talk from LFCS 2012
  - Btrfs: stop providing a bmap operation to avoid swapfile corruptions 2009-01-21
  - Doing Fast Incremental Backups With Btrfs Send and Receive

1. ↑ bees 的 issue 中有讨论过，具体链接以后再补。

分类：​

- 文件系统
- 使用“模板:风格”标记的页面或章节
- 使用“模板:过时”标记的页面或章节

隐藏分类：​

- 使用“模板:准确性”标记的页面或章节

Btrfs
添加话题