这篇文章将探索 Btrfs 中的透明文件系统压缩，以及它如何帮助节省存储空间。这篇文章是《Btrfs 详解》系列文章中的一篇。从 Fedora Linux 33 开始，Btrfs 就是 Fedora Workstation 和 Fedora Silverblue 的默认文件系统。如果你错过了，这里是本系列的上一篇文章：Btrfs 详解：快照。简介很多人都经历过存储空间用完的情况。也许你想从互联网下载一个大文件，或者你需要快速从你的手机中复制些照片，然后操作突然失败。虽然存储空间成本正在稳步降低，但越来越多的设备要么制造时就是固定数量的存储容量，要么最终用户难以扩展其存储容量。但当你的存储空间不足时你可以做什么呢？也许你会求助于云存储，或者你可以随身携带一些外部存储设备。在这篇文章里我会研究该问题的另一种解决方案：透明的文件系统压缩，这是 Btrfs 的一个特性。理想情况下，这将解决你的存储问题，同时几乎不需要对你的系统进行修改！让我们来看看是如何做到的。透明压缩的解释首先，让我们来探寻 透明 压缩是什么意思。你可以通过像 gzip、xz 或者 bzip2 这些压缩算法去压缩文件。这通常是显式操作：你利用一个压缩工具并且让它操作你的文件。虽然根据文件的内容，节约了空间，这有一个主要的缺点：当你想读取文件或者修改的时候，你得先解压缩。这不仅是一个乏味的过程，而且也暂时打破了你之前节省的空间。再者，你最终解压了你不想访问的那部分文件内容。明显有比这更好的方法！相反，透明压缩发生在文件系统级别。在这里，压缩的文件对用户看起来像常规的未压缩文件一样。但是，它们是被压缩后存储在硬盘上的。这之所以可行，是因为操作系统仅仅选择性地访问那部分文件，并且确保在向磁盘写入更新时再次压缩它们。这里的压缩是透明的在于它不被用户感知，除了在文件访问时可能的 CPU 负载小量增加。因此，你可以应用在已有的系统而不是进行硬件修改或者求助于云存储。压缩算法对比Btrfs 提供了多个压缩算法的选择。出于技术原因它不能选用任意的压缩算法。它现在支持：zstdlzozlib好消息是，由于透明压缩的工作原理，你不需要安装这些程序供 Btrfs 使用。在下面的文章里，你会看到如何去运行一个简单的性能测试来对比压缩算法。但是，为了运行性能测试，你必须安装必要的可执行文件。事后不需要留着它们，所以你将使用 Podman 容器来确保不会在系统中留下任何痕迹。注意 ：因为 Btrfs 使用的压缩依赖于内核对这些压缩算法的（重新）实现，用户空间版本的算法得出的结果应该认为是粗略估计。因为一次次敲重复的命令是枯燥的工作，我已经在 Gitlab 上准备了一个可以运行的 Bash 脚本 （https://gitlab.com/hartang/btrfs-compression-test）。这会用上面提到的每个算法在不同的压缩级别运行一次简单的压缩和解压缩。首先，下载脚本：$ curl -LO https://gitlab.com/hartang/btrfs-compression-test/-/raw/main/btrfs_compression_test.sh 下一步，启动一个 Fedora Linux 容器去挂载你当前的工作目录，以便你可以和主机交换文件同时在那里运行脚本：$ podman run --rm -it --security-opt label=disable -v "$PWD:$PWD" \ -w "$PWD" registry.fedoraproject.org/fedora:37 最后运行脚本：$ chmod +x ./btrfs_compression_test.sh $ ./btrfs_compression_test.sh 在我机器上的输出是这样：[INFO] Using file 'glibc-2.36.tar' as compression target [INFO] Target file 'glibc-2.36.tar' not found, downloading now... ################################################################### 100.0% [ OK ] Download successful! [INFO] Copying 'glibc-2.36.tar' to '/tmp/tmp.vNBWYg1Vol/' for benchmark... [INFO] Installing required utilities [INFO] Testing compression for 'zlib' Level | Time (compress) | Compression Ratio | Time (decompress) -------+-----------------+-------------------+------------------- 1 | 0.322 s | 18.324 % | 0.659 s 2 | 0.342 s | 17.738 % | 0.635 s 3 | 0.473 s | 17.181 % | 0.647 s 4 | 0.505 s | 16.101 % | 0.607 s 5 | 0.640 s | 15.270 % | 0.590 s 6 | 0.958 s | 14.858 % | 0.577 s 7 | 1.198 s | 14.716 % | 0.561 s 8 | 2.577 s | 14.619 % | 0.571 s 9 | 3.114 s | 14.605 % | 0.570 s [INFO] Testing compression for 'zstd' Level | Time (compress) | Compression Ratio | Time (decompress) -------+-----------------+-------------------+------------------- 1 | 0.492 s | 14.831 % | 0.313 s 2 | 0.607 s | 14.008 % | 0.341 s 3 | 0.709 s | 13.195 % | 0.318 s 4 | 0.683 s | 13.108 % | 0.306 s 5 | 1.300 s | 11.825 % | 0.292 s 6 | 1.824 s | 11.298 % | 0.286 s 7 | 2.215 s | 11.052 % | 0.284 s 8 | 2.834 s | 10.619 % | 0.294 s 9 | 3.079 s | 10.408 % | 0.272 s 10 | 4.355 s | 10.254 % | 0.282 s 11 | 6.161 s | 10.167 % | 0.283 s 12 | 6.670 s | 10.165 % | 0.304 s 13 | 12.471 s | 10.183 % | 0.279 s 14 | 15.619 s | 10.075 % | 0.267 s 15 | 21.387 s | 9.989 % | 0.270 s [INFO] Testing compression for 'lzo' Level | Time (compress) | Compression Ratio | Time (decompress) -------+-----------------+-------------------+------------------- 1 | 0.447 s | 25.677 % | 0.438 s 2 | 0.448 s | 25.582 % | 0.438 s 3 | 0.444 s | 25.582 % | 0.441 s 4 | 0.444 s | 25.582 % | 0.444 s 5 | 0.445 s | 25.582 % | 0.453 s 6 | 0.438 s | 25.582 % | 0.444 s 7 | 8.990 s | 18.666 % | 0.410 s 8 | 34.233 s | 18.463 % | 0.405 s 9 | 41.328 s | 18.450 % | 0.426 s [INFO] Cleaning up... [ OK ] Benchmark complete! 重要的是在根据脚本得出的数据做决定之前注意这些事情：不是所有的文件压缩效果都一样好。像图片或电影这种已经压缩过的现代多媒体格式不会压缩得更小。脚本中压缩和解压缩各进行一次。重复运行会产生稍微不同的输出。因此，时间应该被理解为是估计，而不是准确的测量。鉴于输出的数据，我决定在我的系统上使用压缩级别 3 的 zstd 压缩算法。依据你的需求，你可能想使用更高的压缩级别（比如，如果你存储设备相当的慢）。要估算可达到的读/写速度，可以将源存档大小（约 260MB）除以（解）压缩时间。压缩测试默认是对 GNU libc 2.36 源码进行的。如果你想看看对指定文件的效果，你可以通过第一个参数传递文件路径给脚本。记住文件一定要可以在容器内访问才行。如果你想要测试其他东西或者执行更加详细的测试，可以阅读脚本的源码，根据需要修改它。配置 Btrfs 压缩Btrfs 里的透明文件系统压缩可以通过几种方式配置：作为挂载文件系统的挂载选项（可用于相同 Btrfs 文件系统的所有子卷）通过 Btrfs 文件属性在 btrfs filesystem defrag 时（不是永久的，不在这里介绍）通过 chattr 文件属性接口（不在这里介绍）我只会介绍其中前两个。在挂载时开启压缩有一个 Btrfs 挂载选项可以开启文件压缩：$ sudo mount -o compress=<ALGORITHM>:<LEVEL> ... 例如，去挂载一个文件系统，并使用等级 3 的 ztsd 算法去压缩，你可以写成：$ sudo mount -o compress=zstd:3 ... 设置压缩等级是可选的。重要的是注意到 compress 挂载选项应用到整个 Btrfs 文件系统和它所有的子卷。此外，这是目前唯一支持的指定压缩等级的方式。为了对文件系统的根应用压缩，必须在 /etc/fstab 上指定。例如，Fedora Linux 安装器，默认启用级别 1 的 zstd 压缩，在 /etc/fstab 里是这样：$ cat /etc/fstab [ ... ] UUID=47b03671-39f1-43a7-b0a7-db733bfb47ff / btrfs subvol=root,compress=zstd:1,[ ... ] 0 0 启用单个文件压缩另外一种方式指定压缩的方法是通过 Btrfs 文件系统属性。使用下面的命令去查看文件、目录或子卷的压缩设置：$ btrfs property get <PATH> compression 类似的，你可以像这样配置压缩：$ sudo btrfs property set <PATH> compression <VALUE> 例如，对在 /etc 下所有文件启用 zlib 压缩：$ sudo btrfs property set /etc compression zlib 你可以通过 man btrfs-property 得到支持值的列表。记住这个接口不允许指定压缩级别。除此之外，如果设置了一个压缩属性，它会覆盖挂载时的其他压缩配置。压缩已有文件在这时，如果你对现有文件系统采用压缩，然后通过 df 或类似命令检查空间利用率，你会发现什么都没变。这是因为 Btrfs 自身不会 “重新压缩” 所有已有的文件。压缩只会发生在往磁盘写新数据的时候。有一些方式去执行显式的重压缩：等待，什么都不做：只要文件被修改并被写回磁盘，Btrfs 根据配置压缩新写入的文件内容。如果我们等待足够长，越来越多的文件被重写，在某个时间点就会被压缩。移动文件到另一个文件系统然后移动回来：取决于你想压缩哪些文件，这可能是相当乏味的选项。执行一次 Btrfs 碎片整理。最后一个选项可能是最方便的，但是它会对已经包含快照的 Btrfs 文件系统提出警告：它会破坏快照间的共享范围。换句话来说，两个快照间所有的共享内容，或者一个快照和它的父子卷，在碎片整理操作后将保存多份。因此，如果你在你的文件系统里已经有很多快照，你不应该对整个文件系统运行碎片整理。这也没有必要，因为如果你想的话，Btrfs 可以对特定的目录或者单个文件进行碎片整理。你可以使用以下命令去执行一次碎片整理：$ sudo btrfs filesystem defragment -r /path/to/defragment 例如，你想像这样去整理你主目录的碎片：$ sudo btrfs filesystem defragment -r "$HOME" 如果有疑问，最好从碎片整理单个大文件开始，并在监视文件系统上的可用空间的同时继续处理越来越大的目录。测量文件系统压缩有时，你可能会想，文件系统压缩为你节省了多少空间。但如何判断呢？首先，要知道一个 Btrfs 文件系统是否在挂载时启用了压缩，你可以使用以下命令：$ findmnt -vno OPTIONS /path/to/mountpoint | grep compress 如果你得到了结果，那么给定挂载点的文件系统就使用了压缩！下一步，compsize 命令会告诉你你的文件需要多少空间：$ sudo compsize -x /path/to/examine 在我的主目录，结果是这样：$ sudo compsize -x "$HOME" Processed 942853 files, 550658 regular extents (799985 refs), 462779 inline. Type Perc Disk Usage Uncompressed Referenced TOTAL 81% 74G 91G 111G none 100% 67G 67G 77G zstd 28% 6.6G 23G 33G 每一行告诉你应用到文件的压缩 “类型” 。* TOTAL 是下面所有行的总计。另一方面，这些列告诉你我们的文件需要多少空间：Disk Usage 是实际分配在硬盘上的空间，Uncompressed 是如果没有压缩，文件所需要的空间，Referenced 是所有未压缩文件加起来的总大小。Referenced 可以与数据 Uncompressed 不同，比如一个文件之前被重复了，或者有快照共享内容。在上面的例子，你可以看到在我的硬盘上总计 91 GB 的未压缩文件仅占据了 74 GB 的存储。取决于在目录里存储的文件类型和应用的压缩等级，这些数字可以有很大差异。文件压缩的其它注意事项Btrfs 使用启发式算法去探测压缩文件。这是因为压缩文件通常效果不好，所以没有必要浪费 CPU 周期去尝试进一步的压缩。为了这个目的，Btrfs 在写入压缩数据到磁盘之前测量压缩率。如果文件的第一部分压缩效果不好，文件被标记为不可压缩并且不会有后续的压缩。如果出于某些原因，你想 Btrfs 压缩所有写入的数据，你可以通过 compress-force 选项挂载一个 Btrfs 文件系统，像这样：$ sudo mount -o compress-force=zstd:3 ... 当像这样配置，Btrfs 会用等级 3 的 zstd 算法压缩所有写入磁盘的数据。一个重要的注意事项是挂载一个有很多数据并开启压缩的 Btrfs 文件系统会比没开启压缩耗时更长。这是有技术上的原因的，而且这是一个不会影响文件系统操作的正常行为。总结本文详细介绍了 Btrfs 中的透明文件系统压缩。这是一种内置的、相对廉价的方法，可以在不需要修改的情况下从现有硬件中获得一些额外的存储空间。本系列文章的下一篇将讨论：Qgroups - 限制文件系统大小RAID - 替换 mdadm 配置（LCTT 译注：后继文章尚未发布，一旦发布我们会尽快翻译。）如果你想了解与 Btrfs 相关的其他主题，请查看 Btrfs 维基 [1] 和文档 [2] 。如果你还没有阅读本系列的前三篇文章，请不要忘记去看看！如果你觉得本文缺少某些内容，请在下面的评论中让我知道。我们下篇文章见！参考资料https://btrfs.wiki.kernel.org/index.php/Main_Page ↩︎https://btrfs.readthedocs.io/en/latest/Introduction.html ↩︎（题图：MJ/1a45064c-8da5-4b60-87f2-9886d6a3299e）via: https://fedoramagazine.org/working-with-btrfs-compression/作者：Andreas Hartmann 选题：lujun9972 译者：A2ureStone 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
这篇文章会探讨什么是 Btrfs 快照，它们如何工作的，你在日常生活中进行快照的好处。这篇文章是《Btrfs 详解》系列文章中的一篇。从 Fedora Linux 33 开始，Btrfs 就是 Fedora Workstation 和 Fedora Silverblue 的默认文件系统。如果你错过了，这里是本系列的上一篇文章：Btrfs 详解：子卷简介想象一下，你长时间处理一个文件，反复添加和撤销修改。然后，在某个时刻你意识到：两小时前你撤销的部分修改，现在会非常有用。而昨天在你销毁那个设计之前，你也已经修改了这个特殊的部分。当然，由于你会定期保存文件，所以旧的改动会丢失。很多人可能都遇到过这样的情况。如果能恢复旧版本的文件，而无需定期手动复制，岂不美哉？这是一个 Btrfs 快照可以帮助你的特别场景。当你使用正确的话，快照同时也为你的电脑提供了很好的备份方案。下面你会找到一些关于快照的例子。如果你想跟着操作，你必须拥有访问某些 Btrfs 文件系统的权限和 root 权限。你可以通过下面命令来验证一个目录的文件系统。$ findmnt -no FSTYPE /home btrfs 这个命令会输出你 /home/ 目录的文件系统名称。如果它是 btrfs，那就可以了。让我们创建一个新的目录去做实验：$ mkdir ~/btrfs-snapshot-test $ cd ~/btrfs-snapshot-test 在下面的文本中，你会看到很多像上面显示的那样的命令输出框。请在阅读/比较命令输出时请记住，框中的内容在行末会被换行。这使得识别跨多行的长行变得困难，降低了可读性。如果有疑问，试着调整浏览器窗口的大小，看看文本的变化！Btrfs 快照让我们从一个基本的问题开始：什么是 Btrfs 快照？如果你在文档 [1] 和维基 [2] 中查找，你不会立刻找到这个问题的答案。事实上，从“功能”一节里是找不到的。如果你搜索一下，你会发现快照和 Btrfs 子卷一起被大量地提及 [3] 。所以现在做什么呢？还记得快照在系列前面的文章里两次被提到吗？是这样说的：CoW 的优势在哪里？简单的说：文件被修改和编辑的历史被保存了下来。Btrfs 保存文件旧版本的引用（inode）可以轻易地被访问。这个引用就是快照：文件系统在某个时间点的状态镜像。这将是这系列文章里的单独的一篇，所以暂时留到后面介绍。—— Btrfs 详解：基础概念以及：另外一个分离 / 和 /home 的优势是我们可以分别进行 快照 。子卷是快照的边界，对一个子卷的快照永远不会包含该子卷下面的其他子卷的内容。快照的更多细节会在后续的文章中介绍。—— Btrfs 详解：子卷看起来快照是和 Btrfs 子卷相关的。你可能之前在其他地方听到过快照，比如说 LVM（逻辑卷管理器）。虽然技术角度上它们都是为了同一个目的，但它们在实现方面有所不同。每个 Btrfs 快照是一个子卷。但是，不是每个子卷都是一份快照。区别在于子卷里面包含的内容。一个快照是子卷加上一些内容：它包含对现在和过去版本的文件的引用（inode）。让我们看看快照是从哪来的！创建 Btrfs 快照想使用快照功能，你需要一个 Btrfs 子卷来进行快照。让我们在测试目录（~/btrfs-snapshot-test）里创建一个：$ cd ~/btrfs-snapshot-test $ sudo btrfs subvolume create demo Create subvolume './demo' $ sudo chown -R $(id -u):$(id -g) demo/ $ cd demo 因为 Btrfs 子卷默认是被 root 所有的，你必须用 chown 去修改子卷里的文件的所有权到普通用户上。现在我们在里面新加一些文件：$ touch foo bar baz $ echo "Lorem ipsum dolor sit amet, " > foo 你的目录现在看起来像这样：$ ls -l total 4 -rw-r--r--. 1 hartan hartan 0 Dec 20 08:11 bar -rw-r--r--. 1 hartan hartan 0 Dec 20 08:11 baz -rw-r--r--. 1 hartan hartan 29 Dec 20 08:11 foo 让我们从这里创建第一次快照：$ cd .. $ sudo btrfs subvolume snapshot demo demo-1 Create a snapshot of 'demo' in './demo-1' 这就好了。让我们看看发生了什么：$ ls -l total 0 drwxr-xr-x. 1 hartan hartan 18 Dec 20 08:11 demo drwxr-xr-x. 1 hartan hartan 18 Dec 20 08:11 demo-1 $ tree . ├── demo │ ├── bar │ ├── baz │ └── foo └── demo-1 ├── bar ├── baz └── foo 2 directories, 6 files 这看起来是一份拷贝！为了验证，我们从快照里读取 foo 的内容：$ cat demo/foo Lorem ipsum dolor sit amet, $ cat demo-1/foo Lorem ipsum dolor sit amet, 当我们修改原始文件时，真正的效果变得明显：$ echo "consectetur adipiscing elit, " >> demo/foo $ cat demo/foo Lorem ipsum dolor sit amet, consectetur adipiscing elit, $ cat demo-1/foo Lorem ipsum dolor sit amet, 这表明快照仍然持有“旧”版本的数据：foo 的内容没有改变。到目前为止，你可以通过一个简单的文件复制来实现完全相同的目标。现在你也可以继续处理旧文件了。$ echo "sed do eiusmod tempor incididunt" >> demo-1/foo $ cat demo-1/foo Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt 但是在底层，我们的快照实际上是一个新的 Btrfs 子卷。你可以通过下面的命令来验证这一点：$ sudo btrfs subvolume list -o . ID 259 gen 265 top level 256 path home/hartan/btrfs-snapshot-test/demo ID 260 gen 264 top level 256 path home/hartan/btrfs-snapshot-test/demo-1 Btrfs 子卷 vs. 文件复制这一切有什么意义呢？到目前为止快照看起来是一个更加复杂的复制文件的方式。事实上，快照不仅仅是表面上看起来那么简单。让我们来创建一个更大的文件：$ dd if=/dev/urandom of=demo/bigfile bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 1.3454 s, 399 MB/s 现在有一个512 MB 大小的新文件 demo/bigfile 。让我们创建另一个快照，这样在你修改数据的时候就不会丢失：$ sudo btrfs subvolume snapshot demo demo-2 Create a snapshot of 'demo' in './demo-2' 现在我们通过追加少量字符串到文件来模拟变化：$ echo "small changes" >> demo/bigfile 这是生效后的文件结构：$ tree . ├── demo │ ├── bar │ ├── baz │ ├── bigfile │ └── foo ├── demo-1 │ ├── bar │ ├── baz │ └── foo └── demo-2 ├── bar ├── baz ├── bigfile └── foo 3 directories, 11 files 但是真正的神奇的发生在其他地方。你已经复制了 demo/bigfile ，你现在拥有了两个大约 512 MiB 的文件。但是，因为它们是不同的拷贝，它们应该会占据共 1 GiB 的空间。记住两个文件的差异不超过 10 字节 —— 和原文件大小相比这几乎没什么差别。Btrfs 快照工作原理与文件复制不同：而是它们保持对当前和过去的 inode 的引用。当你在文件追加更新时，在底层 Btrfs 分配更多的空间去存储更新，同时在原来的 inode 增加对新数据的引用。之前的内容保持不变。为了便于理解，你可以认为这是仅仅“存储”原文件和修改版本的差异。让我们看看这个效果：$ sudo compsize . Processed 11 files, 5 regular extents (9 refs), 3 inline. Type Perc Disk Usage Uncompressed Referenced TOTAL 100% 512M 512M 1.0G none 100% 512M 512M 1.0G 这个有趣的数字出现在 TOTAL 一行：Referenced 是当前目录下所有文件大小的总和Disk Usage 是用于在磁盘上存储文件分配空间的大小你有一共 1 GiB 的文件，但存储它们仅仅占据了 512 MiB。Btrfs 快照和备份目前为止，在这篇文章中，你已经看到如何创建 Btrfs 快照和它们的特别之处。有人可能会想：如果我在我的 PC 本地进行一系列的快照，我就有一个可靠的备份策略。 其实不是这样的 。如果 Btrfs 子卷共享的底层数据被偶然破坏了（被 Btrfs 之外的东西影响，比如宇宙射线），所有指向这些数据的子卷都会存在相同的错误。为了让快照成为真正的备份，你应该将它们存储到一个不同的 Btrfs 系统上，例如在一个外部驱动器上。为了本文的目的，让我们在一个文件里创建一个新的 Btrfs 系统，并挂载它来模拟一个外部驱动。如果你有一个格式为 Btrfs 的外部驱动器，请随意替换以下命令中提到的所有路径来试试！让我们创建一个新的 Btrfs 文件系统：注意：下面的命令会在你的文件系统上创建一个 8 GB 大小的新文件。如果你想跟着下面的步骤，请确保你的磁盘空间至少有 8 GB 剩余。请不要分配小于 8 GB 到这个文件，否则 Btrfs 可能在挂载时会遇到问题。$ truncate -s 8G btrfs_filesystem.img $ sudo mkfs.btrfs -L "backup-drive" btrfs_filesystem.img btrfs-progs v5.18 See http://btrfs.wiki.kernel.org for more information. [ ... ] Devices: ID SIZE PATH 1 8.00GiB btrfs_filesystem.img 这些命令创建了名为 btrfs_filesystem.img 的 8 GB 新文件，同时在上面格式化了一个 Btrfs 文件系统。现在你可以像外部驱动器一样挂载它：$ mkdir backup-drive $ sudo mount btrfs_filesystem.img backup-drive $ sudo chown -R $(id -u):$(id -g) backup-drive $ ls -lh total 4.7M drwxr-xr-x. 1 hartan hartan 0 Dec 20 08:35 backup-drive -rw-r--r--. 1 hartan hartan 8.0G Dec 20 08:37 btrfs_filesystem.img drwxr-xr-x. 1 hartan hartan 32 Dec 20 08:14 demo drwxr-xr-x. 1 hartan hartan 18 Dec 20 08:11 demo-1 drwxr-xr-x. 1 hartan hartan 32 Dec 20 08:14 demo-2 妙，现在挂载在 backup-drive 下面有一个独立的 Btrfs 文件系统！让我们尝试进行快照并且把快照放进去：$ sudo btrfs subvolume snapshot demo backup-drive/demo-3 Create a snapshot of 'demo' in 'backup-drive/demo-3' ERROR: cannot snapshot 'demo': Invalid cross-device link 发生了什么？噢，你尝试对 demo 进行一次快照并把它存在不同的 Btrfs 文件系统里（从 Btrfs 视角来看是一个不同的设备）。还记得一个 Btrfs 子卷仅持有对文件和内容的引用（inode）？这正是问题所在：文件和内容存在于我们的 home 文件系统，但不在新创建的 backup-drive 。你得找到一种方式去传输子卷和其内容到新的文件系统里。在不同的 Btrfs 文件系统存储快照针对这个目的 Btrfs 工具有两个特殊的命令。让我们首先来看看它们是如何工作的：$ sudo btrfs send demo | sudo btrfs receive backup-drive/ ERROR: subvolume /home/hartan/btrfs-snapshot-test/demo is not read-only ERROR: empty stream is not considered valid 另一个错误！这时它告诉你我们想要传输的子卷不是只读的。这是对的：你可以写入新内容到所有目前为止创建的快照/子卷。你可以像这样创建一个只读的快照：$ sudo btrfs subvolume snapshot -r demo demo-3-ro Create a readonly snapshot of 'demo' in './demo-3-ro' 不像之前那样，这里 -r 选项被加到了 snapshot 子命令里。这创建一个只读的快照，这很容易去验证：$ touch demo-3-ro/another-file touch: cannot touch 'demo-3-ro/another-file': Read-only file system 现在你可以重新尝试传输子卷：$ sudo btrfs send demo-3-ro | sudo btrfs receive backup-drive/ At subvol demo-3-ro At subvol demo-3-ro $ tree ├── backup-drive │ └── demo-3-ro │ ├── bar │ ├── baz │ ├── bigfile │ └── foo ├── btrfs_filesystem.img ├── demo [ ... ] └── demo-3-ro ├── bar ├── baz ├── bigfile └── foo 6 directories, 20 files 成功了！你成功传输原来子卷 demo 的一个只读快照到一个外部的 Btrfs 文件系统。在非 Btrfs 文件系统存储快照上面你已经看到你如何能存储 Btrfs 子卷/快照到其他的 Btrfs 文件系统。但如果你没有其他的 Btrfs 文件系统并且不能新创建一个，比如说外部驱动器需要一个和 Windows 或 MacOS 兼容的文件系统，你可以做什么呢？在这种情况下你可以存储子卷在文件里：$ sudo btrfs send -f demo-3-ro-subvolume.btrfs demo-3-ro At subvol demo-3-ro $ ls -lh demo-3-ro-subvolume.btrfs -rw-------. 1 root root 513M Dec 21 10:39 demo-3-ro-subvolume.btrfs 文件 demo-3-ro-subvolume.btrfs 现在包含了随后重建 demo-3-ro 子卷需要的所有东西。增量地发送快照如果你对不同的子卷重复执行这个操作，你会发现在某些时间点不同的子卷不再共享它们的文件内容。这是因为像上面一样发送一个子卷，去重建这个单独的子卷的所有数据将被传送到目标位置。但是，你可以引导 Btrfs 只向目标位置发送不同子卷的差异！所谓的增量发送将保证共享的引用在子卷中仍然共享。为了展示这一点，新增一些变动到我们原来的子卷：$ echo "a few more changes" >> demo/bigfile 然后创建另一个只读子卷：$ sudo btrfs subvolume snapshot -r demo demo-4-ro Create a readonly snapshot of 'demo' in './demo-4-ro' 然后现在发送它：$ sudo btrfs send -p demo-3-ro demo-4-ro | sudo btrfs receive backup-drive At subvol demo-4-ro At snapshot demo-4-ro 在上面的命令，-p 选项指定了一个父子卷用来计算差异。重要的是记住原 Btrfs 文件系统和目标 Btrfs 文件系统都必须包含相同的、未被修改过的父子卷！确保新的子卷真的在那里：$ ls backup-drive/ demo-3-ro demo-4-ro $ ls -lR backup-drive/demo-4-ro/ backup-drive/demo-4-ro/: total 524296 -rw-r--r--. 1 hartan hartan 0 Dec 20 08:11 bar -rw-r--r--. 1 hartan hartan 0 Dec 20 08:11 baz -rw-r--r--. 1 hartan hartan 536870945 Dec 21 10:49 bigfile -rw-r--r--. 1 hartan hartan 59 Dec 20 08:13 foo 但你怎样知道增量发送只传输了子卷间的差异呢？让我们传输数据流到一个文件里然后看看它有多大：$ sudo btrfs send -f demo-4-ro-diff.btrfs -p demo-3-ro demo-4-ro At subvol demo-4-ro $ ls -l demo-4-ro-diff.btrfs -rw-------. 1 root root 315 Dec 21 10:55 demo-4-ro-diff.btrfs 根据 ls ，这个文件仅仅只有 315 字节大小！这意味着增量传输只传输子卷间的差异，和额外的 Btrfs 相关的元数据。从快照中恢复子卷在继续之前，让我们清理掉这时候不再需要的东西：$ sudo rm -rf demo-4-ro-diff.btrfs demo-3-ro-subvolume.btrfs $ sudo btrfs subvolume delete demo-1 demo-2 demo-3-ro demo-4-ro $ ls -l total 531516 drwxr-xr-x. 1 hartan hartan 36 Dec 21 10:50 backup-drive -rw-r--r--. 1 hartan hartan 8589934592 Dec 21 10:51 btrfs_filesystem.img drwxr-xr-x. 1 hartan hartan 32 Dec 20 08:14 demo 到目前为止你已经成功创建了可读/写和只读的 Btrfs 子卷快照，并把它们发送到外部。但是，为了把这作为备份策略，还要有一种方式去发送子卷回原来的文件系统和让它们再次变为可写。出于这个目的，我们移动 demo 子卷到其他地方并且尝试从最近的快照中重建它。第一步：重命名为 broken 子卷。一旦恢复成功它会被删除：$ mv demo demo-broken 第二步: 传回最近的快照到这个文件系统：$ sudo btrfs send backup-drive/demo-4-ro | sudo btrfs receive . At subvol backup-drive/demo-4-ro At subvol demo-4-ro [hartan@fedora btrfs-snapshot-test]$ ls backup-drive btrfs_filesystem.img demo-4-ro demo-broken 第三步: 从快照创建一个可读写的子卷：$ sudo btrfs subvolume snapshot demo-4-ro demo Create a snapshot of 'demo-4-ro' in './demo' $ ls backup-drive btrfs_filesystem.img demo demo-4-ro demo-broken 上一步非常重要：你不能重命名 demo-4-ro 为 demo ，因为这仍然是一个只读子卷！最后你可以检查你所有你想要的东西是不是在那里：$ tree demo demo ├── bar ├── baz ├── bigfile └── foo 0 directories, 4 files $ tail -c -19 demo/bigfile a few more changes 最后的命令告诉你 bigfile 的最后 19 个字符实际上是上次变更执行的结果。这个时候，你可能想从 demo-broken 复制最近的更新到新的 demo 子卷。因为你没有执行任何更新，你可以过时的子卷：$ sudo btrfs subvolume delete demo-4-ro demo-broken Delete subvolume (no-commit): '/home/hartan/btrfs-snapshot-test/demo-4-ro' Delete subvolume (no-commit): '/home/hartan/btrfs-snapshot-test/demo-broken' 就是这样！你成功从一个之前存在不同 Btrfs 文件系统（外部介质）的快照中恢复 demo 子卷。子卷作为快照的边界在本系列的第二篇文章中我提到子卷作为快照的边界，但这到底是什么意思呢？简单来说，子卷的一份快照仅包含这个子卷的内容，而不是下面嵌套的子卷。让我们来看看这个：$ sudo btrfs subvolume create demo/nested Create subvolume 'demo/nested' $ sudo chown -R $(id -u):$(id -g) demo/nested $ touch demo/nested/another_file 让我们像以前一样进行一次快照：$ sudo btrfs subvolume snapshot demo demo-nested Create a snapshot of 'demo' in './demo-nested' 然后查看里面的内容：$ tree demo-nested demo-nested ├── bar ├── baz ├── bigfile ├── foo └── nested 1 directory, 4 files $ tree demo demo ├── bar ├── baz ├── bigfile ├── foo └── nested └── another_file 1 directory, 5 files 注意到 another_file 不见了，仅仅是目录 nested 还在。这是因为 nested 是一个子卷：demo 的快照包含嵌套子卷的目录（挂载点），但里面的内容是缺失的。目前没有方法递归地执行快照去包含嵌套子卷。但是，我们可以利用这个优势去从快照中排除一些目录！这通常对那些你容易再现的数据有用，或者它们很少变化。例子有虚拟机或者容器镜像，电影，游戏文件等等。在总结之前，我们移除所有测试过程中创建的东西：$ sudo btrfs subvolume delete demo/nested demo demo-nested Delete subvolume (no-commit): '/home/hartan/btrfs-snapshot-test/demo/nested' Delete subvolume (no-commit): '/home/hartan/btrfs-snapshot-test/demo' Delete subvolume (no-commit): '/home/hartan/btrfs-snapshot-test/demo-nested' $ sudo umount backup-drive $ cd .. $ rm -rf btrfs-snapshot-test/ 基于 Btrfs 备份最后思考如果你决定使用 Btrfs 来执行数据的定期备份，那么你可能需要使用一个工具来自动完成这项任务。Btrfs 维基有一个专门针对 Btrfs [4] 的备份工具列表。在那里，你还将看到另一个手动执行 Btrfs 备份步骤的摘要。就我个人而言，我对 btrbk [5] 有很多很好的体验，我正在使用它来执行我自己的备份。除了备份之外，btrbk 还可以在你的 PC 本地保存 Btrfs 快照列表。我使用它来防止意外的数据删除。如果你想要了解更多有关使用 Btrfs 进行备份的内容，欢迎在下面评论，我会考虑写一篇专门讨论这个话题的后续文章。总结本文研究了 Btrfs 快照，它们本质上是 Btrfs 子卷。你了解了如何创建可读写和只读快照，以及这种机制如何有助于防止数据丢失。本系列的后续文章将讨论:压缩 - 透明地节省存储空间配额组 - 限制文件系统大小RAID - 替代 mdadm 配置如果你还想了解与 Btrfs 相关的其他主题，请查看 Btrfs 维基 [2:1] 和文档 [1:1] 。不要忘记查看本系列的前两篇文章！如果你认为本文缺少了一些内容，请在下面的评论中告诉我们。再会！参考资料https://btrfs.readthedocs.io/en/latest/Introduction.html ↩︎ ↩︎https://btrfs.wiki.kernel.org/index.php/Main_Page ↩︎ ↩︎https://btrfs.readthedocs.io/en/latest/Subvolumes.html ↩︎https://btrfs.wiki.kernel.org/index.php/Incremental_Backup#Available_Backup_Tools ↩︎https://github.com/digint/btrbk ↩︎（题图：MJ/ad8a61ed-ce6f-409e-b503-69104dd71149）via: https://fedoramagazine.org/working-with-btrfs-snapshots/作者：Andreas Hartmann 选题：lujun9972 译者：A2ureStone 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
在 2018 年的一篇 早前的文章 中，我们介绍了在升级 Fedora Linux 前如何利用 LVM 复制根文件系统，以便在可能出现错误的情况下能有一个回退机制。然而如今，Fedora 工作站的默认安装已经是 Btrfs 文件系统了。现在，你可以利用 Btrfs 快照来更简便地创建一个可引导的回退系统。注意，本文不涉及会如何从其它文件系统转换或迁移到 Btrfs 上。确认根文件系统是否为 Btrfs本示例采用的是 Pinebook aarch64 笔记本电脑。在开始前，务必确认你的根文件系统是否采用 Btrfs。要明确，不是所有的定制版或者镜像文件默认都使用 Btrfs。$ df -T Filesystem Type 1K-blocks Used Available Use% Mounted on devtmpfs devtmpfs 4096 0 4096 0% /dev tmpfs tmpfs 998992 0 998992 0% /dev/shm tmpfs tmpfs 399600 6360 393240 2% /run /dev/mmcblk2p3 btrfs 56929280 39796116 15058348 73% / tmpfs tmpfs 998996 24 998972 1% /tmp tmpfs tmpfs 5242880 0 5242880 0% /var/lib/mock /dev/mmcblk2p3 btrfs 56929280 39796116 15058348 73% /f34 /dev/mmcblk2p3 btrfs 56929280 39796116 15058348 73% /home /dev/mmcblk2p2 ext4 996780 551888 376080 60% /boot /dev/mmcblk2p1 vfat 194348 31648 162700 17% /boot/efi tmpfs tmpfs 199796 100 199696 1% /run/user/1000 tmpfs tmpfs 199796 84 199712 1% /run/user/0 列出当前的 Btrfs 子卷以上的示例输出显示挂载在 “根”（/）的文件系统类型是 Btrfs。你会注意到，有三个挂载点显示了相同的备份设备以及 已用 和 可用 的块数。这是因为它们是从同一 Btrfs 文件系统挂载的不同部分（子卷）。比如，/f34 子卷是我去年创建的那个可引导快照。默认的 Fedora Btrfs 安装会创建一个 Btrfs 文件系统，并在其上分别挂载两个子卷，root 和 home ，挂载路径分别为 / 和 /home。让我们一起来看看我还添加了哪些其它的子卷：$ sudo btrfs subvol list / ID 272 gen 110428 top level 5 path root ID 273 gen 110426 top level 5 path home ID 300 gen 109923 top level 5 path f34 ID 301 gen 95852 top level 5 path home.22Jul26 ID 302 gen 95854 top level 5 path f36.22Jul26 在这里，我们有一个来自最近一次系统升级的 f34 子卷，以及两个只读快照 home 和 f36。要添加和删除这些快照，最简单的方法就是挂载 Btrfs 的根目录。我会更新系统并创建当前 f36 root 子卷的新快照。如果你已经重命名了你的 root 子卷，我相信你知道该如何调整以下的示例以适应你的系统。创建 Btrfs 的回退快照$ sudo dnf update --refresh ...更新了很多部分（如果升级了内核还需要重启） $ sudo mkdir -p /mnt/root $ sudo mount /dev/mmcblk2p3 /mnt/root $ cd /mnt/root $ ls f34 f36.22Jul26 home home.22Jul26 root $ sudo btrfs subvol snapshot root f36 Create a snapshot of 'root' in './f36' 因为 Btrfs 快照是以文件系统为基础的，所以并不需要在创建快照之前进行 “同步”，正如我在 LVM 中建议的。要从新的子卷引导为回退，你需要使用你喜欢的编辑器编辑 /mnt/root/f36/etc/fstab。如果你是刚入门的话，nano 就是一款十分简单的文本编辑器，功能基本够用。以下是我 fstab 文件中的一些行：LABEL=PINE / btrfs subvol=root,compress=zstd:1 1 1 UUID=e31667fb-5b6f-48d9-aa90-f2fd6aa5f005 /boot ext4 defaults 1 2 UUID=75DB-5832 /boot/efi vfat umask=0077,shortname=winnt 0 2 LABEL=PINE /home btrfs subvol=home,compress=zstd:1 1 1 LABEL=SWAP swap swap discard=once 0 0 将 subvol=root 更改为 subvol=f36。这个改动是作用在快照中的文件，而并非你实际运行中的 fstab 文件。你可以通过 diff /etc/fstab /mnt/root/f36/etc/fstab 对比它们的区别。在我的情况下，我还使用了 sudo btrfs subvol delete f34 来删除我去年的 f34 快照。测试 Btrfs 的回退快照你现在可以进行回退的测试了。你可以使用 grubby 或在 /boot/loader/entries 中编辑一项来将 subvol=root 替换为 subvol=f36。然而，为了初学者的安全起见，我们更建议你在启动时编辑 GRUB 进行操作。你可以参考 关于 GRUB 的这篇文章 了解如何进入 GRUB 菜单。在你到达那里后，按下 e 键编辑默认的内核启动项。放心 —— 你所做的更改都只存在于内存中，如果你弄错了，重启电脑即可重新开始。就像编辑 fstab 文件一样，找到 subvol=root 并将其更改为 subvol=f36。然后，按 F10 或 Ctrl + X 来引导你修改过的项目。通过这些更改，你的系统应该能够引导进入你的新快照。你可以查看 /etc/fstab 确保你正在引导至正确的子卷，或键入 mount | grep subvol 查看此时在 / 上挂载的子卷。进行 Fedora Linux 的系统升级如果你的回退功能没问题，重启并返回你的正常根文件系统（并像上面所述，进行确认）。然后，按照 维基页面 上的指南进行标准的系统升级。提示：在运行 dnf system-upgrade reboot 之前，给 root 子卷创建另一个快照，你可以给它命名为 root.dl。这样，如果你发现硬盘空间不够，你不必再下载五个 GB 的文件包。因为除了下载的包以外，所有的内容都将与 root 和 f36 共享，因此它不会占用任何额外的空间。然后说到磁盘块的共享问题……因为在 root 子卷中的 f36 文件和 f36 子卷中的相同文件都使用的是相同的磁盘位置，所以在处理 Btrfs 报告的可用空间时，dnf system-upgrade 会感到困惑。因此在升级过程中从 root 子卷中删除它们并不会真正释放任何空间。如果你耗尽了所有空间，并且决定重启电脑，那么图形用户界面（GUI）将无法启动。此时，你需要使用 Ctrl + Alt + F2 进入文本控制台并登录，这将是你磨练命令行技能的好机会。如何清空空间或扩展根文件系统在这里先不做讨论（我的文件系统经常在一个 LVM 的卷上，可以被扩展）。通常，为升级保留超过 50% 的空闲空间是比较保险的。恢复环节如果不幸出现问题，你可以重启电脑，并编辑 GRUB 条目以引导启动回退快照。如果你是新手，一旦需要在磁盘上修改 GRUB 条目（这样你就不需要每次启动时都进行编辑），可能需要一些指导。删除或重命名损坏的 root 子卷是非常直接的。你可以为 f36 子卷（或 root.dl 快照）创建一个快照，然后尝试再一次进行系统升级。以下是在子卷 f36 上启动到回退系统后重新开始的示例：$ mount | grep subvol $ sudo mount /dev/mmcblk2p3 /mnt/root $ cd /mnt/root $ sudo mv root root.failed $ sudo btrfs subvol snapshot f36 root Create a snapshot of 'f36' in './root' Don't forget to edit /mnt/root/root/etc/fstab to change the subvol mounted on "/" to "root". 事实证明，新的 f38 版本的 kernel-6.2.11 在我的 Pinebook 上进行系统升级后并未成功启动！（不过请不要担心，ARM 只是 Fedora Linux 的可选 CPU 架构——在主流设备上，你很少会遭遇此类问题。）的确，我成功地按照前文所述，在启动时编辑了 GRUB 条目并恢复到了 f36 的 kernel-6.2.10。现在，我继续使用着 f38，但同时搭载了 f36 的 kernel-6.2.10。更新：kernel-6.2.12 已经发布，且我已确认它在 Pinebook 上运行正常。过期问题随着你不断更新 f38 系统，它最终可能会希望删除 /boot 下的最后一个 f36 内核。通常来说，这并不是问题，因为到那个时候，你已经完全熟悉 f38，而 f36 快照只是一个存档。然而，如果你希望你的复刻版本（即 f36 的快照）能无限期地启动，那么你应当在 /boot 下保存一个能正常工作的 f36 内核。最简单的方法是在 /etc/dnf/dnf.conf 文件中设置 installonly_limit=0 并手动移除旧的内核，这种方法既简单又安全（尽管可能稍显繁琐）。这里还有一个更复杂的解决方案（不适合新手）：运行 find /boot -name "*fc36*" 指令，列举出所有在 f36 子卷快照中的内核及 GRUB 文件（这些文件并未包含在快照之内）。将这些文件备份至安全位置（例如我会挂载 f36 子卷，并将文件备份至其下的一个目录）。当 f38 系统启动后，对于每一个 f36 内核版本，都需使用 dnf 删除特定版本的内核（例如，使用 dnf remove kernel-core-5.19.11-200.fc36）。千万不要删除 f38 的内核！然后将你先前备份的 f36 内核恢复至 /boot 下。此时，f38 系统已经无法再识别 f36 的内核，因此也不会将其从 /boot 中删除。然而，使用此方法有一个缺点，那就是你可能会不小心删除正在运行的 f38 内核。如果大家有更佳的解决办法，欢迎在评论区分享。展望未来对于习惯于修改 GRUB 条目的用户，他们可能会考虑创建一个命名为 f38 的快照子卷。将当前的 GRUB 条目进行修改，以便启动到这个子卷，重启后，在这个子卷中进行系统升级。此后，总是根据它所包含的 Fedora Linux 版本来命名根文件系统的子卷。但在本文中，我没有采用这种作法，原因有两点：将当前活动的子卷命名为 root，这是遵循 Fedora Linux 的默认设置。坚持使用 root 作为当前子卷，这样在进行正常的系统升级操作之外，并不需要任何永久性的更改。正如本文所展示的，针对重大系统更改（如系统版本升级）可能引发问题时，只读快照作为本地恢复点，非常有用。这些快照还可以通过 Btrfs 的 send 子命令，发送至远程备份。（如果远程备份设备已经包含了先前的备份数据，Btrfs 可以进行增量发送，仅传输发生变更的文件，这样就能节省时间和空间。）如果你打算长期存档这些快照，保持清晰不混淆且能明确恢复顺序的关键，就是要使用一套一致的命名规则。关于如何使用 Btrfs 的 send 命令来创建备份的更多信息，你可以参考关于 Btrfs 快照备份 的文章。（题图：MJ/6aed1d19-f1dd-4935-ad6f-61f6a868f150）via: https://fedoramagazine.org/make-use-of-btrfs-snapshots-to-upgrade-fedora-linux-with-easy-fallback/作者：Stuart D Gathman 选题：lujun9972 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
这篇文章是《Btrfs 详解》系列文章中的一篇。从 Fedora Linux 33 开始，Btrfs 就是 Fedora Workstation 和 Fedora Silverblue 的默认文件系统。以防你忘记，这是系列文章中的前一篇：Btrfs 详解：基础概念。简介 子卷 Subvolume 允许将一个 Btrfs 文件系统划分成多个独立的子文件系统。这意味着你可以从 Btrfs 文件系统挂载子卷，就好像它们是独立的文件系统。除此之外，例如，你还可以通过 限额组 qgroup （我们将在本系列的另一篇文章里介绍）定义子卷能够占据的最大空间，或者用子卷去包含或排除快照中的文件（我们会后面的文章中会讲到）。自 Fedora Linux 33 后每个 Fedora Workstation 和 Fedora Silverblue 默认安装过程中会利用子卷。在这篇文章中我们会介绍它是如何工作的。下面你会找到很多关于子卷的例子。如果你想跟着操作，你必须拥有访问某些 Btrfs 文件系统的权限和 root 权限。你可以通过下面命令来验证你的 /home/ 目录是否是 Btrfs 。$ findmnt -no FSTYPE /home btrfs 这个命令会输出你 /home/ 目录的文件系统名。如果它是 btrfs，那就可以了。让我们创建一个新的目录去做实验：$ mkdir ~/btrfs-subvolume-test $ cd ~/btrfs-subvolume-test 在下面的文本中，你会看到很多像上面显示的那样的命令输出框。请在阅读/比较命令输出时请记住，框中的内容在行末会被换行。这使得识别跨多行的长行变得困难，降低了可读性。如果有疑问，试着调整浏览器窗口的大小，看看文本的变化!创建和使用子卷我们可以通过以下命令创建一个 Btrfs 子卷：$ sudo btrfs subvolume create first Create subvolume './first' 当我们检查当前目录，我们可以看到现在有一个名为 first 的新目录。注意到下面输出的第一个字符 d：$ ls -l total 0 drwxr-xr-x. 1 root root 0 Oct 15 18:09 first 我们可以像常规目录一样操作它：我们可以重命名它，移动它，在里面创建新文件和目录，等等。注意到目录属于 root，所以我们必须以 root 身份去做这些事情。如果它表现和看起来就像个目录，那我们如何知道这是不是一个 Btrfs 子卷呢？我们可以使用 btrfs 工具去列出所有子卷：$ sudo btrfs subvolume list . ID 256 gen 30 top level 5 path home ID 257 gen 30 top level 5 path root ID 258 gen 25 top level 257 path root/var/lib/machines ID 259 gen 29 top level 256 path hartan/btrfs-subvolume-test/first 如果你安装的是最新的 Fedora Linux，且未修改过，你很可能会看到和上面一样的输出。我们会在之后检查 home 和 root ，还有全部数字的含义。现在，我们看到在我们指定的路径下有一个子卷。我们可以将输出限制在我们当前位置下面的子卷：$ sudo btrfs subvolume list -o . ID 259 gen 29 top level 256 path home/hartan/btrfs-subvolume-test/first 让我们重命名子卷：$ sudo mv first second $ sudo btrfs subvolume list -o . ID 259 gen 29 top level 256 path home/hartan/btrfs-subvolume-test/second 我们还可以嵌套子卷：$ sudo btrfs subvolume create second/third Create subvolume 'second/third' $ sudo btrfs subvolume list . ID 256 gen 34 top level 5 path home ID 257 gen 37 top level 5 path root ID 258 gen 25 top level 257 path root/var/lib/machines ID 259 gen 37 top level 256 path hartan/btrfs-subvolume-test/second ID 260 gen 37 top level 259 path hartan/btrfs-subvolume-test/second/third 我们也可以移除子卷，就像移除目录一样：$ sudo rm -r second/third 或者通过特殊的 Btrfs 命令：$ sudo btrfs subvolume delete second Delete subvolume (no-commit): '/home/hartan/btrfs-subvolume-test/second' 像单独的文件系统一样操作子卷前面的简介里说 Btrfs 子卷就好像单独的文件系统。这意味着我们可以挂载子卷并且传递一些挂载选项给它。我们先创建一个小的目录结构去更好的理解发生了什么：$ mkdir -p a a/1 a/1/b $ sudo btrfs subvolume create a/2 Create subvolume 'a/2' $ sudo touch a/1/c a/1/b/d a/2/e 这就是目录结构的样子：$ tree . └── a ├── 1 │ ├── b │ │ └── d │ └── c └── 2 └── e 4 directories, 3 files 验证现在这里有一个新的 Btrfs 子卷：$ sudo btrfs subvolume list -o . ID 261 gen 41 top level 256 path home/hartan/btrfs-subvolume-test/a/2 为了挂载子卷，我们必须知道 Btrfs 子卷所在的块设备路径。下面的命令会告诉我们：$ findmnt -vno SOURCE /home/ /dev/vda3 现在我们挂载子卷。确保你将参数替换成你 PC 上的：$ sudo mount -o subvol=home/hartan/btrfs-subvolume-test/a/2 /dev/vda3 a/1/b 观察到我们使用 -o 参数去提供额外的选项去挂载程序。在这里我们告诉它挂载在设备 /dev/vda3 上 btrfs 文件系统里名为 home/hartan/btrfs-subvolume-test/a/2 的子卷。这是 Btrfs 特有的选项，在其他文件系统里没有的。我们可以看到目录结构变化了：$ tree . └── a ├── 1 │ ├── b │ │ └── e │ └── c └── 2 └── e 4 directories, 3 files 现在文件 e 出现了两次， d 不见了。我们现在可以用两个不同的路径访问相同的 Btrfs 子卷。在一个路径的所有变化会被立刻反应在其他的位置：$ sudo touch a/1/b/x $ ls -lA a/2 total 0 -rw-r--r--. 1 root root 0 Oct 15 18:14 e -rw-r--r--. 1 root root 0 Oct 15 18:16 x 让我们尝试更多的挂载选项。例如我们可以像这样以只读方式挂载子卷到 a/1/b（插入你 PC 的参数）：$ sudo umount a/1/b $ sudo mount -o subvol=home/hartan/btrfs-subvolume-test/a/2,ro /dev/vda3 a/1/b 我们和上面使用相同的命令，除了我们加上了 ro 在末尾。现在我们不能在这个挂载点上创建文件：$ sudo touch a/1/b/y touch: cannot touch 'a/1/b/y': Read-only file system 但直接访问子卷仍然像之前一样：$ sudo touch a/2/y $ tree . └── a ├── 1 │ ├── b │ │ ├── e │ │ ├── x │ │ └── y │ └── c └── 2 ├── e ├── x └── y 4 directories, 7 files 在下一步之前不要忘记进行清理：$ sudo rm -rf a rm: cannot remove 'a/1/b/e': Read-only file system rm: cannot remove 'a/1/b/x': Read-only file system rm: cannot remove 'a/1/b/y': Read-only file system 天啊，发生了什么？噢，因为我们在上面挂载只读子卷，所以不能删除它。从文件系统的角度来看，删除是一种写入操作：为了删除 a/2/b/e，我们从父目录 a/1/b 的内容中删除目录项 e。换句话来说，我们必须 写入 a/1/b 去表明 e 不复存在。所以我们先卸载子卷，然后移除目录：$ sudo umount a/1/b $ sudo rm -rf a $ tree . 0 directories, 0 files 子卷 ID还记得 btrfs subvolume list 命令的第一次输出吗？那包含了很多数字，让我们看看这些究竟什么。我在这里复制了输出，以便再次查看:ID 256 gen 30 top level 5 path home ID 257 gen 30 top level 5 path root ID 258 gen 25 top level 257 path root/var/lib/machines ID 259 gen 29 top level 256 path hartan/btrfs-subvolume-test/first 我们看到有三列数字，每个前面有一些字母来描述它们的作用。第一列是子卷 ID 。子卷 ID 在 Btrfs 文件系统是唯一的，而且唯一地标识子卷。这意味着名为 home 的子卷也可以用它的 ID 256 来引用。之前的挂载命令是这样写的：$ sudo mount -o subvol=hartan/... 另外一个完全合法的选择是使用子卷 ID ：$ sudo mount -o subvolid=... 子卷 ID 从 256 开始，每创建一个子卷依次递增 1 。但是在这里有一个例外：文件系统的根的子卷名称总是为 /，并且子卷 ID 是 5 。没错，即使文件系统的根技术上也是一个子卷。这是不言而喻的，因此不会出现在 btrfs subvolume 的输出列表里。如果你没有用 subvol 和 subvolid 参数去挂载一个 Btrfs 文件系统，subvolid=5 的顶级子卷就是默认的挂载对象。下面我们会看到一个想要显式挂载文件系统根的例子。第二列的数字是生成号，并且在每次 Btrfs 事务中递增。这几乎是一个内部的计数器，我们不会在这里讨论。最后，第三列数字是 父 子卷的子卷 ID。在上面的输出我们可以看到子卷 home 和 root 的父子卷 ID 都是 5。记住 ID 5 的特殊含义：这是文件系统的根。所以我们知道 home 和 root 都是顶级子卷的子卷。另一方面 hartan/btrfs-subvolume-test.first 是子卷 ID 256（也就是 home）的子卷。在下一节我们会看看子卷 root 和 home 是怎么来的。检查 Fedora Linux 的默认子卷当你从头创建一个新的 Btrfs 文件系统，里面是没有子卷的（当然，除了顶级子卷）。所以 Fedora Linux 里的 home 和 root 子卷是哪里来的？它们是安装程序在安装时创建的。传统的安装经常会为 / 和 /home 目录包含单独的文件系统分区。在启动时，它们通过恰当的挂载组成一个完整的文件系统。但这个方法有一个问题：除非你使用像 lvm 这样的技术，想在将来改变分区的大小是非常难的。因而你可能出现 / 或 /home 用完空间的情况，然而还有很多其他没被使用的分区和空间剩余。因为 Btrfs 子卷全都是相同文件系统的一部分，它们共享底层文件系统提供的空间。还记得我们在上面创建的子卷吗？我们从未告诉 Btrfs 它们多大：一个子卷可以占据文件系统拥有的全部空间，默认是不会阻止这种行为的。但是，我们 可以 通过 Btrfs 的 限额组 qgroup 动态地约束其大小，同时也可以在运行时修改（我们将在后续的文章中了解如何做的）。另外一个分离 / 和 /home 的优势是我们可以分别进行 快照 。子卷是快照的边界，对一个子卷的快照永远不会包含该子卷下面的其他子卷的内容。快照的更多细节会在后续的文章中介绍。理论已经足够了！我们来看看这是怎么回事。首先确保你的根文件系统类型是 Btrfs ：$ findmnt -no FSTYPE / btrfs 然后我们获取它所在的分区：$ findmnt -vno SOURCE / /dev/vda3 记住我们可以通过特殊的子卷 ID 5 挂载文件系统的根（适应文件系统分区！）：$ mkdir fedora-rootsubvol $ sudo mount -o subvolid=5 /dev/vda3 ./fedora-rootsubvol $ ls fedora-rootsubvol/ home root 而且还有 Fedora Linux 安装的子卷！但 Fedora Linux 是如何知道子卷 root 属于 / ，而 home 属于 /home 的呢？文件 /etc/fstab 包含了所谓的文件系统的静态信息。简而言之，在你系统启动的时候会一行一行地读取这个文件，然后挂载那里列出的所有文件系统。在我的系统上，这个文件长这样：$ cat /etc/fstab # [ ... ] # /etc/fstab # Created by anaconda on Sat Oct 15 12:01:57 2022 # [ ... ] # UUID=5e4e42bb-4f2f-4f0e-895f-d1a46ea47807 / btrfs subvol=root,compress=zstd:1 0 0 UUID=e3a798a8-b8f2-40ca-9da7-5e292a6412aa /boot ext4 defaults 1 2 UUID=5e4e42bb-4f2f-4f0e-895f-d1a46ea47807 /home btrfs subvol=home,compress=zstd:1 0 0 （注意上面的 “UUID” 开头行的内容被换行成两行）每行开头的 UUID 用于标识你系统上的硬盘和文件系统分区（大概相当于我在上面使用的 /dev/vda3 ）。第二列是文件系统应该挂载在文件系统树上的路径。第三列是文件系统类型。我们可以看到 / 和 /home 都是 btrfs 类型，正如我们期望的那样！最后，第四列是：这些是挂载选项，这里说通过 subvol=root 选项去挂载 / 。这正是我们一直在 btrfs subvolume list / 里看到的输出！有了这些信息，我们可以重新构建创建这个文件系统项的 mount 命令$ sudo mount -o subvol=root,compress=zstd:1 UUID=5e4e42bb-4f2f-4f0e-895f-d1a46ea47807 / （再次，上面的 “UUID” 开头行的内容被换行成两行）这就是 Fedora Linux 如何使用 Btrfs 子卷！如果你对好奇 Fedora Linux 为什么选择 Btrfs 作为默认的文件系统，请参阅下面链接的更改提议 [1] 。Btrfs 子卷的更多内容Btrfs 维基提供了关于子卷的更多信息，其中最重要的是可应用于 Btrfs 子卷的挂载选项。有些选项，比如 compress 只能应用到文件系统的层面，因而会影响一个 Btrfs 文件系统的所有子卷。你可以通过下面的链接找到entry [2] 。如果你对哪些目录是普通目录和哪些是子卷有困惑，你可以对你的子卷采用特殊的命名约定。例如，你可以给子卷名加上 @ 前缀去方便区分。现在你知道子卷表现得就像文件系统，有人可能会问如何才能最好地将子卷放置在特定位置。比如你想要一个 Btrfs 子卷在 ~/games 下面，然而你的主目录（~）本身就是一个子卷，你该如何实现呢？鉴于上面的例子，你可以使用像 sudo btrfs subvolume create ~/games 的命令。这样，你创建了所谓的 嵌套 子卷：在你的子卷 ~ 里，有一个子卷 games 。这正是一种达成目的的方法。其他有效的方法就是如同 Fedora 默认行为那样：在根子卷下创建所有子卷（也就是它们的父子卷 ID 是 5 ），然后挂载它们到特定的位置。Btrfs 维基有这些方法的概述和对于各自文件系统管理影响的简短讨论 [3] 。总结在本文中，我们探索了 Btrfs 子卷，它们像是 Btrfs 文件系统内部的独立的 Btrfs 文件系统。我们学习了如何创建、挂载和删除子卷。最后，我们探讨了 Fedora Linux 如何在我们完全没有注意到的情况下使用子卷。本系列的下一篇文章将讨论：快照 - 回到过去压缩 - 透明地节省存储空间配额组 - 限制文件系统大小RAID - 替代 mdadm 配置如果你还想了解与 Btrfs 相关的其他主题，请查看 Btrfs 维基 [4] 和文档 [5] 。不要忘记查看本系列的第一篇文章（如果你还没有看过的话）！如果你认为本系列文章缺少了一些内容，请在下面的评论中告诉我们。再会！参考资料https://fedoraproject.org/wiki/Changes/BtrfsByDefault#Benefit_to_Fedora ↩︎https://btrfs.readthedocs.io/en/latest/Subvolumes.html ↩︎https://btrfs.wiki.kernel.org/index.php/SysadminGuide#Layout ↩︎https://btrfs.wiki.kernel.org/index.php/Main_Page ↩︎https://btrfs.readthedocs.io/en/latest/Introduction.html ↩︎（题图：MJ/f047ea87-2490-40e5-9f91-d48d236675e5）via: https://fedoramagazine.org/working-with-btrfs-subvolumes/作者：Andreas Hartmann 选题：lujun9972 译者：A2ureStone 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
这篇文章是《Btrfs 详解》系列文章中的一篇。从 Fedora Linux 33 开始，Btrfs 就是 Fedora Workstation 和 Fedora Silverblue 的默认文件系统。介绍文件系统是现代计算机的基础之一。它是任何操作系统必不可少的一部分，且通常不为人注意。但是，像 Btrfs 这样的现代文件系统提供了许多很棒的特性，使计算机的使用更加方便。例如，它可以无感地为你压缩文件，或者为增量备份建立可靠的基础。这篇文章将带你高屋建瓴地了解 Btrfs 文件系统是如何工作的，有什么特性。本文既不会过多涉及技术细节，也不会研究其底层实现，系列后续的文章会详细介绍一些重要特性。什么是文件系统如果你基本了解过文件系统是如何工作的，那么下面的内容对你应该是不陌生的，你可以直接跳到下一节。否则，请先阅读下面对文件系统的简短介绍。简单来说，文件系统允许你的 PC 去寻找存储在磁盘上的数据。这听起来像是微不足道的工作，但实际上时至今日各种类型的非易失性存储设备（比如机械硬盘、固态硬盘、SD 卡等等）仍然与 1970 年代 PC 被发明时基本相同：一个（巨大的）存储块集合。“ 块 Block ” 是最小的可寻址存储单元。PC 上的每个文件内容被存储在多个块中。一个块通常是 4096 字节的大小。这取决于你的硬件和在这之上的软件（即文件系统）。文件系统允许我们从海量的存储块中查找文件的内容，这是通过所谓的 inode 去实现的。一个 inode 在特殊格式的存储块里记录了文件的信息。这包含文件的大小，哪里去寻找组成文件内容的存储块，访问规则（即谁可读，可写，可执行）等等。下面是 inode 的示意图：inode 的结构对文件系统的功能有巨大的影响，因此它是各种文件系统诸多的重要数据结构之一。出于这个原因，每个文件系统有各自的 inode 结构。如果你想了解更多信息，看看下面 链接 关于 Btrfs 文件系统 inode 结构的内容。如需更详细地了解各个字段的含义，你可以 参考 ext4 文件系统的 inode 结构。写时复制（CoW）文件系统相比 ext4，Btrfs 拥有的杰出特性之一是，它是一个 写时复制 Copy-on-Write （CoW）文件系统。当一个文件被改变和回写磁盘，它不会故意写回它原来的位置，而是被复制和存储在磁盘上的新位置。从这个意义上，可以简单地认为 Cow 是一种 “重定向”，因为文件写入被重定向到不同的存储块上。这听起来很浪费，但实际上并不是。这是因为被修改的数据无论如何一定会被写到磁盘上，不管文件系统是如何工作的。Btrfs 仅仅是确保了数据被写入在之前没被占据的块上，所以旧数据保持完整。唯一真正的缺点就是这种行为会导致文件碎片化比其他文件系统要快。在日常的电脑使用中，你不太可能会注意到这点差异。CoW 的优势在哪里？简单的说：文件被修改和编辑的历史被保存了下来。Btrfs 保存文件旧版本的引用（inode）可以轻易地被访问。这个引用就是快照：文件系统在某个时间点的状态镜像。这将是这系列文章里的单独的一篇，所以暂时留到后面介绍。除了保存文件历史，CoW 文件系统永远处于一致的状态，即使之前的文件系统事务（比如写入一个文件）由于断电等原因没有完成。这是因为文件系统的元数据更新也是写时复制的：文件系统本身永远不会被覆写，所以中断不会使其处于部分写入的状态。对文件的写时复制你可以将文件名视为对 inode 的指针。在写入文件的时候，Btrfs 创建一个被修改文件内容（数据）的拷贝，和一个新的 inode（元数据），然后让文件名指向新的 inode，旧的 inode 保持不变。下面是一个假设示例来阐述这点：这里 myfile.txt 增加了三个字节。传统的文件系统会更新中间的 Data 块去包含新的内容。CoW 文件系统不会改变旧的数据块（图中灰色），写入（复制）更改的数据和元数据在新的地方。值得注意的是，只有被改变的数据块被复制，而不是全部文件。如果没有空闲的块去写入新内容，Btrfs 将从被旧文件版本占据的数据块中回收空间（除非它们是快照的一部分，本系列后续文章会看到）。对目录的写时复制从文件系统的角度看，目录只是特殊类型的文件。与常规文件不同，文件系统直接解释数据块的内容。一个目录有自身的元数据（inode，就像上面说的文件一样）去记录访问权限或修改时间。最简单的形式，存在目录里的数据（被叫作目录项）是一个 inode 引用的列表，每个 inode 又是另外的文件或目录。但是，现代文件系统在目录项中至少会存储一个文件名和对应的 inode 引用。之前已经指出，写入一个文件会创建之前 inode 的副本，并相应修改其内容。从根本上，这产生了一个和之前无关的新的 inode 。为了让被修改的文件对文件系统可见，所有包含这个文件引用的目录项都会被更新。这是一个递归的过程！因为一个目录本身是一个带有 inode 的文件。修改目录里的任何一项都会为这个目录文件创建新的 inode 。这会沿着文件系统树递归直到文件系统的根。所以，只要保留对任何旧目录的引用，并且这些目录没有被删除和覆写，就可以遍历之前旧状态的文件系统树。这就是快照的功能。后续文章可以期待的内容Btrfs 不只是一个 Cow 文件系统。它目标是实现高级特性的同时关注容错、修复和易于管理（参见 文档）。本系列未来的文章将会专门介绍这些特性。子卷 – 文件系统中的文件系统快照 – 回到过去压缩 – 透明节省存储空间配额组 – 限制文件系统大小RAID – 替代 mdadm 配置这远非 Btrfs 特性的详尽列表。如果你想全面地了解可用特性，查看 维基 和 文档。总结我希望我已能激起你进一步了解计算机文件系统的兴趣。如果目前你有任何疑问，请在评论区留言讨论以便在日后文章中探讨，同时，你也可以自行学习文中提供的相关资源。如果你发现 Btrfs 中某项特别有趣的功能，也欢迎在评论区提出。如果某个主题收到足够的关注，我可能会在系列文章中新增相关内容。下一篇文章再见！（题图：MJ/35fa1970-1806-4026-8d58-095a56206ec9）via: https://fedoramagazine.org/working-with-btrfs-general-concepts/作者：Andreas Hartmann 选题：lkxed 译者：A2ureStone 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
引言这篇概述文章将告诉你为何以及如何迁移你的当前分区到 Btrfs 文件系统。如果你对此感兴趣，请阅读这篇分步指南来完成。从 Fedora 33 开始，新安装的 Fedora 操作系统默认文件系统为 Btrfs。我确信大部分用户现在已经听说了它的优势：写时复制、内置校验、灵活的压缩方式、简易的快照和回滚方式。它确实是一个现代化的文件系统，为桌面存储带来新的功能。在升级到 Fedora 33 后，我想利用 Btrfs 的优势，但对我个人来说，我不想因为“只是为了改变文件系统”而去重装整个系统。我发现（只有）寥寥无几的具体如何做转换的教程，所以我决定在这里分享我的详细经验。小心！这样做你是在玩火。希望你阅读以下内容时不要感到惊讶：在编辑分区和转换文件系统时，你的数据可能会被破坏和丢失。最终，你可能会得到一个不能启动的操作系统，并面临数据恢复的风险。你可能会无意删除你的分区，或者以其它方式破坏了你的操作系统。这些转换过程即使对于生产系统来说也是安全的 —— 前提是你提前做好了计划，对关键数据做好了备份和回滚计划。作为一个 可以执行超级权限的系统管理员，你可以在没有限制、没有任何常规安全防护措施的情况下，做任何事情。安全的方式：重装 Fedora重装操作系统是转换文件系统到 Btrfs 的 “官方” 方式，推荐给大多数用户使用。因此，如果在这个教程中有那么一点不确定，就选择这种方式。步骤大致如下：备份你的主文件夹和你系统中可能会用到的任何数据，比如 /etc。（编者按：虚拟机也是这样）将已安装的安装包以列表形式保存到到文件中。重新安装 Fedora，删除你当前的分区，并选择新的 Btrfs 默认分区方案。恢复主文件夹的内容，并使用软件包列表文件重装软件包。对于详细的步骤和命令，请看一位社区用户在 ask.fedoraproject.org 站点的评论。如果正确完成，你将得到一个和之前一样的操作系统，使丢失数据的风险最小化。转换的利弊让我们快速澄清一下：这种文件系统转换有什么优势和劣势？优势：当然，不需要重新安装！你的系统里的所有文件和之前一模一样。技术上来说，没有备份的情况下，就地进行是可能的。你会学到许多关于 Btrfs 的知识！如果所有都按计划进行，会是相当快的一个过程。劣势：你必须熟悉终端环境和 shell 命令。你可能会丢失数据，参见上文。如果出了什么问题，你得自己解决。特别之处：你需要大约 20% 的可用磁盘空间才能成功转换。但对于完整的备份和重装方式，你可能需要的空间更多。你可以在转换过程中自定义你分区的所有参数，但如果选择重装，你也可以从 Anaconda 自定义。LVM 怎么办？在近期几次 Fedora 安装中，LVM 布局一直是默认的。如果你有一个带有多个分区（例如 / 和 /home）的 LVM 分区布局，你得以某种方式合并它们，来获得 Btrfs 所有性能。如果选择这样做，你可以单独转换分区到 Btrfs 文件系统，同时保留卷组。然而，迁移到 Btrfs 文件系统的优势之一是摆脱 LVM 分区布局强加的限制。你也可以利用 Btrfs 文件系统提供的收发功能在转换后来合并分区。另见 《Fedora 杂志》： 利用 LVM 回收硬盘空间、从 Btrfs 快照中恢复文件 以及 在 Btrfs 和 LVM-ext4 两者之间做选择。了解 Btrfs建议阅读以下内容对 Btrfs 文件系统是什么有一个基础的了解。如果你没有把握，只有选择重装 Fedora 这种安全的方式。必须了解的：Fedora Magazine：Btrfs 来到 Fedora 33Btrfs 系统管理指南, 尤其是 关于子卷和 flat 子卷布局。btrfs-convert 指南有用的资源：man 8 btrfs – 命令行界面man 5 btrfs – 挂载参数man btrfs-convert – 要用到的转换工具man btrfs-subvolume – 管理子卷转换步骤创建一个实时镜像由于不能转换已挂载的文件系统，我们将通过 Fedora 实时镜像 Live Image 进行。安装 Fedora 镜像写入工具，然后 “烧录” Fedora 33 到你的 U 盘中来创建实时镜像。释放磁盘空间btrfs-convert 会在分区的剩余空间重新创建文件系统的元数据，同时保持所有已有的 ext4 文件系统数据还在它当前的位置上。不幸的是，所需的剩余空间的大小无法提前知道：如果没有足够的空间，转换将会失败（但不会破坏数据）。这里有一些释放空间有用的方法：利用 baobab 来识别大容量的文件和文件夹，然后移除。如果可能的话，不要手动删除主文件夹以外的文件。清理旧的系统日志：journalctl –vacuum-size=100M。如果你正使用 Docker，请小心地使用类似 docker volume prune、docker image prune -a 这样的工具。清理 GNOME Boxes 之类的虚拟机内不用的镜像。清理不用的软件包和 Flatpak 包：dnf autoremove、flatpak remove –unused。清理软件包缓存：pkcon refresh force -c -1、dnf clean all。如果你有把握，你可以谨慎的清理 ~/.cache 文件夹。转换到 Btrfs备份你所有有价值的数据，确保你的系统已完全更新，然后重启到实时镜像。运行 gnome-disks 工具找到你所拥有的设备的路径，比如 /dev/sda1（如果你在使用 LVM，它可能看起来有所不同）。检查文件系统然后执行转换：（编者按：以下命令使用 root 用户运行，谨慎使用！）$ sudo su - # fsck.ext4 -fyv /dev/sdXX （请替换为你的具体的设备路径） # man btrfs-convert （阅读它） # btrfs-convert /dev/sdXX （请替换为你的具体的设备路径） 这将会花十几分钟甚至几个小时，依据分区的大小和是机械硬盘还是固态硬盘。如果你看到错误，你可能需要更多剩余空间。作为最后的手段，你可以尝试 btrfs-convert -n。怎样回滚？如果因为某些原因转换失败，你的分区将保持在 ext4 文件系统或者它之前的状态。如果你想在成功转换之后回滚，简单如下：# btrfs-convert -r /dev/sdXX 警告！ 如果你做了以下这些事情之一，你将永久失去回滚的功能：碎片整理、均衡或者删除 ext2_saved 子卷。由于 Btrfs 文件系统的写时复制特性，你可以安全的复制/移动甚至删除文件、创建子卷，因为 ext2_saved 会保持引用旧数据。挂载和检查现在这个分区应该已经有了 Btrfs 文件系统。挂载它然后查看你的文件……和子卷！# mount /dev/sdXX /mnt （请替换为你的具体的设备路径） # man btrfs-subvolume （阅读它） # btrfs subvolume list / （使用 -t 以表格方式查看） 因为你已经阅读了 相关的手册页，你应该知道创建子卷快照是安全的，并且有 ext2-saved 子卷作为你之前数据的简易备份。是时候阅读 Btrfs 系统管理指南了，这样你就不会把常规文件夹和子卷混淆了。创建子卷我们希望实现一个“扁平”子卷布局，这和 Anaconda 默认创建的布局相同：toplevel （卷根目录，不能被默认挂载） +-- root （子卷根目录，被挂载到 /） +-- home （子卷根目录，被挂载到 /home） 你可以跳过这个步骤，或者使用一个不同的布局。这种特殊结构的优势是你可以轻松的创建 /home 的快照，并且对每个子卷使用不同的压缩和挂载参数。# cd /mnt # btrfs subvolume snapshot ./ ./root2 # btrfs subvolume create home2 # cp -a home/* home2/ 这里我们已经创建了两个子卷。root2 是一个完整的分区快照，而 home2 开始是一个空子卷，然后我们往里复制内容。（这个 cp 命令不会重复数据，所以会很快。）在 /mnt 目录（顶层子卷），删除除了 root2、home2 和 ext2_saved 之外的所有内容。重命名 root2 和 home2 子卷为 root 和 home。在 root 子卷里，清空 home 目录，以便之后我们能够挂载 home 子卷。如果都做对了，那就很简单了！修改 fstab 分区表为了重启之后挂载新卷，必须要修改 fstab，用新的行来代替旧的 ext4 文件系统挂载行。你可以使用 blkid 命令来找到你的分区的 UUID。UUID=xx / btrfs subvol=root 0 0 （请替换为你的具体 UUID） UUID=xx /home btrfs subvol=home 0 0 （请替换为你的具体 UUID） （注意如果指向的是同一个分区，那么这两个 UUID 是相同的。）这些都是新安装的 Fedora 33 的默认值。在 fstab 中，你也可以选择自定义压缩和添加类似 noatime 这样的参数。可以查看 关于压缩参数的维基页面 和 man 5 btrfs 了解所有相关的参数。chroot 到系统如果你曾经做过系统恢复，我想你肯定知道这些命令。这里，我们将得到一个 基本上 在你系统里的 shell 提示符，可以访问网络。首先，我们必须重新挂载 root 子卷到 /mnt 目录，然后挂载 /boot 和 /boot/efi 分区（它们可能有所不同，这取决于你的文件系统布局）：# umount /mnt # mount -o subvol=root /dev/sdXX /mnt （请替换为你的具体的设备路径） # mount /dev/sdXX /mnt/boot （请替换为你的具体的设备路径） # mount /dev/sdXX /mnt/boot/efi （请替换为你的具体的设备路径） 然后我们继续挂载系统设备：# mount -t proc /proc /mnt/proc # mount --rbind /dev /mnt/dev # mount --make-rslave /mnt/dev # mount --rbind /sys /mnt/sys # mount --make-rslave /mnt/sys # cp /mnt/etc/resolv.conf /mnt/etc/resolv.conf.chroot # cp -L /etc/resolv.conf /mnt/etc # chroot /mnt /bin/bash $ ping www.fedoraproject.org 重装 GRUB 及内核最容易的方法就是重装 GRUB 和 内核，因为它完成了所有必要的配置 —— 现在我们可以访问网络了。所以，在 chroot 环境内部：# mount /boot/efi # dnf reinstall grub2-efi shim # grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg # dnf reinstall kernel-core ...或者干脆重新生成 initramfs： # dracut --kver $(uname -r) --force 如果你是支持 UEFI 的系统，这里是适用的。如果你是 BIOS 的系统，请查看下面的文档。重启之前，让我们查看是否一切正常：# cat /boot/grub2/grubenv # cat /boot/efi/EFI/fedora/grub.cfg # lsinitrd /boot/initramfs-$(uname -r).img | grep btrfs 你应该在 grubenv 和 grub.cfg 有正确的分区 UUID 或指向（grubenv 可能没有更新，如有必要可以编辑它），并在 grub.cfg 中看到 insmod btrfs 配置和在 initramfs 镜像中有 btrfs 模块。参见: Fedora 系统管理指南中的 重装 GRUB 2 和 验证初始 RAM 磁盘镜像 。重启现在系统能够正常启动。如果不能，别慌，回到实时镜像修复这个问题。最坏的情况下，你可以从那里重装 Fedora 。首次启动之后检查你的新 Btrfs 文件系统一切都正常。如果你觉得没问题，你需要回收旧的 ext4 快照使用的空间，进行碎片整理和平衡子卷。后两者可能要花一些时间，并且相当耗费资源。对此你必须这样挂载顶级子卷：# mount /dev/sdXX -o subvol=/ /mnt/someFolder # btrfs subvolume delete /mnt/someFolder/ext2_saved 然后，当机器有空闲时间时，运行这些命令：# btrfs filesystem defrag -v -r -f / # btrfs filesystem defrag -v -r -f /home # btrfs balance start -m / 最后，有一个 “非写时复制” 属性，对于新系统，这个属性是为虚拟机镜像文件夹自动设置的。如果你使用虚拟机的话，可以设置它：# chattr +C /var/lib/libvirt/images $ chattr +C ~/.local/share/gnome-boxes/images 这个属性只会对在这些文件夹里的新文件生效。复制镜像并删除原镜像，你可以通过 lsattr 确认结果。总结我真心希望你发现这个教程是有用的，并且能够对是否在你的系统上转换为 Btrfs 做出谨慎而明智的决定。祝你成功转换！欢迎在评论中分享你的经验，或者遇到更深层次的问题，请在 ask.fedoraproject.org 提问。via: https://fedoramagazine.org/convert-your-filesystem-to-btrfs/作者：Gergely Gombos 选题：lujun9972 译者：hwlife 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
硬核观察 #453 微软 Edge 浏览器变成了广告软件
微软 Edge 浏览器变成了广告软件不少用户反馈在升级到 Edge 新版本中出现了 更多的提醒和广告，例如推荐用户使用 Microsoft Start（此前叫做 MSN feed）的服务。微软正在试验更多的广告/推荐，这些广告将出现在浏览器的新标签页中。此外，微软的弹出广告也显示，它正在利用浏览器的新协助功能，从你执行的搜索中收集结果改进其必应搜索引擎。老王点评：这种情况特别像早些年流行的一种软件 AD-Ware。Btrfs 文件系统将改变格式以解决一些严重问题Btrfs 文件系统开发者正在开发一个重磅更新，以解决文件系统设计中的一些“糟糕的部分”，如全局根文件系统中的锁争夺，以及块组项在整个范围树上的传播问题。但这个更新会导致其磁盘格式发生变化，之前的 Btrfs 文件系统需要转换才行。这项工作预计持续 6~12 个月。老王点评：虽然这种开发的初衷是好的，但是引入不兼容性还是要慎重，可以考虑叫 Btrfs2。Chrome 推送企业策略补丁，以阻止查看网页 HTML 源码谷歌在 Chrome 98 中提供了一个 Chrome 企业策略补丁，允许学校 IT 管理员设置 禁止查看 HTML 源代码。开发团队声称这项功能旨在解决学校中某些持续存在的问题，尤其是涉及学生通过查看 HTML 源码来偷看线上测验的答案、或通过技术手段绕过屏蔽站点。这个更新补丁的推出时机，正值前段时间美国密苏里州州长声称“查看 HTML 源码等同于黑客攻击”，因而引发了不少争议。老王点评：其实他们就是想把互联网变成一个不透明的黑盒。
B-tree 文件系统（Btrfs）融合了文件系统和卷管理器。它为 Linux 操作系统提供了高级文件系统应当拥有的诸多不错的功能特性。好几年前 Btrfs 就已经可以在 Linux 中使用了，所以你可能已经熟悉它了。如果没有，你可能对它尚有疑虑，尤其是如果你使用的是 Fedora 工作站 （Btrfs 现在是它的默认文件系统）。本文旨在帮助你熟悉它及其高级功能，例如 写时复制 和 校验和。Btrfs 是 “B-Tree Filesystem” 的缩写，实际上是文件系统和卷管理器的结合体。它通常被视为对 ZFS 的回应，ZFS 早在 2005 年就被引入 Sun 微系统的 Solaris 操作系统中，现在基本上被一个名为 OpenZFS 的开源实现所取代。Ubuntu 和 FreeBSD 常常使用 OpenZFS。其他具有类似特性的示例有红帽的 Stratis 和 Linux 逻辑卷管理器 Logical Volume Manager （LVM）。安装为了尝试 Btrfs，我下载了 Fedora 33 工作站 ISO 文件 并将其安装到一个新的虚拟机（VM）中。安装过程与以前的版本没有变化。我没有自定义任何设置，包括驱动器分区和格式化，以保持本教程的准确“开箱即用”设置。当虚拟机启动并运行后，我安装并运行了 GNOME 分区编辑器（GParted），以获得一个良好的、工厂级的驱动器布局视图。从安装这一点来说，与你以前所习惯的情况没什么不同；事实上，你可以正常使用该系统，甚至可能没有注意到文件系统是 Btrfs。然而，拥有这个新的默认文件系统使你能够利用几个很酷的特性。检查 Btrfs 文件系统我暂时没有找到特定于 Btrfs 的图形工具，尽管它的一些功能已经被合并到现有的磁盘管理工具中。在命令行中，你可以更仔细地查看 Btrfs 格式：# btrfs filesystem show Label: 'fedora_localhost-live' uuid: f2bb02f9-5c41-4c91-8eae-827a801ee58a Total devices 1 FS bytes used 6.36GiB devid 1 size 10.41GiB used 8.02GiB path /dev/vda3 修改 Btrfs 标签我首先注意到的是安装程序设置的文件系统标签：fedora_localhost-live。这是不准确的，因为它现在是一个已安装的系统，不再是 livecd。所以我使用 btrfs filesystem label 命令对其进行了更改。修改 Btrfs 标签非常的简单：# btrfs filesystem label / fedora_localhost-live # btrfs filesystem label / fedora33workstation # btrfs filesystem label / fedora33workstation 管理 Btrfs 子卷子卷看起来像是可以由 Btrfs 管理的标准目录。我的新 Fedora 33 工作站上有几个子卷：# btrfs subvolume list / ID 256 gen 2458 top level 5 path home ID 258 gen 2461 top level 5 path root ID 265 gen 1593 top level 258 path var/lib/machines 使用 btrfs subvolume Create 命令创建新的子卷，或使用 btrfs subvolume delete 删除子卷：# btrfs subvolume create /opt/foo Create subvolume '/opt/foo' # btrfs subvolume list / ID 256 gen 2884 top level 5 path home ID 258 gen 2888 top level 5 path root ID 265 gen 1593 top level 258 path var/lib/machines ID 276 gen 2888 top level 258 path opt/foo # btrfs subvolume delete /opt/foo Delete subvolume (no-commit): '/opt/foo' 子卷允许设置配额、拍摄快照以及复制到其他位置和其他主机等操作。那么系统管理员如何利用这些功能？用户主目录又是如何操作的呢？添加用户就像从前一样，添加一个新的用户帐户会创建一个主目录供该帐户使用：# useradd student1 # getent passwd student1 student1:x:1006:1006::/home/student1:/bin/bash # ls -l /home drwx------. 1 student1 student1 80 Oct 29 00:21 student1 传统上，用户的主目录是 /home 的子目录。所有权和操作权是为所有者量身定制的，但是特殊功能来没有管理它们。而企业服务器环境是另外一种情况。通常，目录是为特定的应用程序及其用户保留的。你可以利用 Btrfs 来管理和应用对这些目录的约束。为了将 Btrfs 子卷作为用户主页，在 useradd 命令中有一个新选项：--Btrfs-subvolume-home。尽管手册页尚未更新（截至本文撰写之时），但你可以通过运行 useradd --help 来查看该选项。通过在添加新用户时传递此选项，将创建一个新的 Btrfs 子卷。它的功能与创建常规目录时的 -d 选项类似：# useradd --btrfs-subvolume-home student2 Create subvolume '/home/student2' 使用 getent passwd student2 验证用户，它将显示为正常。但是，运行 btrfs subvolume 命令列出子卷，你将看到一些有趣的内容：新用户的主目录！# btrfs subvolume list / ID 256 gen 2458 top level 5 path home ID 258 gen 2461 top level 5 path root ID 265 gen 1593 top level 258 path var/lib/machines ID 272 gen 2459 top level 256 path home/student2 探索企业服务器环境的第二个场景。假设你需要在 /opt 中安装一个 WildFly 服务器并部署一个 Java web 应用程序。通常，你的第一步是创建一个 wildfly 用户。使用新的 --btrfs-subvolume-home 选项和 -b 选项来指定 /opt 作为基本目录：# useradd -b /opt --btrfs-subvolume-home wildfly Create subvolume '/opt/wildfly' 于是，wildfly 用户可以使用了，并且主目录设置在了 /opt/wildfly。删除用户删除用户时，有时需要同时删除该用户的文件和主目录。userdel 命令有 -r 选项，它可以同时删除 Btrfs 子卷：# userdel -r student2 Delete subvolume (commit): '/home/student2' 设置磁盘使用配额在我的一节计算机科学课上，一个学生运行了一个失控的 C 程序，然后写进了磁盘，将我们院的 Unix 系统上整个 /home 目录都填满了！在管理员终止失控进程并清除一些空间之前，服务器将无法使用。上述情况也是如此；那个 Wildfly 企业应用程序将为其用户提供越来越多的日志文件和内容存储。如何防止服务器因磁盘已满而死机？设置磁盘使用限制是个好主意。幸运的是，Btrfs 通过设置配额的方式支持这一点。配置配额需要几个步骤。第一步是在 Btrfs 文件系统上启用配额：# btrfs quota enable / 确保你知道每个子卷的配额组（qgroup）ID 号，该编号由 btrfs subvolume list 命令显示。每个子卷都需要基于 ID 号码来关联配额组。这可以通过 btrfs qgroup create 单独完成，但是，btrfs 维基提供了以下命令来加快为文件系统上的子卷创建配额组：> btrfs subvolume list \<path> | cut -d' ' -f2 | xargs -I{} -n1 btrfs qgroup destroy 0/{} \<path> 在新安装的 Fedora 33 工作站系统中，你在根文件系统路径上操作，/。用根路径替换 \<path>：# btrfs subvolume list / | cut -d' ' -f2 | xargs -I{} -n1 btrfs qgroup create 0/{} / 然后运行 btrfs quota rescan，查看新的配额组：# btrfs quota rescan / quota rescan started # btrfs qgroup show / qgroupid rfer excl -------- ---- ---- 0/5 16.00KiB 16.00KiB 0/256 272.04MiB 272.04MiB 0/258 6.08GiB 6.08GiB 0/265 16.00KiB 16.00KiB 0/271 16.00KiB 16.00KiB 0/273 16.00KiB 16.00KiB 于是现在，你可以将配额分配给其中一个配额组，然后将配额应用于其关联的子卷。因此，如果要将 student3 的主目录使用限制为 1 GB，请使用 btrfs qgroup limit 命令：# btrfs qgroup limit 1G /home/student3 查看特定子卷的配额：# btrfs qgroup show -reF /home/student3 qgroupid rfer excl max_rfer max_excl -------- ---- ---- -------- -------- 0/271 16.00KiB 16.00KiB 1.00GiB none 稍有不同的选项参数将显示所有配额组和设置的所有配额：# btrfs qgroup show -re / qgroupid rfer excl max_rfer max_excl -------- ---- ---- -------- -------- 0/5 16.00KiB 16.00KiB none none 0/256 272.04MiB 272.04MiB none none 0/258 6.08GiB 6.08GiB none none 0/265 16.00KiB 16.00KiB none none 0/271 16.00KiB 16.00KiB 1.00GiB none 0/273 16.00KiB 16.00KiB none none 其他特性这些例子提供了 Btrfs 特性的一些思考。运行 btrfs --help 查看命令的完整列表。还有许多其他值得注意的功能；例如，快照和发送/接收是两个值得学习的功能。总结讨论Btrfs 为向 Linux 提供高级文件系统特性集贡献了很多特性。这不是第一次；我知道 ZFS 在大约 15 年前引入了这种类型的文件系统，但是 Btrfs 是完全开源的，不受专利的限制。如果你想探索这个文件系统，我建议从虚拟机或备用系统开始。我想能够出现一些图形化的管理工具，为那些喜欢用图形工具的系统管理员提供便利。幸运的是，Btrfs 具有强大的开发活动，Fedora 33 项目决定将其设置为工作站上的默认值就证明了这一点。via: https://opensource.com/article/20/11/btrfs-linux作者：Alan Formy-Duval 选题：lujun9972 译者：Chao-zhi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Fedora 33 在其各类桌面版本中引入了新的默认文件系统 Btrfs。多年以来，Fedora 一直在 逻辑卷管理 Logical Volume Manager （LVM） 卷之上使用 ext4，引入 Brtfs 对 Fedora 来说是一个很大的转变。更改默认文件系统需要 令人信服的原因。虽然 Btrfs 是令人兴奋的下一代文件系统，但 LVM 上的 ext4 是成熟而稳定的。本指南旨在探索各自的高级特性，使得更容易在 Btrfs 和 LVM-ext4 之间进行选择。先说结论最简单的建议是坚持使用默认值。全新安装的 Fedora 33 环境默认为 Btrfs，升级之前的 Fedora 版本将继续使用最初安装的设置，通常是 LVM-ext4。对于现有的 Fedora 用户来说，获取 Btrfs 的最简单方式是全新安装。然而，全新安装比简单升级更具破坏性。除非有特殊需要，否则这种干扰可能是不必要的。Fedora 开发团队仔细考虑了这两个默认值，因此对任何一个选择都要有信心。那么其他文件系统呢？现在有很多 Linux 系统的文件系统。在加上卷管理器、加密方法和存储机制的组合后，这一数字呈爆炸式增长。那么，为什么要关注 btrfs 和 LVM-ext4 呢？对于 Fedora 的用户来说，这两种设置可能是最常见的。在 Fedora 11 中，LVM 之上的 ext4 成为了默认磁盘布局，在此之前则使用的是 ext3。既然 Btrfs 是 Fedora 33 的默认设置，那么绝大多数现有用户会考虑是应该原地踏步还是向前跳跃。面对全新安装的 Fedora 33 环境，有经验的 Linux 用户可能会想知道是使用这个新的文件系统，还是退回到他们熟悉的文件系统。因此，在众多可能的存储选项中，许多 Fedora 用户会想知道如何在 Btrfs 和 LVM-ext4 之间进行选择。两者的共性尽管两个文件系统之间存在核心差异，但 Btrfs 和 LVM-ext4 实际上有很多共同之处。两者都是成熟且经过充分测试的存储技术。从 Fedora Core 的早期开始，就一直在使用 LVM，而 ext4 在 2009 年成为 Fedora 11 的默认设置。Btrfs 在 2009 年并入 Linux 主线内核，并且 Facebook 广泛使用了该文件系统。SUSE Linux Enterprise 12 在 2014 年使其成为默认文件系统。因此，它在生产环境中也有着长久的运行时间。这两个系统都能很好地防止因意外停电而导致的文件系统损坏，尽管它们的实现方式不同。它们支持的配置包括使用单盘设置和跨越多个设备，并且这两种配置都能够创建近乎即时的快照。有各种工具可以帮助管理这两种系统，包括命令行和图形界面。这两种解决方案在家用台式机和高端服务器上都同样有效。LVM-ext4 的优势ext4 文件系统 专注于高性能和可伸缩性，没有太多额外的花哨之处。它能有效地防止长时间后的碎片化，并当碎片化出现后提供了 很好的工具。ext4 之所以坚如磐石，是因为它构建在前代的 ext3 文件系统之上，带来了多年的系统内测试和错误修复。LVM-ext4 环境中的大多数高级功能都来自 LVM 本身。LVM 位于文件系统的“下方”，这意味着它支持任何文件系统。 逻辑卷 Logical volume （LV）是通用的块设备，因此 虚拟机可以直接使用它们。这种灵活性使得每个逻辑卷都可以使用合适的文件系统，用合适的选项应对各种情况。这种分层方法还遵循了“小工具协同工作”的 Unix 哲学。从硬件抽象出来的 卷组 volume group （VG）允许 LVM 创建灵活的逻辑卷。每个逻辑卷都提取自同一个存储池，但具有自己的设置。调整卷的大小比调整物理分区的大小容易得多，因为没有数据有序放置的限制。LVM 物理卷 physical volume （PV）可以是任意数量的分区，甚至可以在系统运行时在设备之间移动。LVM 支持只读和读写的 快照，这使得从活动系统创建一致的备份变得很容易。每个快照都有一个定义的大小，更改源卷或快照卷将占用其中的空间。又或者，逻辑卷也可以是 稀疏配置池 thinly provisioned pool 的一部分。这允许快照自动使用池中的数据，而不是使用在创建卷时定义的固定大小的块。有多个磁盘驱动器的 LVM当有多个设备时，LVM 才真正大放异彩。它原生支持大多数 RAID 级别，每个逻辑卷可以具有不同的 RAID 级别。LVM 将自动为 RAID 配置选择适当的物理设备，或者用户可以直接指定它。基本的 RAID 支持包括用于性能的数据条带化（RAID0）和用于冗余的镜像（RAID1）。逻辑卷也可以使用 RAID5、RAID6 和 RAID10 等高级设置。LVM RAID 支持已经成熟，因为 LVM 在底层使用的 设备映射器（dm） 和 多设备（md） 内核支持， 与 mdadm 使用的一样。对于具有快速和慢速驱动器的系统，逻辑卷也可以是 缓存卷。经典示例是 SSD 和传统磁盘驱动器的组合。缓存卷使用较快的驱动器来存储更频繁访问的数据（或用作写缓存），而慢速的驱动器则用于处理大量数据。LVM 中大量稳定的功能以及 ext4 的可靠性在既往的使用中早已被证明了。当然，功能越多就越复杂。在配置 LVM 时，要找到合适的功能选项是很有挑战性的。对于单驱动器的台式机系统，LVM 的功能（例如 RAID 和缓存卷）不适用。但是，逻辑卷比物理分区更灵活，快照也很有用。对于正常的桌面使用，LVM 的复杂性会成为典型的用户可能遇到的问题恢复的障碍。Btrfs 的优势从前几代文件系统中学到的经验指导了构建到 Btrfs 的功能设计。与 ext4 不同，它可以直接跨越多个设备，因此它具有通常仅在卷管理器中才能找到的功能。它还具有 Linux 文件系统空间中独有的功能（ZFS 具有相似的功能集，但不要指望它在 Linux 内核中出现）。Btrfs 的主要功能也许最重要的功能是对所有数据进行 校验和 checksumming 。校验和与 写时复制 copy-on-write （COW）一起，提供了在意外断电后确保文件系统完整性的 关键方法。更独特的是，校验和可以检测数据本身中的错误。悄然的数据损坏（有时也称为 bitrot）比大多数人意识到的更常见。如果没有主动验证，损坏最终可能会传播到所有可用的备份中。这使得用户没有有效的副本。通过透明地校验所有数据，Btrfs 能够立即检测到任何此类损坏。启用正确的 dup 或 raid 选项，文件系统也可以透明地修复损坏。写时复制也是 Btrfs 的基本功能，因为它在提供文件系统完整性和即时子卷快照方面至关重要。从公共子卷创建快照后，快照会自动共享底层数据。另外，事后的 重复数据删除 deduplication 使用相同的技术来消除相同的数据块。单个文件可以通过使用 cp 的 reflink 选项 来使用 COW 功能。reflink 副本对于复制大型文件（例如虚拟机镜像）特别有用，这些文件往往随着时间的推移具有大部分相同的数据。Btrfs 支持跨越多个设备，而无需卷管理器。多设备支持可提供数据镜像功能以实现冗余和条带化以提高性能。此外，还实验性地支持更高级的 RAID 级别，例如 RAID 5 和 RAID 6。与标准 RAID 设置不同，Btrfs 的 RAID1 实际上允许奇数个设备。例如，它可以使用 3 个设备，即使它们的大小不同。所有 RAID 和 dup 选项都是在文件系统级别指定的。因此，各个子卷不能使用不同的选项。请注意，使用多设备的 RAID1 选项意味着即使一个设备发生故障，卷中的所有数据都是可用的，并且校验功能可以保持数据本身的完整性。这超出了当前典型的 RAID 设置所能提供的范围。附加功能Btrfs 还支持快速简便的远程备份。子卷快照可以 发送到远程系统 进行存储。通过利用文件系统中固有的 COW 元数据，这些传输通过仅发送先前发送的快照中的增量更改而非常有效。诸如 snapper 之类的用户应用程序使管理这些快照变得容易。另外，Btrfs 卷可以具有 透明压缩 功能，并且 chattr +c 可以标记进行压缩的单个文件或目录。压缩不仅可以减少数据消耗的空间，还可以通过减少写入操作量来帮助延长 SSD 的寿命。压缩当然会带来额外的 CPU 开销，但是有很多选项就可以权衡取舍。Btrfs 集成了文件系统和卷管理器功能，这意味着总体维护比 LVM-ext4 更简单。当然，这种集成的灵活性较低，但是对于大多数台式机甚至服务器而言，设置已足够。LVM 上使用 BtrfsBtrfs 可以 就地转换 ext3/ext4 文件系统。就地转换意味着无需将数据复制出来然后再复制回去。数据块本身甚至都不需要修改。因此，对于现有的 LVM-ext4 系统，一种选择是将 LVM 保留在原处，然后简单地将 ext4 转换为 Btrfs。虽然可行且受支持，但有一些原因使它不是最佳选择。Btrfs 的吸引力之一是与卷管理器集成的文件系统所带来的更轻松的管理。要是在 LVM 之上运行，对于系统维护，仍然要对额外的卷管理器进行一些设置。同样，LVM 设置通常具有多个固定大小的逻辑卷，并具有独立文件系统。虽然 Btrfs 支持给定的计算机上的多个卷，但是许多不错的功能都需要单一卷具有多个子卷。如果每个 LVM 卷都有一个独立的 Btrfs 卷，则用户仍然需要手动管理固定大小的 LVM 卷。虽然能够收缩挂载的 Btrfs 文件系统的能力确实使处理固定大小的卷的工作变得更轻松。通过在线收缩功能，就无需启动 实时镜像 了。在使用 Btrfs 的多设备支持时，必须仔细考虑逻辑卷的物理位置。对于 Btrfs 而言，每个逻辑卷都是一个单独的物理设备，如果实际情况并非如此，则某些数据可用性功能可能会做出错误的决定。例如，如果单个驱动器发生故障，对数据使用 RAID1 通常可以提供保护。如果实际逻辑卷在同一物理设备上，则没有冗余。如果强烈需要某些特定的 LVM 功能，例如原始块设备或高速缓存的逻辑卷，则在 LVM 之上运行 Btrfs 是有意义的。在这种配置下，Btrfs 仍然提供其大多数优点，例如校验和和易于发送的增量快照。尽管使用 LVM 会产生一些操作开销，但 Btrfs 的这种开销并不比任何其他文件系统大。总结当尝试在 Btrfs 和 LVM-ext4 之间进行选择时，没有一个正确的答案。每个用户都有独特的要求，并且同一用户可能拥有具有不同需求的不同系统。看一下每个配置的功能集，并确定是否有令人心动的功能。如果没有，坚持默认值没有错。选择这两种设置都有很好的理由。via: https://fedoramagazine.org/choose-between-btrfs-and-lvm-ext4/作者：Troy Curtis Jr 选题：lujun9972 译者：Chao-zhi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
快照 snapshot 是 Btrfs 的一个有趣的功能。快照是一个子卷的副本。生成快照是立即的。然而，生成快照与执行 rsync 或 cp 不同，快照并不是一创建就会占用空间。编者注：来自 BTRFS Wiki：快照简单的来说就是一个子卷，它使用 Btrfs 的 COW 功能与其他子卷共享其数据（和元数据）。占用的空间将随着原始子卷或快照本身（如果它是可写的）的数据变化而增加。子卷中已添加/修改的文件和已删除的文件仍然存在于快照中。这是一种方便的备份方式。使用快照进行备份快照驻留在子卷所在的同一磁盘上。你可以像浏览普通目录一样浏览它，并按照生成快照时的状态恢复文件的副本。顺便说一下，在快照子卷的同一磁盘上生成快照并不是一个理想的备份策略：如果硬盘坏了，快照也会丢失。快照的一个有趣的功能是可以将快照发送到另一个位置。快照可以被发送到外部硬盘或通过 SSH 发送到远程系统（目标文件系统也需要格式化为 Btrfs）。要实现这个，需要使用命令 btrfs send 和 btrfs receive。生成快照要使用 btrfs send 和 btrfs receive 命令，重要的是要将快照创建为只读，而快照默认是可写的。下面的命令将对 /home 子卷进行快照。请注意 -r 标志代表只读。sudo btrfs subvolume snapshot -r /home /.snapshots/home-day1 快照的名称可以是当前日期，而不是 day1，比如 home-$(date +%Y%m%d)。快照看起来像普通的子目录。你可以把它们放在任何你喜欢的地方。目录 /.snapshots 可能是一个不错的选择，以保持它们的整洁和避免混淆。编者注：快照不会对自己进行递归快照。如果你创建了一个子卷的快照，子卷所包含的每一个子卷或快照都会被映射到快照里面的一个同名的空目录。使用 btrfs send 进行备份在本例中，U 盘中的目标 Btrfs 卷被挂载为 /run/media/user/mydisk/bk。发送快照到目标卷的命令是：sudo btrfs send /.snapshots/home-day1 | sudo btrfs receive /run/media/user/mydisk/bk 这被称为初始启动，它相当于一个完整的备份。这个任务需要一些时间，取决于 /home 目录的大小。显然，后续的增量发送只需要更短的时间。增量备份快照的另一个有用的功能是能够以增量的方式执行发送任务。让我们再来生成一个快照。sudo btrfs subvolume snapshot -r /home /.snapshots/home-day2 为了执行增量发送任务，需要指定上一个快照作为基础，并且这个快照必须存在于源文件和目标文件中。请注意 -p 选项。sudo btrfs send -p /.snapshot/home-day1 /.snapshot/home-day2 | sudo btrfs receive /run/media/user/mydisk/bk 再来一次（一天之后）：sudo btrfs subvolume snapshot -r /home /.snapshots/home-day3 sudo btrfs send -p /.snapshot/home-day2 /.snapshot/home-day3 | sudo btrfs receive /run/media/user/mydisk/bk 清理操作完成后，你可以保留快照。但如果你每天都执行这些操作，你可能最终会有很多快照。这可能会导致混乱，并可能会在你的磁盘上使用大量的空间。因此，如果你认为你不再需要一些快照，删除它们是一个很好的建议。请记住，为了执行增量发送，你至少需要最后一个快照。这个快照必须存在于源文件和目标文件中。sudo btrfs subvolume delete /.snapshot/home-day1 sudo btrfs subvolume delete /.snapshot/home-day2 sudo btrfs subvolume delete /run/media/user/mydisk/bk/home-day1 sudo btrfs subvolume delete /run/media/user/mydisk/bk/home-day2 注意：第 3 天的快照被保存在源文件和目标文件中。这样，明天（第 4 天），你就可以执行新的增量 btrfs send。最后的建议是，如果 U 盘的空间很大，可以考虑在目标盘中保留多个快照，而在源盘中只保留最后一个快照。via: https://fedoramagazine.org/btrfs-snapshots-backup-incremental/作者：Alessio 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出