技巧和 / - 迁移到新硬盘
在本期 Linux Journal [第 84 页] 的另一篇文章中,我谈到了我在笔记本电脑上安装新的固态硬盘 (SSD) 的体验。我在文章中没有提到的一件事是如何将我的所有数据和设置传输到新硬盘。有很多方法可以解决这个问题。例如,您可以将旧硬盘镜像到新硬盘上,然后扩展最后一个分区以填满可能更大的磁盘(这对我不适用,因为我的新 SSD 实际上比旧硬盘小得多)。其他人只是每次获得新硬盘时都重新安装操作系统,然后传输他们的 /home 目录和其他设置,但我笔记本电脑上总是有足够的自定义程序和设置,以至于这种方法很麻烦。您也可以使用带有特定标志的 rsync 来迁移文件,虽然我确实喜欢这种方法用于网络传输,但对于本地传输,这可能很麻烦,因为它必须先扫描整个驱动器才能开始。
多年来,我使用 find 管道连接到 cpio 的久经考验的组合进行了多次硬盘迁移。我喜欢这种方法,因为它使用了肯定会安装的常用工具,它立即启动并且不需要扫描驱动器,并且使用正确的标志,它可以正确处理(并避免)特殊文件系统,例如 /proc、/sys 等等。到目前为止,它还没有让我失望,这次迁移也不例外。但是,这一次,我确实遇到了一些我稍后会谈到的陷阱。首先,介绍基本步骤。
您不希望在复制文件时文件被更改,因此您不希望从正常的桌面环境进行此迁移。通常,我启动到像 Knoppix 这样的救援磁盘,以便文件系统保持冻结状态。其他时候,我只是切换到单用户模式,这样大多数文件就不会更改。对于桌面系统,我通常只是将两个驱动器直接连接到系统,对于笔记本电脑,我使用 USB 硬盘适配器,以便可以同时连接两个驱动器。对于我的上次迁移,我碰巧没有 1.8 英寸驱动器的 USB 适配器,所以我首先将数据传输到中间驱动器,然后安装新驱动器并再次传输。
您可以使用任何适合您的分区工具——从 fdisk 到 qtparted。这听起来可能很明显,但请确保您分配了足够的空间来容纳您现有的数据,如果您移动到更大的硬盘,则需要足够的空间来增长。分区驱动器后,使用 mkfs 或您首选的格式化工具将文件系统写入每个分区(或为交换分区使用 mkswap)。
在 /mnt 下为您创建的新分区创建挂载点。对于我的示例,我在 /dev/sdb1 上有一个根分区,在 /dev/sdb3 上有一个 home 分区,所以我将以 root 身份键入
mkdir /mnt/sdb1 mkdir /mnt/sdb3 mount /dev/sdb1 /mnt/sdb1 mount /dev/sdb3 /mnt/sdb3
如果您从救援磁盘运行此命令,您还需要确保也挂载了源分区。
现在这个法术没有太多内容,但有趣的是,在使用多年并将其传递给朋友后,您如何记住这样的脚本。首先,切换到要复制的分区的根级别,然后以 root 身份执行命令。因此,要从单用户模式迁移我的根分区,我执行了以下操作
cd / find ./ -xdev -print0 | cpio -pa0V /mnt/sdb1
要从救援磁盘迁移,命令几乎相同,但您需要更改为源分区的挂载点(我将其挂载在 /dev/sda1)
cd /mnt/sda1 find ./ -xdev -print0 | cpio -pa0V /mnt/sdb1
find 命令搜索整个根分区中的文件和目录。 -xdev 标志告诉 find 停留在当前挂载的文件系统内。否则,当 find 到达 /home 时,它也会复制该目录的内容,并可能填满新分区。然后,它将文件传递给 cpio,cpio 将它们放置在我的新挂载点下,同时保留权限、符号链接和其他设置。 cpio 命令还会为它复制的每个文件输出一个点,因此您可以对它的进度有所了解。但是,我通常做的是转到另一个终端并监视 df 的输出,以便我可以观察它的增长
watch df
一旦第一个 find | cpio 命令完成,为您的每个其他分区重复它。在我的示例中,如果我处于单用户模式,我会执行以下操作
cd /home find ./ -xdev -print0 | cpio -pa0V /mnt/sdb3
如果我正在使用救援磁盘,我会这样做
cd /mnt/sda3 find ./ -xdev -print0 | cpio -pa0V /mnt/sdb3
您在此步骤中执行的操作会略有不同,具体取决于您设置分区的方式。如果您移动了分区布局,则需要编辑新根分区上的 /etc/fstab 文件,以便它反映您设置的新驱动器。
传统上,这对我来说是一个简单的步骤,因为我尝试以相同的顺序排列分区,并且通常不必触及 fstab,但在上次迁移中,由于 Ubuntu 使用 UUID 来引用分区,我不得不添加一个额外的步骤。许多现代发行版不按设备名称引用分区。相反,为每个分区分配一个称为 UUID 的唯一标识符。如果您在 /etc/fstab 中看到 UUID=longstringofhex,则表示您是这种情况。
现在,您有两个选择。第一个选择是将所有这些 UUID 行更改为引用实际设备。这将有效,并且不太容易出现会导致系统无法启动的拼写错误,但您将失去 UUID 的优势。另一种方法是引用新分区的 UUID,并将它们放在旧 UUID 的位置。您可以在 /dev/disk/by-uuid 下找到磁盘到 UUID 映射的列表
greenfly@minimus:~$ ls -l /dev/disk/by-uuid/ total 0 lrwxrwxrwx 1 root root 10 2008-04-06 16:00 ↪634719fd-a6da-4fee-8646-0d485d7681db -> ../../sda2 lrwxrwxrwx 1 root root 10 2008-04-06 16:00 ↪665d7008-fde9-4055-8af9-483697acb005 -> ../../sda1 lrwxrwxrwx 1 root root 10 2008-04-06 16:00 ↪cf3892fd-e3d8-446f-8552-4c633be9c382 -> ../../sda3
当然,您始终可以选择两种方法的混合,并在 fstab 中为首次启动设置硬盘设备名称,然后在您确认系统启动后,您可以更新带有 UUID 的 fstab。
与 fstab 一样,如果您更改了分区布局,则需要更新 /boot/grub/menu.lst(或在某些系统上,在 /boot/grub/grub.conf 中)下的 GRUB 配置以反映您的更改。此外,GRUB 可以通过 UUID 引用驱动器,因此如果您在 GRUB 配置文件中看到对 UUID 的引用,请务必更新它以反映新值。更新文件后,chroot 进入新根分区的挂载点,然后运行 grub-install
chroot /mnt/sdb1 /usr/sbin/grub-install --recheck /dev/sdb
更改 /mnt/sdb1 和 /dev/sdb 以分别反映您的新挂载的根分区及其磁盘设备。如果 chrooted grub-install 不起作用,您通常可以使用带有 --root-directory 选项的救援磁盘(或单用户)grub-install
/usr/sbin/grub-install --recheck --root-directory /mnt/sdb1 /dev/sdb
在使用我的新系统一段时间后,我注意到它无法从休眠状态正确恢复。似乎每次交换分区都会损坏。经过一些故障排除后,我发现根本原因是基于 UUID 的硬编码恢复设备,该设备放在机器的初始 ramdisk 中。您可能会也可能不会遇到此问题,具体取决于您的 Linux 发行版,因为每个发行版管理其 initrd 的方式都不同。但是,这是我的 Ubuntu 系统的修复方法。我能够在 /etc/initramfs-tools/conf.d/resume 中找到对旧 UUID 的违规引用。我所需要做的就是更新新驱动器上的该文件以指向我的交换分区的新 UUID,然后从新系统运行 update-initramfs,然后重新启动。
Kyle Rankin 是旧金山湾区的高级系统管理员,也是包括 O'Reilly Media 出版的 Knoppix Hacks 和 Ubuntu Hacks 在内的多本书籍的作者。他目前是 North Bay Linux Users' Group 的主席。