如何制作完整副本btrfs 文件系统的内容?完整副本我的意思是当前数据,但也不同子卷和他们的快照,理想情况下保留它们的 CoW 结构(即:不重复具有相同内容的块。
似乎块级复制(例如dd
)不是一个好主意,因为它重复了 UUID,并且没有办法轻易改变它, 显然。
答案1
选项 1 - 哑数据复制然后更改 UUID
确保源分区已卸载并且不会自动安装。
使用dd
(缓慢,愚蠢)或partclone.btrfs -b -s /dev/src -o /dev/target
用于btrfstune -u
在复制之后和挂载之前更改 UUID。
数据丢失警告:做不是尝试(自动)挂载任何一个原件或副本,直到 UUID 发生变化
选项 2 -btrfs-clone
我没有亲自尝试过btrfs-clone
,但它声称将现有的 BTRFS 文件系统克隆到新的文件系统,并按顺序克隆每个子卷。
答案2
截至今天(2016-05-06),我还没有找到任何现成的解决方案,但解决了我的目的问题,包括写时复制处理。“克隆”的步骤/source
如下/target
:
获取按以下顺序排序的子卷列表
ogen
:btrfs subvolume list -qu --sort ogen /source
。排序可能足以保证首先处理依赖于先前快照或子卷的快照或子卷。这对于处理写时复制很重要,因为我们需要首先传输基本卷。使用 使所有子卷变为只读
btrfs property set -ts /source/some-volume ro true
。现在,对于上面列表中的每个子卷,从顶部开始执行以下操作:
如果卷没有父 UUID(显示为
-
)或者列表中不再存在父 UUID,请运行:btrfs send /source/some/volume | btrfs receive /target/some/
如果卷确实有一个仍然存在的父 UUID,那么我们应该已经将其转移,因为
--sort ogen
我们可以将其用作避免数据重复的基础。因此,在列表中找到父 UUID 的路径并运行:btrfs send -p /source/parent/volume/ -c /source/parent/volume/ /source/some/volume/ | btrfs receive /target/some/
(btrfs 可能会-p
自动猜测参数,但我更喜欢明确说明)。运行上述命令之一后,使目标和源再次变为读写状态:
btrfs property set -ts /source/some/volume ro false; btrfs property set -ts /target/some/volume ro false
。如果源之前是只读的,则可以跳过此步骤。
这应该可以处理很多情况。注意事项:
嵌套子卷/快照时,排序方面可能会出现一些复杂情况。
整个过程如果有脚本的话显然会更有趣。
btrfs send
接受多个克隆源 (-c
) 参数。不仅指定父级卷路径,还指定任何祖先或任何先前发送的卷路径可能会很有利。这里没有任何区别,但它可能 — — 只是猜测 — — 在某些情况下有助于避免数据重复。我不确定快照或子卷上的元信息是否会在此过程中丢失,但对于大多数用例来说,其他所有有趣的东西都应该保留。
整个过程帮助我将一个 800 GB 的文件系统(使用 3.8 GB,根据df
)转移到一个 10 GB 的映像(使用 3.8 GB)。如果没有 和-p
,则传输-c
将使用大约 190 GB,因此确实避免了数据重复。
答案3
我已经创建了一个python 工具它可以做到这一点。我这样做是因为我在我自己的实现和@Johannes Ernst的实现中都尝试了@Thomas Luzat的方法,并且在克隆过程中使用的空间从20GB增加了一倍到40GB。我认为需要一些更有效的方法。
考虑这个常见的文件系统历史:
current ---------------------------------\
| | | |
snap4 snap3 snap2 snap1
根据 Thomas 的算法,将首先克隆“当前”,并且所有快照(即“当前”之前状态的快照)将使用“当前”作为克隆源/父级。显然,最好将 snap3 基于 snap4,将 snap2 基于 snap3,等等。
这只是冰山一角;在具有复杂历史的 btrfs 文件系统中寻找“最佳”克隆源(就节省空间而言)并非易事。我想出了另外 3 种解决此问题的策略,这些策略似乎可以更有效地利用空间。其中一种方法实际上导致克隆的大小略低于源的大小。
您可以在github 页面如果你有兴趣的话。
答案4
我上次看到的btrfs-send
仍然是在 btrfs 邮件列表中流传的实验性补丁。