Btrfs

来自 Arch Linux 中文维基

引自 Btrfs 文档介绍

BTRFS 是一种现代的写时复制(COW)Linux 文件系统,致力于实现一些高级功能,同时着重于容错性、修复性以及易于管理性。
注意:

和其它一些文件系统一样,Btrfs也在进行不断地开发。这意味着某些功能可能还不适合用于日常使用。要确认你的用例是否受到影响,参见Btrfs的状态文档(英文)和本文的#已知问题部分。

准备工作[编辑 | 编辑源代码]

安装基础操作所必须的 btrfs-progs 软件包以使用用户空间工具。

如果需要从 Btrfs 文件系统引导启动(比如说内核和初始内存文件系统(initramfs)驻留在 Btrfs 分区上),请检查启动引导器是否支持 Btrfs。

创建文件系统[编辑 | 编辑源代码]

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

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

单一设备上的文件系统[编辑 | 编辑源代码]

要在分区 /dev/partition 上创建一个 Btrfs 文件系统,执行:

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

Btrfs 用于元数据的默认节点大小 (nodesize) 为 16 KiB,而用于数据的默认扇区大小 (sectorsize) 等于页面大小 (page size) 并会自动检测。 要对元数据使用较大的节点大小 (必须为扇区大小的倍数,最大允许 64 KiB),请通过 -n 选项开关指定 nodesize 的值。如下例所示,要使用 32 KiB 大小的块:

# mkfs.btrfs -L 自定义标签 -n 32k /dev/分区名
注意: 根据 mkfs.btrfs(8) § OPTIONS 手册页内容:“较小的节点大小会增加分页,但也会让 B 树更高,进而减少线程锁竞争。较高的节点大小则能更好地打包数据和减少分页,但代价是,更新元数据块时会使用更多的内存”。

多设备文件系统[编辑 | 编辑源代码]

警告:

多个设备可以用来创建一组 RAID。支持的 RAID 级别有 RAID 0、RAID 1、RAID 10、RAID 5 和 RAID 6。从 5.5 版本内核开始,新增对 RAID1c3RAID1c4 的支持,它们分别是带 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 钩子或 btrfs 钩子才能在一个池中使用多个 Btrfs 设备。查阅 Mkinitcpio#常用钩子以获取更多信息。

一旦创建好了文件系统,建议使用下面的命令扫描多设备Btrfs文件系统并注册它们,这样在挂载多设备文件系统时就仅需指定其中的一个设备:

# btrfs device scan
注意:
  • 可以稍后再将设备添加到多设备文件系统中。详情请参见 Btrfs wiki 文章
  • 多个设备可以大小各异。但是,如果在 RAID 配置中一个硬盘的大小比其他的都大,那么它多出的空间将不会被使用。
  • 有些 引导加载程序 不支持多设备文件系统,比如 Syslinux
  • Btrfs 不会自动从速度最快的设备读取,因此混合使用不同类型的磁盘会导致性能表现不稳定。详情请参阅 Stack Overflow 上的这个回答

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

Profiles[编辑 | 编辑源代码]

Btrfs使用profiles这个概念来配置RAID的镜像、奇偶校验和条带属性,在标准的RAID术语中叫做RAID 级别。在同一个Btrfs文件系统中,元数据的Profiles(mkfs.btrfs(8)-m选项)和数据的Profiles(mkfs.btrfs(8)-d选项)可以不一样。

一些重要的Profiles:

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

配置文件系统[编辑 | 编辑源代码]

写时复制 (CoW)[编辑 | 编辑源代码]

默认情况下 Btrfs 总是对所有文件使用写时复制 (CoW)。写入不会就地覆盖数据;相反,数据块在被复制和修改后会写入到新的位置,元数据也会更新以指向新的位置。请参阅 Btrfs 系统管理指南相关章节以获取实现细节以及它的优点和缺点。

停用 CoW[编辑 | 编辑源代码]

警告: 在 Btrfs 中禁用写时复制会同时禁用数据校验和。Btrfs 将无法检测到损坏的 nodatacow 文件。与 RAID1 结合使用时,断电或其他导致损坏的原因可能会使数据失去同步。

要对某个子卷上的新文件停用写时复制,使用 nodatacow 挂载选项。这只会影响新创建的文件,写时复制仍然会在已存在的文件上生效。nodatacow 参数同样会禁用压缩。参阅 btrfs(5) 以了解细节。

