如何克隆树莓派系统到较小的硬盘/SD卡上(如何分区、设置修复引导)

最近有个老固态硬盘空下来了,虽然写入速度没那么快,但是足够满足千兆网络了,所以我就想把现在给树莓派使用的固态硬盘换下来。由于一些设置很浪费时间,所以我不打算重装系统。此外这个老固态是 120GB 的,要小于正在使用的固态硬盘(512GB),所以一些常见的复制硬盘的方法就不能使用了。

本文只需要使用树莓派,但是我是使用 SSH 访问树莓派的,所以截图会是 macOS 的样式。

在写完文章后,我自己又照着重新弄了一遍,确定没啥问题,但还是建议读者先对重要文件进行备份,以防万一。

本文有点长,操作也有些繁琐,所以我将其编写成一个脚本工具了,方便使用:https://github.com/ZhongUncle/clone_rasp_disk

注意事项

由于我需要反复验证这个流程的正确性,所以对硬盘操作了多次。这时候遇到了一个问题:由于格式化并不会清除很多已经存在文件,这就导致可能有些文件并不会被rysnc正确同步,这可能会导致启动出现问题。所以要么对硬盘开头大约 5GB (启动区+一些系统目录的位置,由于你安装和设置的不同大小需要自己进行修改)进行“0”覆盖(使用dd),或者对硬盘进行全盘抹除(这样比较花费时间,但是能保证不出现问题)。

为什么不使用dd或SD card copier

本文不会使用 CLI 程序dd或 GUI 应用程序 SD card copier。

不使用dd因为这些程序复制的时候,是把整个盘复制了,这就导致写入肯定会失败(目标盘小于目的盘)。而且速度很慢,就算尽量减少传输经过的控制器数量和提高传输接口,但是从固态写固态也就是 30~45MB/s(不优化的话就 15~20MB/s)。

但是SD card copier 没有这个问题。不使用 SD card copier 是因为我还要插 HDMI 的线,而且不适合平时备份等操作,所以想研究一下使用 CLI 的方式。如果你能使用桌面模式,那么推荐直接使用 SD card copier 应用程序。而且这种方法要快很多,速度能稳定在 50~70MB/s。

原理

本文的方法和 SD card copier 原理是一样的:先在目标硬盘上分两个区,启动区(名称为bootfs,格式为 Windows_FAT_32)和使用区(也被称为根区名称为rootfs,格式为 Linux),然后使用rsync复制,这样速度也快很多。

如果在树莓派上使用lsblk -f(这里只是为了演示,后面会介绍一个信息更详细的工具)查看硬盘的结构和文件系统可以看到:

请添加图片描述

如果你好奇树莓派的启动分区bootfs为啥不使用 ext4 文件系统,这是因为要求最小为 16 GiB,但是启动区占这么大有点离谱了。此外,使用 FAT32 这种在 Windows、Linux、macOS 上都可以读取的文件系统,也方便更改一些设置(树莓派可以通过修改启动区bootfs中的文件来修改一些配置的,比如 HDMI 级别等)。

由于启动需要,我们需要分区是按照“启动区-使用区”的顺序存在于硬盘上。所以我们需要先格式化出启动区,再将剩余部分格式化为使用区。

第一步:分区和新建文件系统

首先将两个盘连到树莓派上,记得将目标硬盘格式化成 Linux 可以识别的文件系统(Mac 上可以使用磁盘工具格式化为 exFAT,或者使用 Raspberry Pi Imager 将其格式化成 FAT32)。

接下来使用parted工具进行分区,倒不是因为可以进行交互操作,主要是可以显示更详细的分区信息,而且设置一些参数也更方便。

首先使用sudo parted -l命令当前连接的硬盘信息:

请添加图片描述

第一部分是系统盘,我们可以看到其中的每个分区的大小、起始地址、终止地址、文件系统等等信息。第二部分是我们的目标硬盘。

然后我们使用下面的命令在目标硬盘生成相似分区结构:

