Linux 环境下硬盘数据的迁移
之前一直在用的老 SSD 只有 128GB,上边装了 Ubuntu 作为宿主 OS,另外常备一个 Windows7 的虚拟机,时常面临空间不够的问题,一般是用 Vmware 中 Hard Disk 的Compact Disk功能来挤出一些空间来,但是这样频繁的硬盘读写对硬盘寿命多少有些影响。
后来换新机时自带的 SSD 是 256GB 的,当时出于方便不想重装环境就用老的 SSD 替换了下来,现在抽出一块时间把数据都转移到新硬盘上,尽量不影响平时的工作。
操作
1. 装硬盘
将新硬盘插到笔记本的硬盘位,如果有第二个硬盘位或光驱位(可以改装成硬盘位)可以直接放旧硬盘,如果像我的 T470P 一样第二硬盘位不支持 SATA 接口的情况,就得上淘宝买个 USB-SATA 适配器了。
如果新硬盘上有重要数据必须备份,比如保存到一块足够大的机械硬盘上,老硬盘最好也备份一下(我因为偷懒略过了这一步)。
2. 查询硬盘的分区号
1 | fdisk -l |
老硬盘有一个 boot 分区和挂载到/
的主分区,为了保持同样,需要对新硬盘进行格式化和分区,分成一个 boot 分区和一个主分区,参考这篇经验。
3. 拷贝分区
假设新硬盘的主分区是/dev/sda2,旧硬盘的主分区是/dev/sdb2,那么使用下面命令拷贝数据:
1 | sudo dd if=/dev/sdb2 of=/dev/sda2 |
硬盘内容是非常大的,而 dd 命令不会展示中间过程,非常不方便。
其实 dd 命令默认不会展示进度,只会在接收到 SIGUSR1 消息后才会打印出自己当前的进度,可以使用 kill 系的命令向 dd 进程发送消息来查看:
1 | watch -n 5 pkill -USR1 ^dd$ |
注意 dd 命令也会拷贝 uuid 过去,uuid 是一个唯一的标识符,因为类似/dev/sda 这样的映射点,在新设备加入的时候,可能会生成新的映射点,比如原来系统里是/dev/sda 现在变成了/dev/sdb 等等,所以一般情况下,在/etc/fstab 里写自己规则的时候,都是用 uuid 而非映射点。
可以不修改新硬盘分区的 uuid,也就省去了修改/etc/fstab 或者/boot/grub/grub.conf 的麻烦。
4. 拷贝 boot 分区
作为实验,我拷贝 boot 分区的时候使用的是 cp 命令,相对 dd 命令来说,cp 不会原封不动地拷贝过来,而是哪里有空间就分到哪里,而且不会将 UUID 一并拷贝过去,需要手动设置。
5. 更新硬盘信息
1 | # 操作前先卸载分区 |
e2fsck 可以检查文件系统的完整性,并且可以修复一些错误。执行 e2fsck 或 fsck 之前必须先 umount partition,否则有可能导致文件系统系统损坏。
1 | # 检查`/dev/sda1`是否存在问题,如果发现问题就自动修复 |
resize2fs 可以调整 ext2/ext3/ext4 文件系统的大小(扩展或缩小),可以指定一个 size 属性,如果不指定则认为需要扩展到该分区的大小。
6. 修改 uuid
如果想修改 uuid,比较简单的办法是打开gparted
,在分区上右键,生成新的 uuid。
同时还要修改/etc/fstab
中的内容,替换掉原来的 uuid
当然也可以通过命令修改 UUID,首先是查看分区的 UUID:
1 | ls -l /dev/disk/by-uuid |
uuidgen 会返回一个合法的 uuid,结合 tune2fs 可以新生成一个 uuid 并写入 ext2,3,4 的分区中:
比如新建或改变 sda5 的 uuid (需要 root 权限)
1 | uuidgen | xargs tune2fs /dev/sda5 -U |
也可以把 fstab 里找到的原 uuid 写回分区:
1 | tune2fs -U c1b9d5a2-f162-11cf-9ece-0020afc76f16 /dev/sda5 |
7. 为 boot 分区添加 boot 标记
最后,可以在 gparted 界面上右键分区设置标记,选中 boot,表明这个分区是有启动点的。
8. 修复 grub
更新 grubupdate-grub2
。
如果重启后,进入系统有问题,但是可以进入 grub rescue,自己又不知道到底问题出哪里的话,简单的办法是使用 boot-repair 这个工具。
1 | sudo add-apt-repository ppa:yannubuntu/boot-repair |
然后打开 bootrepair 进行一键修复即可。
我的在运行前,询问我/dev/sda 是可移动硬盘吗,当然不是。。在认为他的自动处理能力有问题以后,我点开了高级设置,手动选择了正确的 grub 位置(/dev/sda
),然后等待修复完成,大概不到 10mins。
完成后重启即可进入系统。
拓展
注意文件系统中的软/硬链接
对/home
迁移时,拷贝时不是直接 cp 的,因为/home 目录下存在很多软链接、硬链接、文件、嵌套的文件夹等,所以使用了下面的命令来拷贝:
1 | $ find . -depth -print0 | cpio --null --sparse -pvd /mnt/newhome/ |
QA
- 拷贝 boot 分区为什么用 cp 而不是 dd 命令? cp 是对文件(字节方式)操作的,dd 是对块(扇区方式)进行操作的。
1
2
3# bs每次複製的塊大小
# count要複製的次數
dd if=/dev/hda of=/dev/hdc bs=4 count=1024
dd 将原始数据(raw data)按照数据源的格式原封不动地拷贝到目的地。cp 将文件和目录拷贝到目的地后按照目的地的格式排列新数据。cp 将一个硬盘的数据复制到第二个硬盘上,由于系统写硬盘不是顺序写的,哪里有足够的空间就放到哪,所以第二个硬盘相同扇区号上的数据和第一块硬盘有可能是不同的。
注意:对于不能以文件或目录格式呈现的数据(如引导启动块的数据),cp 无能为力。
似乎 dd 相对 cp 来说更合适,因为 cp 在拷贝完后还得再设置 UUID、flags,为什么还用 cp?实际上是因为以前装系统的时候没把 boot 分区和 home 分区分开来,现在没法用 dd 一个分区一个分区拷贝,这一点在上边也已经说过了。 - boot 分区的标记有什么作用?
在 gparted 中可以为 boot 分区设置 boot 标记,表明这个分区是有启动点的。(暂时没有找到关于 EFI 更深入的资料,只能这么理解了)