注意: 根据 btrfs(5) § MOUNT OPTIONS: “在单个文件系统中,无法让某些子卷使用 nodatacow 参数挂载,而其他的使用 datacow 参数挂载。第一个被挂载子卷的挂载参数将会应用于其他所有子卷。“

要单文件或目录禁用写时复制特性,请使用下面的命令:

$ chattr +C /目录/文件

这会为这个文件的单个引用停用写时复制,如果这个文件不只有一个引用,比如文件有多个克隆或轻量克隆(clones / lightweight clones)或者在文件系统快照中,写时复制依然生效。注意自coreutils 9.0版本起,cp默认使用轻量复制,更多细节参见cp(1)

注意: 引自 chattr(1) 的手册页:
“在 Btrfs 上,'C' 标志应该被设置在新建的或者是空白的文件,如果被设置在已有数据的文件,当块分配给该文件时,文件将不确定是否完全稳定。如果 'C' 标志被设置给一个目录,将不会影响目前的目录,但在该目录创建的新文件将具有 No_COW 属性。”
提示:根据上文内容,可以用下面的方法为已存在的文件或目录停用写时复制:
$ 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
需要保证这个过程中目标文件不会被使用,同时注意下面描述的 mvcp 在没有--reflink=never时将不会生效。
对快照的影响[编辑 | 编辑源代码]

如果一个文件禁用了写时复制(NOCOW)并创建了一个快照,在快照后,第一次在该文件的块写入将会是一个COW操作,因为快照锁定了旧文件的块来确保内容正确。但文件依然保留了NOCOW属性,任何后续写入操作依然在本次快照后产生的相同文件块中进行,直到产生下一次快照。

频繁快照会降低NOCOW的效果,因为在每次快照后的第一次写入都需要COW。要避免这种情况,可以把所有NOCOW文件放在一个单独的子卷中并避免对该子卷进行快照操作。

压缩[编辑 | 编辑源代码]

Btrfs 支持透明和自动压缩。这就减小了文件的大小,通过减少文件写入增幅来显著延长闪存介质(flash-baesd media)的寿命 [1][2][3]。在某些特定的场景下(比如单线程、重负荷的文件 I/O))还提高了性能。尽管在其他的场景下(比如多线程和/或大文件 I/O 高强度 CPU 任务)还是明显影响了性能。通常使用更快的压缩算法,比如 zstdlzo 可以获得更好的性能,这个性能测试提供了详细的对比。

LZO的压缩等级是固定的,而ZLIB和ZSTD有从1到9(ZLIB)或15(ZSTD)的压缩等级,等级越高压缩率越大,参见btrfs(5) § COMPRESSION。改变压缩等级将直接影响CPU和I/0吞吐,建议在改变压缩等级前后进行检查或性能测试。

compress=alg[:level] 挂载选项可自动考虑为每个文件启用压缩,其中的 alg 处可以选填为 zlib, lzo, zstd, 或者 no(即不压缩)。由此,Btrfs 将检查压缩数据的第一部分是否能将其缩减。如果能,则会压缩该文件的整个写入;否则不会压缩任何内容。所以,如果数据的第一部分没有被缩减,那么即使数据的其余部分可以大大缩减,写入时也不会被压缩。[4]这样做是为了防止让磁盘一直等待写入,直到所有要写入的数据传递给 Btrfs 并被压缩后为止。

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

原因: 下文陈述的有关试验测试的结果缺少引用来源。 (在 Talk:Btrfs 中讨论)

另外可以改用 compress-force=alg[:level] 挂载选项,这会让 Btrfs 跳过对数据第一部分的压缩检查,并尝试对每个文件启用自动压缩。最不济的情况,这会 (稍微) 导致 CPU 占用率无故升高。不过,在多个混合使用系统的试验测试显示,与仅使用 compress=zstd (其也有 10% 的磁盘压缩率) 相比,使用 compress-force=zstd 可以显著提高约 10% 的磁盘压缩率。不过,请注意官方Btrfs指导手册不推荐使用强制压缩。

只有在加入挂载选项后创建或修改的文件才会被压缩。

给现存文件启用压缩,可使用 btrfs filesystem defragment -calg 命令,alg 处可选填为 zliblzozstd。举例来说,要用 zstd 方式给整个文件系统重新压缩,执行下列命令:

# btrfs filesystem defragment -r -v -czstd /
警告: 对具有 COW 副本(快照副本或使用cp或 bcp 创建的文件)进行碎片整理以及使用带压缩算法的 -c 开关进行碎片整理可能会导致生成两个不相关的文件从而大幅增加磁盘使用量。

要在新的 Btrfs 分区上安装 Arch Linux 时就启用压缩功能,请在挂载文件系统时使用 compress 选项:mount -o compress=zstd /dev/sdxY /mnt/。在配置过程中,请在 fstab 中把 compress=zstd 添加到根目录文件系统的挂载选项里。

提示:通过执行 chattr +cbtrfs property set file compression alg,也可以在不使用 compress 选项的情况下为每个单文件启用压缩属性。第一个命令适用于传统的文件属性(继承自ext2文件系统,不太灵活),因此压缩算法只能使用默认的zlib。第二个命令可以为压缩的文件指定压缩算法(但需要注意指定压缩级别目前还没有实现)。对目录执行会使这个目录下新文件自动被压缩。
警告:
  • 如果使用 zstd 参数,使用较旧版本内核或者尚不支持 zstdbtrfs-progs 的系统可能不能读取或修复您的文件系统。
  • GRUB 在 2.04 版本中引入了对 zstd 的支持。使用此后版本时,请通过手动运行 grub-install(需添加适用于机器 BIOS/UEFI 设置的选项参数)确保安装在 MBR/ESP 中的引导加载程序已确实升级,因为这些事情不会自动完成。可参阅 FS#63235

查看压缩类型和压缩比[编辑 | 编辑源代码]

compsize 软件包能获取一个文件列表 (或一整个 Btrfs 文件系统),并测量出它们使用的压缩类型和其有效压缩比。不过,其给出的未压缩时大小数值不一定能和其他程序 (比如 du) 给出的数值吻合,因为每一文件所占空间范围都会计数一次,即使文件被链接了多次,即使文件的一部分不再被使用 (但其未被垃圾回收)。 -x 选项可让程序运行保持在单一个文件系统上,这在 compsize -x / (检查根目录) 之类的情况下很有用,可以避免程序去尝试访问非 Btrfs 子目录从而导致整个程序运行失败。

子卷[编辑 | 编辑源代码]

"btrfs 子卷不是(也不能看作)块设备,一个子卷可以看作 POSIX 文件名字空间.这个名字空间可以通过子卷上层访问,也可以独立挂载。"[5]

每个 Btrfs 文件系统都有一个 ID 为 5 的顶层子卷,该子卷不能删除或被其他子卷替代。顶层子卷在文件系统中的路径为/,其他子卷嵌套在顶层子卷下。其他子卷能够在文件系统中移动,改变路径,但不能改变他们的ID.

默认情况下,顶层子卷会随着文件系统一块挂载,当然也可以挂载一个特定子卷

子卷的一个主要使用场景是#快照

参阅下面的链接获得更多信息:

创建子卷[编辑 | 编辑源代码]

要创建一个子卷,btrfs文件系统必须先挂载。子卷名通过最后一个参数设置。

# btrfs subvolume create /path/to/subvolume
注意: 如果路径中父目录不存在,你可以通过指定--parents选项自动创建对应的文件目录。

列出子卷列表[编辑 | 编辑源代码]

要列出当前路径 (path) 下的子卷和它们的 ID:

# btrfs subvolume list -p path

删除子卷[编辑 | 编辑源代码]

要删除一个子卷:

# btrfs subvolume delete /path/to/subvolume

用户也可以像移除常规目录一样删除一个子卷 (用 rm -r, rmdir 命令)。

挂载子卷[编辑 | 编辑源代码]

可以使用 subvol=/path/to/subvolumesubvolid=objectid 挂载标志来安装子卷,就像文件系统分区一样。例如,您可以拥有一个名为 subvol_root 的子卷,并将其挂载为 /。通过在文件系统的顶层创建各种子卷,然后将它们挂载到适当的挂载点,可以模仿传统的文件系统分区。建议使用subvol=/path/to/subvolume而不是子卷ID(subvolid)挂载,因为在恢复#快照时子卷ID可能会变化,需要修改挂载配置。