sudo parted /dev/sdb --script 'mklabel msdos mkpart primary fat32 4194.5kB 541MB mkpart primary ext4 541MB 120GB print quit'
  • /dev/sdb是目标盘的设备名称。不要使用/dev/sdb1,这是已存在的分区名称。
  • 使用--script则不会进入交互模式,这样一条命令即可完成操作。需要注意官方没有使用这个选项,但是如果按照上面的内容,不使用该选项,直接尾接后面的命令,那么会摧毁整个硬盘的分区(会有提示)。
  • mklabel msdos设置分区模式为 MBR 格式。这里不使用gpt是因为系统上就是msdos(从上图的Partition Table可以看到这个信息)。
  • mkpart primary fat32 4194.5kB 541MB 这部分是划分启动区的命令,primary表示是独立分区(或者称为“主分区”,对应的是“扩展分区”)。使用fat32文件系统,起始地址使用4194.5kB,因为树莓派启动是从第 8192 块开始的,但是parted显示的数值是有误差的,以sudo fdisk -l的显示内容为准。终止地址和系统盘的终止地址一样就行。
  • mkpart primary ext4 541MB 120GB这部分是划分根区的命令,使用ext4文件系统,起始地址就是启动区的终止地址,但是终止地址是硬盘的大小,也就是和最开始图中显示的终止地址一样。
  • print会打印出分区信息。
  • exit会退出parted

需要注意个命令不能拆成两个,因为退出后再使用mkpart会抹除原有分区,这样最后还是生成一个分区。

显示如下:

请添加图片描述

这时工作还未全部完成,我们需要手动给两个分区手动创建一下FAT32ext4文件系统,如下:

sudo mkfs.vfat -F 32 /dev/sdb1
sudo mkfs.ext4 -L rootfs /dev/sdb2

如果不进行这一步,那么会出现一些很奇怪的问题。前面分区的信息中,正确显示了我们是创建了一个供ext4使用的分区,编号为2。但是如果你用sudo parted -l查看一下,会发现如下情况,File system一栏中,第二个分区没有任何信息:

请添加图片描述

这时候加载这个分区发现会提醒以下错误信息:

$ sudo mount /dev/sdb2 /mnt/rootfs/
mount: /mnt/rootfs: wrong fs type, bad option, bad superblock on /dev/sdb2, missing codepage or helper program, or other error.
       dmesg(1) may have more information after failed mount system call.
mount: (hint) your fstab has been modified, but systemd still uses
       the old version; use 'systemctl daemon-reload' to reload.

所以手动创建。

第二部:使用rsync进行复制

在使用rsync进行复制之前,需要将两个分区加载一下。

首先是在/mnt/目录下新建一个目录,用来装载根分区:

sudo mkdir /mnt/rootfs 

然后装载根分区:

sudo mount /dev/sdb2 /mnt/rootfs/

那么从哪复制(同步)到哪呢?还记得文章第一张图中的内容吗?显示了系统盘上两个分区对应的目录:/boot/firmware(启动分区)和/(根分区)。

首先是启动分区:

