使用 btrfs send/receive 将长期运行的 Arch 系统无损迁移到新硬件

💡 原文英文,约1500词,阅读约需6分钟。
📝

内容提要

本文介绍用 btrfs send/receive 无损迁移 Arch 系统到新硬盘,相比 rsync 可保留子卷结构、校验和与压缩。流程为:清理缓存垃圾,对每个子卷做只读快照,逐个发送接收并提升为可写子卷,替换 fstab、grub 等处的 UUID,处理 ESP 并注册启动项。全程在线,仅最后重启切换;跨硬件还需更换微码、显卡驱动并注意启动模式。

🔎

延伸解读

为何选择 btrfs send/receive 而非 rsync

rsync 虽然能复制文件,但无法保留 btrfs 的子卷结构、校验和与压缩属性。文章指出,rsync 会将子卷变成普通目录,丢失边界;而 send/receive 以文件系统指令流传输,数据落地即完整,无需事后校验,且保留 compress-force=zstd 等挂载选项的语义,避免解压再压缩的开销。对于依赖子卷布局的系统,这是关键差异。

迁移前的清理与在线操作要点

快照会完整传输子卷内容,因此清理垃圾能显著减少传输量。文章建议清理 pacman 缓存、AUR 构建缓存(如 ~/.cache/yay)、孤儿包、系统日志和用户缓存。整个迁移过程在线进行:只读快照瞬间完成,系统持续运行,send/receive 耗时不影响使用;仅最后重启切换磁盘。快照后旧盘的新写入(如日志)会被有意舍弃,对家用机可接受。

UUID 替换与启动项处理

新分区 UUID 变化,需用 blkid 查询并替换四处配置:/etc/fstab、timeshift.json、grub.cfg 和 grub-btrfs.cfg。这是最易出错的环节。随后挂载 ESP 并用 efibootmgr 注册启动项。作者建议下次改用 genfstab -U 和 chroot 下 grub-mkconfig 重新生成配置,避免手改被后续升级覆盖。

跨硬件迁移的额外考量

若迁移到不同硬件,还需处理 CPU 厂商变化(更换 intel-ucode/amd-ucode)、GPU 驱动更换,以及目标机 UEFI 设置差异(CSM、Secure Boot),必要时新建 ESP 并重新注册启动项。文章还提醒 btrfs 快照非递归,嵌套子卷在快照中显示为空目录,需单独处理;并推荐使用 btrfs send --proto 2 --compressed-data 直接传输压缩块以节省时间。

❓

Q&A

为什么迁移 Arch 系统时推荐用 btrfs send/receive 而不是 rsync?

rsync 无法保留 btrfs 的三个关键特性:子卷结构(rsync 后子卷变成普通目录)、数据校验和(send/receive 传输文件系统指令,数据落地即可信,无需事后比对)、压缩(send/receive 保留文件系统语义,不会像 rsync 那样解压再压缩)。此外,只读快照是写时复制,几乎瞬间完成,系统可继续运行,实现在线迁移。

用 btrfs send/receive 迁移前,为什么要先清理系统垃圾?具体清理哪些?

因为快照会完整发送整个子卷,垃圾也会被传过去,导致传输更慢、目标盘更拥挤。建议清理:包缓存(pacman -Sc 及 AUR 助手构建缓存如 ~/.cache/yay)、孤儿包(pacman -Rns $(pacman -Qtdq))、系统日志(journalctl --vacuum-size=100M)、用户缓存(~/.cache 下的浏览器缓存等)和回收站。清理后再快照,传输量会明显减少。

btrfs send/receive 迁移的完整步骤是什么?

步骤:1. 挂载源和目标(使用 compress-force=zstd,noatime,ssd,space_cache=v2);2. 对每个子卷创建只读快照;3. 逐个 send 并 receive 到目标;4. 将接收到的只读快照提升为可写子卷(并删除 _ro 中间快照);5. 替换 UUID(涉及 /etc/fstab、/etc/timeshift/timeshift.json、/boot/grub/grub.cfg、/boot/grub/grub-btrfs.cfg);6. 挂载 ESP 并注册启动项(efibootmgr);7. sync、卸载、重启进入新盘。

迁移过程中需要替换哪些地方的 UUID?

需要替换 UUID 的四个地方:/etc/fstab(挂载表)、/etc/timeshift/timeshift.json(快照工具)、/boot/grub/grub.cfg(启动配置)、/boot/grub/grub-btrfs.cfg(btrfs 快照启动菜单)。新分区有新的 UUID,用 blkid 查询后,用 sed 替换旧 UUID。

迁移到不同硬件时需要注意哪些额外问题?

跨硬件迁移需注意:CPU 厂商变更(Intel↔AMD)要更换微码包(intel-ucode/amd-ucode);GPU 厂商变更要更换显卡驱动;目标机器的 UEFI 设置可能不同(CSM 关闭、Secure Boot 状态),必要时创建新 ESP 并重新注册启动项。

btrfs send/receive 迁移过程中系统需要停机吗?

不需要。快照瞬间完成,系统继续正常运行;send/receive 耗时多久都不影响;fstab 和 grub 的修改是在目标盘的副本上进行的,与运行中的系统无关。唯一的停机是最后重启进入新盘,而换盘本来就需要重启,所以不算迁移成本。快照后旧盘上的少量写入(如新日志)会被有意留下,对家用机无影响。

btrfs 快照是递归的吗?嵌套子卷如何处理?

btrfs 快照不是递归的。嵌套子卷在快照中会显示为空目录。如果子卷嵌套在 @home 内,需要在 send 之前单独处理。文章中的五个子卷都是顶层兄弟,所以没有这个问题。

作者计划下次迁移时做哪些改进?

两个改进:1. 重新生成 fstab 和 grub 配置,而不是手动 sed 替换。使用 genfstab -U /mnt 生成挂载表,并在目标系统的 chroot 中运行 grub-mkconfig -o /boot/grub/grub.cfg,避免手动编辑的 grub.cfg 被未来 grub 升级覆盖。2. 使用 btrfs send --proto 2 --compressed-data(需要 btrfs-progs 6.0+ 和内核 6.0+),直接传输 zstd 压缩块,避免解压再压缩,节省跨机传输时间。

🏷️

标签

➡️

继续阅读