提示:不使用顶层子卷 (ID=5) 挂载为根目录,可以更方便地修改子卷的布局结构。相反,可考虑创建新的子卷,然后挂载为 /
注意: 引自 btrfs(5) § MOUNT OPTIONS:
“大多数挂载选项适用于整个文件系统,并且只有要挂载的第一个子卷的选项才会生效。 这是因为没有实现,未来可能会发生变化。”

可参阅 Btrfs Wiki FAQ 以了解哪些挂载参数能够被用于独立的子卷。

参阅 Snapper#推荐文件系统布局, Btrfs SysadminGuide#Managing SnapshotsBtrfs SysadminGuide#Layout 获得子卷应用的示例。

有关 Btrfs 特定的挂载选项的完整列表,请参阅 btrfs(5)

挂载子卷为根挂载点[编辑 | 编辑源代码]

要使用一个子卷作为根挂载点,可以通过设置默认子卷或指定 rootflags=subvol=/path/to/subvolume 内核参数。在 /etc/fstab 中编辑根挂载点并指定挂载选项 subvol=。或者可以在 /etc/fstab 中用 ID 指定子卷:用 rootflags=subvolid=objectid 作为内核参数并用 subvolid=objectid 作为挂载选项。建议使用subvol=/path/to/subvolume而不是子卷ID,因为在恢复#快照时子卷ID可能会变化,需要修改挂载配置,否则系统可能不会正确启动。

改变默认子卷[编辑 | 编辑源代码]

如果挂载时不指定 subvol= 选项便会挂载默认子卷。要改变默认子卷,执行:

# btrfs subvolume set-default subvolume-id /

subvolume-id 可以通过#列出子卷列表获得。

注意: 在安装了 GRUB 的系统上,在改变默认子卷以后不要忘记运行 grub-install ,让引导加载器发现默认子卷的变化。参见 这个论坛帖子

通过 btrfs subvolume set-default 修改默认子卷将会导致文件系统的最顶层无法访问,除非使用 subvol=/ 或者 subvolid=5 挂载参数。[6]

配额[编辑 | 编辑源代码]

警告: Qgroup 尚且不稳定且在有(过多)快照的子卷上应用配额可能会导致性能问题,比如在删除快照的时候。 此外,这里还有更多 已知问题.

Btrfs中的配额支持是通过使用配额组或 qgroup 在子卷级别实现的:默认情况下,每个子卷都以 0/subvolume_id 的形式分配配额组。 但是,如果需要的话,可以使用任意数字创建配额组。

要使用 Qgroup,你首先需要启用它:

# btrfs quota enable path

从此时开始,新创建的子卷将由这些配额组控制。 为了能够为已创建的子卷启用配额,首先正常启用配额,然后使用它们的 subvolume_id 为每个子卷创建一个配额组,再重新扫描它们:

# btrfs subvolume list path | cut -d' ' -f2 | xargs -I{} -n1 btrfs qgroup create 0/{} path
# btrfs quota rescan path

Btrfs 中的配额组形成树层次结构,其中 Qgroup 附加到子卷。大小限制由每个 Qgroup 独立配置且在并在包含给定子卷的树中达到任何限制时应用。

配额组的限制可以应用于总数据使用,非共享数据使用,压缩数据使用或全部。文件复制和文件删除可能都会影响限制,因为如果删除原始卷的文件并且只剩下一个副本,则另一个 Qgroup 的非共享限制可能会更改。例如,新快照几乎与原始子卷共享所有块,对子卷的新写入将向专用限制提升,一个卷中的公共数据的删除将升高到另一个卷中的专用限制。

要对 Qgroup 应用限制,请使用命令 btrfs qgroup limit。根据你的使用情况,使用总限制,非共享限制( -e)或压缩限制( -c)。

显示文件系统使用中给定路径的使用情况和限制:

# btrfs qgroup show -reF path

提交间隔[编辑 | 编辑源代码]

将数据写入文件系统的频率由 Btrfs 本身和系统的设置决定。Btrfs 默认设置为 30 秒检查点间隔,新数据将在 30 秒内被提交到文件系统。 这可以通过在 /etc/fstab 增加 commit 挂载参数来修改:

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

