# 起因
这些天固态硬盘价格疯狂跳水,碰巧我的笔记本储存空间又到了临界值;抵不住诱惑的我终于以不到 400 的价格拿下铠侠 rc20。而我的笔记本又是尴尬的单硬盘位,于是连忙购入硬盘盒开始全盘迁移。
# 简单的情况陈述
我的情况可能比较特殊:Windows 和 ArchLinux 的双系统,其中 arch 更采用了 btrfs 的文件系统,全部储存在一个硬盘当中。虽然不知道 btrfs 的迁移是否相比传统的 ext4 更加简单,但我这次却因为 btrfs 吃尽苦头。这自然不是 btrfs 的原因,归根到底还是因为我对其并不熟悉(没错我就是小白~哼哒)。虽说如此,我在查阅资料的过程中也确实发现,关于btrfs迁移的教程少得可怜,而我也果然在此过程中踩了无数个坑;为了使有需要对btrfs迁移的读者有资料可以参照,也是写这篇文章的动因之一。
# 正戏开演
要对双系统进行全盘迁移,首先有一点是明确的——那就是需要对每个系统进行单独迁移。虽然迁移的顺序无关紧要,但我仍然建议你先迁移 win,以防止 efi 分区的覆盖。
# Windows 系统迁移
Win 的系统迁移可以说是很简单了。打开图吧工具箱,找到 diskgenuis;或者进入官网下载。选定硬盘和分区大小进行迁移就好。
迁移完毕,这时可以看到分区:恢复分区、EFI、C盘、D盘……嗯……确认无误后让我们进入下一步骤(当然下面才是我真正想写的东西)。
# Linux(btrfs)系统迁移
# 查看硬盘信息
sudo fdisk -l
能够清楚查看到所有硬盘的信息。
Disk /dev/nvme0n1: 931.51 GiB, 1000204886016 bytes, 1953525168 sectors
Disk model: KIOXIA-EXCERIA G2 SSD
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 89D3EDE7-1394-43CA-B6E7-4B3FF7916E9C
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 20973567 20971520 10G Linux swap
/dev/nvme0n1p2 20973568 986714111 965740544 460.5G Linux files
/dev/nvme0n1p3 986714112 987762687 1048576 512M EFI System
/dev/nvme0n1p4 987762688 987795455 32768 16M Microsoft r
/dev/nvme0n1p5 987795456 1302368255 314572800 150G Microsoft b
/dev/nvme0n1p6 1302368256 1951477167 649108912 309.5G Microsoft b
/dev/nvme0n1p7 1951477760 1953525134 2047375 999.7M Windows rec
这里出于演示,只展示了一个硬盘(
因为我只连了一个硬盘)。需要格外注意硬盘的标识,以免出现不小心把需要迁移的硬盘给格了的惨况。
# 分区
我所采用的分区方式参照 archlinux 简明指南 ,采取了上面所展示的分区方式。也就是说,分了内存的 60% 给 swap,其余全部分给根目录。分区操作使用 sudo cfdisk /dev/nvme0n1p2
。
为使示范代码更具体,下文将以上面的分区信息为例。你所需要关注的只有 swap、Linux File 以及 EFI 所在的卷,此处分别为 /dev/nvme0n1p1,/dev/nvme0n1p2 和 /dev/nvme0n1p3。以下命令若无权限请自行添加 sudo 或在 root 下运行。
分别选择新加卷的大小和类型,同样在进行仔细检查后用 [Write] 确认写入并 [Quit] 退出。
# 格式化分区
# 格式化 swap 分区
mkswap /dev/nvme0n1p1
# 格式化 btrfs 分区
mkfs.btrfs -L iArch /dev/nvme0n1p2
其中,-L 可指定你所喜欢的分区标签。
# 创建子卷
# 首先挂载btrfs分区
mount -t btrfs -o compress=zstd /dev/nvme0n1p2 /mnt
# 然后创建子卷
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
# 最后卸载/mnt以进行下一步操作
umount /mnt
# 同步
为了无损迁移数据,使用 rsync
同步数据。
# 挂载分区
mount /dev/nvme0n1p2 /mnt
此处不能使用 btrfs 的挂载方式,否则无法显示子卷。btrfs 文件系统需要分别同步子卷,否则就会出现文件被隐藏的情况(我在迁移过程中所遇到的最大的坑!都是血泪)。
# 同步 @ 子卷
rsync -aAXv /* /mnt/@ --exclude={"/home/*","/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/boot"}
# 同步 @home 子卷
rsync -aAxv /home/* /mnt/@home
# 卸载
mount /mnt
# 挂载
# 挂载 / 目录
mount -t btrfs -o subvol=/@,compress=zstd /dev/nvme0n1p2 /mnt
# 挂载 /home 目录
mount -t btrfs -o subbol=/@home,compress=zstd /dev/nvme0n1p2 /mnt/home
# 挂载 efi 目录
mount /dev/nvme0n1p3 /mnt/boot/efi
# 挂载 swap 分区
swapon /dev/nvme0n1p1
# 挂载完毕后,生成 fstab 文件
genfstab -U /mnt > /mnt/etc/fstab
# 卸载
umount -R /mnt
# 重建引导
重建引导其实可以参考我的另一篇文章 Grub引导恢复历险 ,对那些不想跳转到另一篇文章的读者,我在下面简要列出了关键步骤。
其实只是把那篇文章的命令抄过来……
# 挂载根目录
mount -t btrfs -o subvol=/@,compress=zstd /dev/nvme0n1p2 /mnt
# 挂载家目录
mount -t btrfs -o subvol=/@home,compress=zstd /dev/nvme0n1p2 /mnt/home
# 挂载 efi 目录
mount /dev/nvme0n1p1 /mnt/boot/efi
# 切换系统环境
arch-chroot /mnt
# (重新)安装相关的包
pacman -S grub efibootmgr os-prober
# 安装 GRUB 到 EFI 分区
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ARCH
# 生成 grub 配置文件
grub-mkconfig -o /boot/grub/grub.cfg
exit # 退出
umount -R /mnt #卸载分区
reboot #重启
# 若无Windows引导,在进入系统后……
sudo grub-mkconfig -o /boot/grub/grub.cfg
# 小结
至此全部工作告一段落。Linux 能够使用 rsync 进行迁移的根本原因在于 Unix “一切皆文件” 的理念;虽说如此,Linux 的正确迁移需要对其文件系统的结构有一个全局性的认识,相比 Windows 借助第三方工具进行一键迁移确实略显复杂。但是,正是通过这种复杂我们才能从中学到有价值的东西;Windows 那种黑盒一般的迁移方式除了让人感到方便,又能让人从中学到什么呢?
不过果然在学习面前,这种时候方便才是更重要的!