Raspberry Pi のシステムの入った SD カードのディスク イメージ を同じ容量の別の SD カードへ 復元 する際、正確な容量が微妙に小さいとそのままでは正しく 復元 出来ません。そこで イメージ を編集しメディアの差異に依らず正しく 復元 出来るようにしてみます。
微妙に小さいSDへの復元
FlightAwareがRaspberry Pi向けに提供しているADS-Bレシーバシステム、PiAwareを運用しているSDカードが怪しくなってきたため、新しいSDカードへ交換すべく、以前作成したバックアップイメージから復元しようとするも、Win32DiskImagerではイメージ書き込み時に容量不足の警告を受けます。
これは同じ容量が謳われたSDカードであっても、同じメーカーの商品でさえ製造時期により、その正確な容量が異なるため。
それでも書き込みを強行出来てしまうため、警告内容をよく見ずに進めてしまったのですが、後から検証してみるとbalenaEtcherでは容量が小さすぎると、ターゲットメディアとして選択することが出来ない安全仕様になっていました。
警告無視して復元したSDを検証
こうして警告を無視して復元したSDカードは、Windowsのエクスプローラ上でも一見問題無く認識されており、ドライブの中もエラー無く開くことができました。
尚、Linuxで一般的に使われるextファイルシステムをWindowsで読み書きするには、ext2fsdをインストールしておく必要があります。
Windowsでこれ以上調べることは難しいので、このSDカードをUbuntuで開いてみます。Disksユーティリティでは問題無さそうに見えますが、
blkid で確認すると、ルートシステムのPARTUUIDが見当たりません。
1 2 3 4 5 6 7 8 9 10 |
$ lsblk /dev/sdd NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sdd 8:48 1 15G 0 disk ├─sdd1 8:49 1 108.5M 0 part └─sdd2 8:50 1 14.8G 0 part $ sudo blkid /dev/sdd* /dev/sdd: PTUUID="62f06e5f" PTTYPE="dos" /dev/sdd1: LABEL="boot" UUID="0549-62B1" TYPE="vfat" PARTUUID="62f06e5f-01" /dev/sdd2: LABEL="rootfs" UUID="71391df1-8b84-4d13-9df5-da34ab84d2c6" TYPE="ext4" |
私もきちんと理解しておらず今回あらためて調べてみたのですが、PARTUUIDとはパーティション毎に固有な識別子であり、メディアが変わってもイメージから復元後も同じPARTUUIDが保持されるのだそうです(ちなみにUUIDはファイルシステムに付与される識別子)。
ブート時にカーネルパニック
このSDカードをRaspberry Piに挿して起動の様子をUARTから観察してみると、案の定カーネルパニックしてしまいました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[ 1.165770] CPU: 0 PID: 1 Comm: swapper Not tainted 4.19.66+ #1253 [ 1.172147] Hardware name: BCM2835 [ 1.175726] [<c0017edc>] (unwind_backtrace) from [<c0014e24>] (show_stack+0x20/0x24) [ 1.183754] [<c0014e24>] (show_stack) from [<c06b9750>] (dump_stack+0x20/0x28) [ 1.191254] [<c06b9750>] (dump_stack) from [<c0024690>] (panic+0xdc/0x264) [ 1.198387] [<c0024690>] (panic) from [<c0972678>] (mount_block_root+0x244/0x2d8) [ 1.206134] [<c0972678>] (mount_block_root) from [<c0972990>] (mount_root+0x128/0x16c) [ 1.214321] [<c0972990>] (mount_root) from [<c0972b48>] (prepare_namespace+0x174/0x1d8) [ 1.222600] [<c0972b48>] (prepare_namespace) from [<c0972190>] (kernel_init_freeable+0x208/0x258) [ 1.231785] [<c0972190>] (kernel_init_freeable) from [<c06cf6c4>] (kernel_init+0x18/0x10c) [ 1.240335] [<c06cf6c4>] (kernel_init) from [<c00090ac>] (ret_from_fork+0x14/0x28) [ 1.248150] Exception stack(0xd70f1fb0 to 0xd70f1ff8) [ 1.253381] 1fa0: 00000000 00000000 00000000 00000000 [ 1.261824] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 1.270261] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000 [ 1.277107] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,2) ]--- [ 3.860314] random: crng init done |
これはブートの挙動を決める /boot/cmdline.txt において、ルートファイルシステムの場所を次のようにPARTUUIDで指定しているためでしょう。
1 |
root=PARTUUID=62f06e5f-02 |
これを以下のようなデバイス指定とすれば起動するのかも知れませんが、
1 |
root=/dev/mmcblk0p2 |
おそらく /etc/fstab にも同様な表記が使われていることからも、書き込み時に警告が出ないよう、ディスクイメージをメディアより少し小さめにトリムしてみます。
ディスクイメージの編集
Ubuntuではイメージファイルの右クリックから、ディスクイメージマウンタでまるごとループデバイスとしてマウントすると、先ほどのDisksユーティリティで通常のストレージと同じように扱うことが出来ます。
rootfsのパーティションを選びアンマウントの後、下の歯車アイコンからリサイズをクリックすると、次のようなパーティションサイズ編集ウィンドウが開くので、1.59GBあるこのパーティションを15.0GBまで小さくしてみます。
リサイズ後のパーティション構成は次のように変わり、後方が空き領域となりました。
なお、ディスクイメージの状態によっては、ループデバイスが読み取り専用となってしまい、変更を伴う操作が出来ないことがあります。このような時は、以前、CLIでのループデバイス操作をまとめたこちらの記事を試してみると良いかもしれません。
こうしてパーティションは小さくなったので、次は truncate コマンドを使って後方の空き領域をディスクイメージから切り取ります。まず fdisk で2つ目のパーティション後端のセクタ番号を確認。
1 2 3 4 5 6 7 8 9 10 |
$ fdisk -l piAware_20210114.resized.img ディスク ./piAware_20210114.resized.img: 15 GiB, 16070475776 バイト, 31387648 セクタ 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト ディスクラベルのタイプ: dos ディスク識別子: 0x62f06e5f デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ ./piAware_20210114.resized.img1 8192 230413 222222 108.5M c W95 FAT32 (LBA) ./piAware_20210114.resized.img2 237568 29630463 29392896 14G 83 Linux |
こうして判明したセクタ番号( 29630463 )から切り取りサイズを割り出して truncate コマンドを実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ truncate --size=$[(29630463+1)*512] piAware_20210114.resized.img $ fdisk -l ./piAware_20210114.resized.truncated.img ディスク ./piAware_20210114.resized.truncated.img: 14.1 GiB, 15170797568 バイト, 29630464 セクタ 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト ディスクラベルのタイプ: dos ディスク識別子: 0x62f06e5f デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ ./piAware_20210114.resized.truncated.img1 8192 230413 222222 108.5M c W95 FAT32 (LBA) ./piAware_20210114.resized.truncated.img2 237568 29630463 29392896 14G 83 Linux |
これでようやくイメージファイルのダイエットは完了しました。
これまでの作業の過程でイメージファイルのファイルサイズがどのように変化したのか比べてみると、パーティションをリサイズしただけでは小さくはならず、 truncate して初めて小さくなったことが分かります。
1 2 3 |
16,070,475,776 Byte piAware_20210114.img 16,070,475,776 Byte piAware_20210114.resized.img 15,170,797,568 Byte piAware_20210114.resized.truncated.img |
小さくしたイメージを書き込み
小さくしたイメージをbalenaEtcherに読み込ませると、今度はターゲットSDカードを選択出来るようになったので、そのまま書き込みました。その後のSDカードのパーティション構成をUbuntuで確認すると、rootfsパーティション後方の空き領域の容量が図7の時と異なるのが分かります。この差がSDカードメディア間の微妙な容量の差異というわけです。
また、 blkid でもルートシステムのPARTUUIDが正しく表示されるようになっていました。
1 2 3 4 5 6 7 8 9 10 |
$ lsblk /dev/sdd NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sdd 8:48 1 15G 0 disk ├─sdd1 8:49 1 108.5M 0 part /media/user/boot └─sdd2 8:50 1 14G 0 part /media/user/rootfs $ sudo blkid /dev/sdd* /dev/sdd: PTUUID="62f06e5f" PTTYPE="dos" /dev/sdd1: LABEL="boot" UUID="0549-62B1" TYPE="vfat" PARTUUID="62f06e5f-01" /dev/sdd2: LABEL="rootfs" UUID="71391df1-8b84-4d13-9df5-da34ab84d2c6" TYPE="ext4" PARTUUID="62f06e5f-02" |
正常にブート成功
このSDカードをRaspberry Piに挿して通電すると、シリアルコンソールを確認するまでもなく、基板上のACT緑LEDの点滅から正常に起動していることが分かりました。
起動中のRaspberry Piのコンソールから blkid を確認すると次の通り。
1 2 3 4 5 6 7 8 9 |
$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT mmcblk0 179:0 0 15G 0 disk ├─mmcblk0p1 179:1 0 108.5M 0 part /boot └─mmcblk0p2 179:2 0 14G 0 part / $ sudo blkid /dev/mmcblk0p1: LABEL="boot" UUID="0549-62B1" TYPE="vfat" PARTUUID="62f06e5f-01" /dev/mmcblk0p2: LABEL="rootfs" UUID="71391df1-8b84-4d13-9df5-da34ab84d2c6" TYPE="ext4" PARTUUID="62f06e5f-02" /dev/mmcblk0: PTUUID="62f06e5f" PTTYPE="dos" |
メディア間の容量の差異はSDカードに限った話ではなく、HDDでも普遍的に起こりうる事象で、RAIDミラーリング構成ではよくHDDの容量より少し小さめに領域確保して、メディア間に多少の差異があっても問題無くディスク交換出来るようにするのを思い出しました。