系统范围的设置也会影响提交间隔。它们包括 /proc/sys/vm/* 下的文件,这超出了本文的范围,因此不再赘述。 它们的内核文档位于 https://docs.kernel.org/admin-guide/sysctl/vm.html

固态硬盘 TRIM[编辑 | 编辑源代码]

Btrfs 文件系统能够从支持 TRIM 命令的 SSD 驱动器中释放未使用的块。可使用挂载参数 discard=async 启用异步丢弃(asynchronous discard)支持,linux 6.2 版本已经默认启用该功能。已释放的空间范围不会被马上丢弃,它们会被集中起来并在稍后由一个单独的工作线程进行 TRIM,这将能改善提交延迟。

异步丢弃可以安全地同定期TRIM使用[7]

有关启用和使用 TRIM 的更多信息,请参阅固态硬盘#TRIM

使用[编辑 | 编辑源代码]

交换文件[编辑 | 编辑源代码]

注意: 跨设备文件系统上的交换文件不受支持,参见btrfs(5) § SWAPFILE SUPPORT以了解所有限制。

创建交换文件的正确方法是首先创建一个非快照子卷以存储交换文件,

# btrfs subvolume create /swap 
提示:考虑直接在顶层子卷上创建子卷,例如@swap。然后将子卷挂载/swap(或其他可访问路径)。

创建交换文件:

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

如果未指定 --size 选项,交换文件默认大小为2 GiB。

启用交换文件:

# swapon /swap/swapfile

最后编辑fstab,添加交换文件的配置:

/etc/fstab
/swap/swapfile none swap defaults 0 0

更多信息参见Fstab#用法

注意: 也可以手动创建交换文件,通过chattr设置整个子卷的No_COW属性,然后按照Swap#建立交换文件的内容创建交换文件。参见btrfs(5) § SWAPFILE SUPPORT

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

显示已使用的/空闲空间[编辑 | 编辑源代码]

df(1) 这样的用户空间工具可能不会准确的计算剩余空间 (因为并没有分别计算文件和元数据的使用情况) 。推荐使用 btrfs filesystem usage 来查看使用情况。比如说:

# btrfs filesystem usage /
注意: btrfs filesystem usageRAID5/RAID6 设备上可能无法正常工作。

或者使用btrfs filesystem df在非root权限下快速检查已分配空间的使用情况:

$ btrfs filesystem df /

请参阅 [8] 以获取更多信息。

du(1)ncdu(1) 这类分析文件系统子集空间使用的工具同样受到影响,因为其没有考虑reflink,快照和压缩。可以考虑使用btduAURcompsize这类可识别btrfs特性的工具。

碎片整理[编辑 | 编辑源代码]

Btrfs 支持通过配置挂载参数 autodefrag 来实现在线的碎片整理,参见 btrfs(5) § MOUNT OPTIONS 。要手动整理你的根目录的话,可以使用:

# btrfs filesystem defragment -r /

使用不带 -r 开关的上述命令将导致仅整理该目录的子卷所拥有的元数据。这允许通过简单地指定路径进行单个文件碎片整理。

警告: 对具有 CoW 副本(快照副本或使用cp或 bcp 创建的文件)进行碎片整理以及使用带压缩算法的 -c 开关进行碎片整理可能会导致生成两个不相关的文件从而大幅增加磁盘使用量。

RAID[编辑 | 编辑源代码]

Btrfs 提供对 RAID 一类的 #多设备文件系统的原生支持。自修复冗余阵列和在线数据在线平衡是使btrfs RAID 与mdadm区分开来的重要特性。参阅 the Btrfs wiki page 获得更多信息。Btrfs 管理员手册提供了一些额外技术背景信息。

警告: 奇偶校验 RAID(RAID 5/6)代码中存在多个严重的数据丢失错误。 检查 Btrfs 文档的 RAID5/6 页面 (英文) 和 BUG 汇报 (linux-btrfs 邮件列表 (英文)) 以获取更多信息。2020 年 6 月, 有人提出了一个 通俗易懂的现存问题列表 (英文) 和一个 有用的恢复指南 (英文)

检修 (Scrub)[编辑 | 编辑源代码]

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

Btrfs Wiki 术语表中写到,Scrub 是一种"在线文件系统检查工具"。它能读取文件系统中的文件和元数据,并使用校验值和 RAID 存储上的镜像区分并修复损坏的数据。

注意: 运行 scrub 会阻止系统待机, 详见 这个讨论
手动启动[编辑 | 编辑源代码]

启动一个(后台运行的)包含 / 目录的文件系统在线检查任务:

# btrfs scrub start /

检查该任务的运行状态:

# btrfs scrub status /
通过服务或者定时器启动[编辑 | 编辑源代码]

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

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

数据平衡 (Balance)[编辑 | 编辑源代码]

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

在单设备文件系统上,数据平衡对于(临时)减少分配但未使用(元)数据块的数量也是有用的。有时候这对于解决 "filesystem full" 故障来说也是必须的。

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

快照[编辑 | 编辑源代码]

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

要创建一个快照:

# 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合并到同一个区(extend)内。

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

调整大小[编辑 | 编辑源代码]

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

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

  • 新的大小必须大于已有数据的大小,否则会导致数据损失。
  • 新的大小必须等于或小于当前设备的可用空间。
注意: 如果你还计划减小文件系统所在的逻辑卷大小,请先减小文件系统大小后再尝试减小逻辑卷的大小。

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

# btrfs filesystem resize max /

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

# btrfs filesystem resize size /

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

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

已知问题[编辑 | 编辑源代码]

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

加密[编辑 | 编辑源代码]

Btrfs 目前还没有内建的加密支持,但未来可能加入此功能。可以在运行mkfs.btrfs前加密分区,参阅 Dm-crypt/加密整个系统。另一个选择是栈式文件系统加密

检查 btrfs 文件系统问题[编辑 | 编辑源代码]

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

提示和技巧[编辑 | 编辑源代码]

无分区 Btrfs 磁盘[编辑 | 编辑源代码]

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

Btrfs 能占用整个存储设备,使用子卷模拟分区表来替代 MBRGPT 分区表。虽然无分区磁盘不需要使用其它方法创建分区,然后在一个分区上创建 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 环境中重建初始化内存盘 (mkinitcpio -p linux)以确保系统正确启动。

注意: 如果转换过程中有任何异样,不管是无法挂载新转换的 Btrfs 文件系统或是无法往其中写入数据,只要备份子卷 /ext2_saved 还在,就可以进行回滚。请使用 btrfs-convert -r /dev/partition 命令进行回滚,这将会丢弃任何对新转换 Btrfs 文件系统的更改。

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

# btrfs subvolume delete /ext2_saved

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

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

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

损坏恢复[编辑 | 编辑源代码]

警告: 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-btrfsgrub-btrfs-gitAUR 的帮助下,在重新生成配置文件时使用 Btrfs 快照自动填充启动菜单。

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

搭配 systemd-nspawn 使用 Btrfs 子卷[编辑 | 编辑源代码]

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

减少访问时间元数据的更新[编辑 | 编辑源代码]

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

增量备份到外置设备[编辑 | 编辑源代码]

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

  • btrbk — Btrfs子卷的快照和远程备份工具
https://github.com/digint/btrbk || btrbk
  • snap-sync — 使用Snapper快照并备份到外置设备或远程机器
https://github.com/wesbarnett/snap-sync || snap-sync
  • snapsyncSnapper的同步工具
https://github.com/doudou/snapsync || ruby-snapsyncAUR

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

  • snapborg — 一个类似borgmatic的工具,将snapper快照与borg整合起来
https://github.com/enzingerm/snapborg || snapborgAUR

自动快照[编辑 | 编辑源代码]

要管理并自动创建快照,你可以使用像SnapperTimeshiftYabsnap这样的快照管理器。

疑难解答[编辑 | 编辑源代码]

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

GRUB[编辑 | 编辑源代码]

分区偏移[编辑 | 编辑源代码]

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

GRUB 可以引导启动 Btrfs 分区,但是因为模块可能会比其它文件系统大,grub-install 生成的 core.img 文件超过了 MBR 与第一个分区之间的空间大小 (63 扇区/31.5KiB)。最新版的 fdiskgdisk 等磁盘工具会通过第一个分区前空出 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 /storage.
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 提供系统以更长的超时时间来轻松解决。例如:

/dev/sda                /storage    btrfs       rw,relatime,x-systemd.mount-timeout=5min  0 0

出现 BTRFS: open_ctree failed 错误[编辑 | 编辑源代码]

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

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


截至 2014 年 11 月,一个似乎存在于 systemdmkinitcpio 中的 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 不应出现在 HOOKSMODULES 列表中。

请查阅原论坛讨论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来替代。

另请参阅[编辑 | 编辑源代码]