跳至内容

Jixun's Blog 填坑还是开坑,这是个好问题。

将内存卡的 Armbian 迁移到其它内存卡

家里有一台「Orange PI Zero」用于提供一些内网服务。因为旧卡只是一个普通的 Class 10 卡,最大写入速度为 10 MB/s,在执行 apt updateapt upgrade 指令时会… 非常的慢。

※ 任何恢复操作前都需要备份。备份前请腾出空间用于储存备份数据。
※ 这篇文章是实际操作后的复盘记录。我会尽量保持文章的一致性,如果发现错误请报告。

准备工作 #

本文的设备名如下:

  • 旧卡设备是 /dev/sdb
  • 新卡设备是 /dev/sdc

你需要准备的工具:

  • 压缩指令 zstd,解压输出指令 zstdcat
    • 如果没有,可以分别替换为 gzipzcat
  • 备份工具 partclone
  • 底层数据读写 dd
  • (可选) 挂载文件用但不适合恢复的 squashfs,用于提取文件

备份 #

备份系统分区 #

因为不想用 DD 把使用和未使用的分区数据都拷贝了,因此分别用 partclone1 来进行分区备份还原。

sudo partclone.ext4 -c -s /dev/sdb1 | zstd > opi_working_20230721.pcl.zst

得到备份文件,看看大小:

$ ls -lh opi_working_20230721.pcl.zst | cut -f5 -d' '
264M
$ zstdcat opi_working_20230721.pcl.zst | wc -c
987993258 (约 942.2 MB)

zstd 的压缩率还是很可观的,差不多 28%。

归档 (方便文件访问) #

因为我不希望一直将内存卡挂载在电脑上,因此我还用 squashfs 打了一个备份,方便挂载查看文件。如果不需要,可以跳过。

其中 -mem 8G 用来指定存档压缩时最多可占用的内存大小。可以根据你的系统来调节:

# squashfs 是对分区内的文件进行打包
sudo mount /dev/sdb1 /mnt

sudo mksquashfs /mnt opi_working_20230721.squashfs \
  -not-reproducible \
  -xattrs \
  -noappend \
  -progress \
  -mem 8G

# 可以取消挂载了
sudo umount /mnt

挂载的话也是非常简单:

sudo mkdir -p /storage/orangepi_root_old
sudo mount -t squashfs -o ro -o loop \
  opi_working_20230721.squashfs \
  /storage/orangepi_root_old

备份引导 #

Armbian 其实还在文件头写出了一个小引导(还有一些 MBR 信息),先照抄过来。

$ sudo fdisk -l /dev/sdb | tee opi_working_20230721.partition_table.txt
Disk /dev/sdb: 14.46 GiB, 15523119104 bytes, 30318592 sectors
Disk model: USB3.0 CRW   -SD
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: dos
Disk identifier: 0x940fc01d

Device     Boot Start      End  Sectors  Size Id Type
/dev/sdb1        8192 29982720 29974529 14.3G 83 Linux

可以看到第一个分区在扇区偏移(Sector Offset) 8192 处,因此使用 dd 来拷贝这部分的数据:

sudo dd if=/dev/sdb of=opi_working_20230721.header.bin bs=512 count=8192

可以使用 xxd 观察,可以发现从字节偏移 0x2000 处开始有引导代码2

00002000: 1600 00ea 6547 4f4e 2e42 5430 ed4e 3a0c  ....eGON.BT0.N:.
00002010: 0060 0000 5350 4c02 0000 0000 0000 0000  .`..SPL.........
00002020: 2c00 0000 0000 0000 0000 0000 7375 6e38  ,...........sun8
00002030: 692d 6832 2d70 6c75 732d 6f72 616e 6765  i-h2-plus-orange
00002040: 7069 2d7a 6572 6f00 0000 0000 0000 0000  pi-zero.........
00002050: 0000 0000 0000 0000 0000 0000 0000 0000  ................

还原 #

恢复引导 #

※ 该操作会干掉你的分区信息。如果需要,请先备份硬盘数据。

直接将备份的设备头信息写出到新的设备 /dev/sdc 即可:

sudo dd if=opi_working_20230721.header.bin of=/dev/sdc oflag=direct

修复分区表 #

另外因为第一个扇区是 MBR 信息,因此恢复引导的时候也把分区表给拷贝了。

如果是拷贝到新的内存卡,则需要手动修复下:

  • 执行 sudo fdisk /dev/sdc 编辑分区表
    • 指令: d - 删除第一个分区
      • 若询问分区序号,则键入 1 后回车
      • 重复删除直到没有分区。
    • 指令: n - 新建一个分区
      • 询问类型 - 键入 p 后回车,使用主要分区
      • 询问序号 - 键入 1 后回车,使用第一个主分区
      • 询问起始扇区 - 键入 8192 后回车 (同备份的分区扇区偏移)
      • 询问终止扇区 - 直接回车,使用内存卡最终的位置 (你也可以使用 -4M 不使用结尾的部分储存)。
      • 若询问是否擦除分区标记 - 选择 YN 都可以。
    • 指令: t - 修改分区类型
      • 若询问分区序号,则键入 1 后回车
      • 询问分区类型,键入 83 后回车 (代表 Linux 分区)
    • 指令: p - 预览要应用的分区更改。
      • 若预览看起来不对劲,键入指令 q 并回车来放弃更改并退出
    • 指令: w - 写出分区表更改
操作过程查看
$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.39.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-30318591, default 2048): 8192
Last sector, +/-sectors or +/-size{K,M,G,T,P} (8192-30318591, default 30318591):

Created a new partition 1 of type 'Linux' and of size 14.5 GiB.
Partition #1 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: N

Command (m for help): t
Selected partition 1
Hex code or alias (type L to list all): 83
Changed type of partition 'Linux' to 'Linux'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

还原分区 #

然后使用 partclone 来还原:

zstdcat opi_working_20230721.pcl.zst | sudo partclone.ext4 -r -s - -o /dev/sdc1

检查分区 #

还原完后,先跑个检查:

sudo fsck /dev/sdc1

如果发生错误,建议检查原始设备是否也有问题。可以尝试在 fsck 进行修复。

(跑题) 内存卡读写测速 #

测试指令:

# 测试写
sudo dd if=/dev/zero of=./__test.img bs=1M count=256 oflag=direct status=progress

# 测试读
sudo dd of=/dev/zero if=./__test.img bs=1M count=256 iflag=direct status=progress
  • 旧卡 (脱机读写):写 7.2 MB/s51.3 MB/s
  • 新卡 (在线读写):写 20.8 MB/s23.5 MB/s

嗯… 虽然说翻了一倍,但其实和声称的 50MB/s 还是差了些的。拔下来脱机跑看看。

  • 新卡 (脱机读写): 写 51MB/s92.6 MB/s

看来限制是在单片机自身上了,那也没办法了… 有可能和供电不足有关?毕竟我为了省事是直接从路由器的 USB 口接的电源。


  1. 文档参考 Partclone: manual | partclone.restore ↩︎

  2. 可以参考全志 sunxi 百科 的引导说明。 ↩︎

知识共享许可协议 本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

评论区