sudo rsync -axHAWXS --numeric-ids --info=progress2 --exclude={"/mnt/","/boot/firmware/"} /* /mnt/rootfs

这里的选项意思如下:

  • a是存档模式,这会递归读取目录,不破坏符号链接、权限等信息。
  • x表示不会跨越文件系统的边界。
  • H保留硬连接。
  • A保留ACL(访问控制表)。
  • W禁用网络传输使用的增量算法。由于这里是都是本地路径,所以可以提高速度。
  • S 可以有效地处理稀疏文件,这样传输完占用的空间更少。(不用这个的话,所有源文件可能 8GB,但是目的文件总和可能有 10GB)
  • numeric-ids使用数字 ID,而不是映射。
  • info=progress2会显示传输进度和信息,而且是整个传输的进度和信息,而不是每个文件的统计信息。
  • 有几个目录不需要复制,因为是重复的,所以要使用--exclude=来排除它们。在很多关于系统克隆的文章中,列出了其他可以忽略的目录/dev/sys/proc,但是在我花了两个小时抢救之后,可以确定像/dev/sys/proc这些都是不能忽略的,(关于如何抢救如果写了一篇博客我会在这里列出链接)

这里解释一下排除的两个目录。

  • 第一个/mnt/是避免重复复制,因为这里就是复制的目的地。不然会复制两次甚至更多次。
  • 最后一个/boot/firmware/是因为这部分内容是启动的内容,我们后面单独复制(一起复制可能会跳过这部分)。

在复制/sys/目录下的部分文件会提示一堆错误。这些错误不用管,因为不能读取(显示没权限)或者是虚拟文件。详细内容可以看看这个帖子:Why does rsync fail to copy files from /sys in Linux? - Unix & Linux stackexchange

由于前面排除了一些目录,所以这里需要手动创建它们:

sudo mkdir /mnt/rootfs/mnt /mnt/rootfs/boot/firmware

然后就可以装载启动分区了:

sudo mount /dev/sdb1 /mnt/rootfs/boot/firmware/

然后就是复制启动分区,这里大部分选项和启动分区中的选项一样:

sudo rsync -axHAWXS --numeric-ids --info=progress2 /boot/firmware/* /mnt/rootfs/boot/firmware/

如果你比较细心的话,会发现原先红色的软链接文件现在变蓝了:

请添加图片描述

可以靠这个现象判断是否复制成功。但是并不是所有的文件都能这样判断的,比如说/proc/中的一些软链接文件可能需要后续自动更新和生成才能变红。

第三步:修复/etc/fstab/boot/cmdline.txt

/etc/fstab文件会列出启动时自动挂载的所有磁盘分区。由于我们是直接复制的,UUID 对不上,所以需要手动进行修改。

使用sudo fdisk -l可以在Disk identifier部分看到硬盘的标识符,这个我们后面需要用:

请添加图片描述

可以看到/dev/sdb1/dev/sdb2两个分区的 UUID。根据这个内容对相应的文件进行修改,需要注意修改的文件是/mnt/rootfs/etc/fstab(路径可能会有所不同),而不是系统盘中的/etc/fstab

/mnt/rootfs/etc/fstab的两个PARTUUID=的后面修改成对应的内容即可,如下(下图是没改完的,按理说两个 UUID 只有后面编号不同):

请添加图片描述

然后修改/mnt/rootfs/boot/cmdline.txt(这是个软链接,实际文件在firmware中)中的相应部分(下图中高亮部分):

请添加图片描述

这时候就一切完工了。我们可以关机、拔掉原来的硬盘启动试试看(一定要拔掉旧的,不然可能会用旧的启动分区来启动新的,我在实验的时候遇到过,然后又抢救了一回硬盘)。

可以看到能直接使用,几乎没什么区别,使用sudo fdisk -l查看硬盘可以看到现在的/dev/sda是这个硬盘了。

请添加图片描述

希望能帮到有需要的人~

参考资料或扩展阅读

本文虽然我付出了不少的时间和精力进行实验和尝试,但是也要感谢很多人编写的博客为我提供了思路和解决方案。

How can I change the volume name of a FAT32 filesystem? - Unix & Linux stackexchange:这篇帖子介绍了如何给 FAT32 修改分区名。

How to Format Disk Partitions in Linux - Dejan Tucakov:从这篇文章中我才知道某些命令行分区工具并不会创建文件系统,然后我发现parted也是。

Clone File System Hierarchy to Another Disk With Rsync - Francesco Galgani:这篇文章介绍了如何使用rsync克隆磁盘,也为我解决了很多rsync复制的问题,还为我调整启动引导提供了灵感。文章主要是关于大众设备上的 Linux 系统,所以只提及了/etc/fstab,而且引导是通过 GRUB。树莓派自己的系统的引导是通过config.txtcmdline.txt文件进行的。如果你想尝试 GRUB 引导启动树莓派,那么可以看看这个贴子GRUB on RPi 4 - Raspberry Pi Forums(我没有尝试,对内容实际意义不做保证)。

The config.txt file - Raspberry Pi Documentation:这是config.txt的官方文档,虽然本文没使用到config.txt,但是在这篇文档中介绍了树莓派的大致启动流程,我也是从中发现cmdline.txt,才能完成最后的修复工作。

Raspberry Pi 4 and Raspberry Pi 5 Boot Flow - Raspberry Pi Documentation:这部分文档介绍了详细的启动流程,作为扩展阅读可以看看。

Raspberry Pi 4/400 Bootloader Firmware Update/Recovery Guide - James A. Chambers:这篇博客介绍了如何修复和更新树莓派 4/400 的启动器固件。因为两个硬盘有时候不小心同时连接到树莓派启动,可能会导致启动器固件出现问题。可以看看这篇文章修复固件。

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值