ラズパイ4のmicroSDが壊れて起動しなくなってから復旧までの道のり

# 概要

本記事は、Raspberry Pi 4でOS等の主要データを格納していたmicroSDが壊れて起動しなくなった後で、新しいmicroSDにデータをコピーして運良く復旧できた内容についてまとめたものです。

# 事の発端

## ラズパイに突然アクセスできなくなる...

Raspberry Pi 4をおおよそ二年ほど、常時稼働させていました。用途の一つとして、自分で作ったDockerイメージを格納するためのコンテナレジストリのサーバ稼働用として使っていました。OSはUbuntu 22.04 LTSです。
ある時、別のマシンで作ったコンテナイメージをラズパイのコンテナレジストリに``docker push``していたら、突如処理が止まってしまいます。原因特定のため、``ping``や``ssh``や``nmap``のコマンド達を実行してみるも、つながっている感じのレスポンスはどれも返ってこない状態です...
ラズパイはWi-Fi接続で使っていたので、「おそらくネットワークの調子が悪いのかな」と推測します。ラズパイの現在の状態を確認できる手段があればいいのですが、普段はモニターを接続せずに使っていてすぐには確認できないです。初期設定だと、電源が入っている状態でモニターを後でつないでも画面には何も映らない設定になっています。

なので仕方なく、電源スイッチを切ってモニターをつないだ後に、再び電源スイッチを入れて再起動することにします。

## ラズパイが起動しない...

電源を入れて1分くらい待つと、以下のように怪しい表示が出てきます。

![Image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/f392cc3a-c918-6648-03ab-2988ec194e67.jpeg)

以下、主要なメッセージを抜粋。
```
superblock needs_recovery flag is clear, but journal has data.
Run journal anyway

UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
fsck exted with status code 4
The root filesystem on /dev/mmcblk0p2 requires a manual fsck
```

どうやら``/dev/mmcblk0p2``のファイルシステムに重要な問題があり自動復旧できなくて、手動での修復が必要のようです。
``fsck``はファイルシステムのチェックや修復に使うという認識は何となくありましたが、実際に使ったことはありません。若干不安ではありますが、言われた通りに``fsck``を実行してみることにします。

![Image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/be987b07-93be-f4fb-2d9f-2652f0dfdb2c.jpeg)

ところが、``unable to set superblock flags on writable`` （``writable``というデバイスのsuperblock flagsを設定できませんでした）と表示されて修復できなかったようです。うーんこれは結構厳しい...

※余談ですが、最初筆者は上の意味を「superblock flagsがwritableな状態にならなかった」と誤解していました。後に、``writable``は``/dev/mmcblk0p2``のパーティションに付けられたラベルの名前だったことに気づきます。なので素直に「``writable``というデバイスのsuperblock flagsを設定できませんでした」と理解すればよかったのです。（出ている単語に引っ張られて誤訳してしまう自分が嫌だw）

# 復旧のための作戦と準備

## 新しいmicroSDカードにコピーして復旧する方針に

ラズパイのOS本体が入っているmicroSDカードはもう寿命だなと判断して、新しいmicroSDカードを買ってそちらにデータをコピーすることにします。実際にmicroSDカードのデバイスの状況を診断ツールとかで確認したわけではないので本当はまだ使えたかもしれませんが、そこを頑張るメリットはほぼないので「もう寿命」と判断しました。
新しいmicroSDカードとして購入したのは、SanDiskの128GBのストレージを格納できるもの（型番はSDSQUAB-128G-GH3MA、[リンク](https://www.amazon.co.jp/SanDisk-microSD%E3%82%AB%E3%83%BC%E3%83%89-Class10-10%E5%B9%B4%E9%96%93%E9%99%90%E5%AE%9A%E4%BF%9D%E8%A8%BCUltra-SDSQUAB-128G-GH3MA/dp/B0CH2X5LBX)）です。

また、データをコピーするためのLinux PCをラズパイとは別に用意します。幸いなことに私が持っていたPCはSDカードの差し込み口があったので、microSDからSDへの変換アダプターさえあればデータをコピーできそうです。（もしSDカード差し込み口がない場合は、SDカードリーダを買う必要があります）

## 復旧手順を考える

復旧に必要なモノの準備が整ったので、次は手順を考えます。以下のような感じでやっていきます。

#### 1. microSDカードのデータを、PCにコピー

```
1-1. 今まで使っていたmicroSDカードを、コピー用のPCに取り付ける
1-2. microSDカードのデータをPCにコピーする
1-3. 今まで使っていたmicroSDカードをPCから取り外す
```

#### 2. PCにコピーしたデータを、新しいmicroSDカードにコピー

```
2-1. 新しいmicroSDカードを、コピー用のPCに取り付ける
2-2. 新しいmicroSDカードにパーティションを作成する
2-3. PCにコピーしたデータを新しいmicroSDカードにコピーする
2-4. 新しいmicroSDカードをPCから取り外す
```

#### 3. ラズパイの起動

```
新しいmicroSDカードをラズパイに差し込んで、祈りながら電源スイッチを入れる
```


ここで一番心配なのは、「1-2. microSDカードのデータをPCにコピーする」の部分です。そもそもファイルシステムが異常な状態になっているのに、まともにコピーできるのだろうか...

まあともかくやってみましょう。

# 復旧していく

考えた復旧手順をもとに、復旧を目指して実作業を進めていきます。

## 1. microSDカードのデータを、PCにコピー

### 1-1. 今まで使っていたmicroSDカードを、コピー用のPCに取り付ける

microSDカードを取り付けた後に、現在のデバイスの状態を確認してみます。
（後で新しいmicroSDカードでパーティションを作成する際にセクターで範囲指定したいので、``unit s``でセクターで表示しています）
```
$ sudo parted /dev/mmcblk0 unit s print
モデル: SD SC128 (sd/mmc)
ディスク /dev/mmcblk0: 128GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ:

番号  開始     終了        サイズ      タイプ   ファイルシステム  フラグ
 1    2048s    526335s     524288s     primary  fat32             boot, lba
 2    526336s  249737182s  249210847s  primary  ext4
```
パーティションが二つに分かれていて、``/dev/mmcblk0p1``はブート用、``/dev/mmcblk0p2``はOS本体が格納されている領域のようです。先ほどラズパイを起動した時に問題があると言われたのは、``/dev/mmcblk0p2``のパーティションでした。

### 1-2. microSDカードのデータをPCにコピーする

上で確認した各パーティションのデータをそれぞれコピーします。コピーするためにはOSにマウントが必要なので、次のコマンドでマウントしてOSから各ファイルシステムにアクセスできる状態にしておきます。

```
sudo mkdir /mnt/src1 /mnt/src2
sudo mount /dev/mmcblk0p1 /mnt/src1
sudo mount /dev/mmcblk0p2 /mnt/src2
```

問題があると言われた ``/dev/mmcblk0p2`` もあっさりとマウントできました。不安なので、中身もざっくり確認してみます。

```
$ ls -l /mnt/src2/
合計 116
drwxr-xr-x  24 root root  4096  1月 28 16:08 ./
drwxr-xr-x  12 root root  4096  8月 15  2023 ../
drwxr-xr-x   2 root root  4096  4月 19  2022 .disk/
lrwxrwxrwx   1 root root     7  4月 19  2022 bin -> usr/bin/
drwxr-xr-x   4 root root  4096  3月 24 08:41 boot/
drwxr-xr-x   2 root root  4096  8月 17  2022 config/
drwxr-xr-x   2 root root  4096  8月 17  2022 data/
drwxr-xr-x   4 root root  4096  4月 19  2022 dev/
drwxr-xr-x 122 root root 12288  3月 24 08:34 etc/
drwxr-xr-x   5 root root  4096  1月 29  2023 home/
...
```

おお普通に見れている！安心するのは早いですが、とりあえずはよかった。

続いてコピー用のディレクトリを作ります。
```
sudo mkdir -p /path/to/copy1
sudo mkdir -p /path/to/copy2
```
↑ ディレクトリ名はお使いの環境に応じて変更ください

作ったディレクトリに、``rsync``コマンドでデータをコピーしていきます。
まずは ``/dev/mmcblk0p1`` から。

```
sudo rsync -ahv /mnt/src1/ /path/to/copy1/
```
10秒もかからずに終わりました。
容量を確認すると237MBなので、25MB/sくらいの速さでコピーできていそうです。
```
$ sudo du -sh /path/to/copy1
237M    /path/to/copy1
```

続いては、ファイルシステムた異常になっている問題の``/dev/mmcblk0p2``のコピーです。確か容量は40GBよりちょっと少ないくらいだったので、30分もあればコピーが終わると予想し、以下のコマンドでコピーを実行します。
```
sudo rsync -ahv /mnt/src2/ /path/to/copy2/
```

ところが1日以上経ってもrsyncが完了せず、ずっと続いています。
そして、時折以下のようなエラーが出力されます。

```
rsync: read errors mapping "/mnt/src2/filepath": Input/output error (5)
```
```
rsync: readdir("/mnt/src2/dirpath"): Input/output error (5)
```

途中でrsyncの標準出力が止まってしまうので、処理を一回止めて再実行するというのを数回試します。が、また途中で止まってしまい、結局rsyncは最後まで終了できませんでした...
それでもコピー先のディレクトリやファイル一覧を確認すると、だいだいコピーはできていそうです。完全にrsyncが終わるのを待っていたらどれだけ時間が掛かるかわからないので、「コピーは完了した」とみなして、次のステップに進むことにします。

### 1-3. 今まで使っていたmicroSDカードをPCから取り外す

以下のコマンドでアンマウントしてから、microSDカードをPCから取り外します。
```
sudo umount /mnt/src1
sudo umount /mnt/src2
```

## 2. PCにコピーしたデータを、新しいmicroSDカードにコピー


### 2-1. 新しいmicroSDカードを、コピー用のPCに取り付ける

続いて新しいmicroSDカードを取り付けて、現状を確認します。

```
$ sudo parted /dev/mmcblk0 print
モデル: SD SD128 (sd/mmc)
ディスク /dev/mmcblk0: 128GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ:

番号  開始    終了   サイズ  タイプ   ファイルシステム  フラグ
 1    16.8MB  128GB  128GB   primary
```

パーティションテーブルは既にmsdosで作られていて、今まで使っていたmicroSDと同じなのを確認できます。
また、一つのパーティションが既に作られていますが、この後パーティションを作り直す際に邪魔になるので、この時点で次のコマンドで削除しておきます。

```
$ sudo parted /dev/mmcblk0 rm 1
```

### 2-2. 新しいmicroSDカードにパーティションを作成してフォーマットする

今まで使っていたmicroSDと同じようにパーティションとファイルシステムを作成します。
もともとは、次のようなパーティション構成で作られていました。

```
番号  開始     終了        サイズ      タイプ   ファイルシステム  フラグ
 1    2048s    526335s     524288s     primary  fat32             boot, lba
 2    526336s  249737182s  249210847s  primary  ext4
```

新しいmicroSDも、上と同じ状態になるようにこれから進めていきます。

#### パーティションの作成

以下のようにして、2つのパーティションを作成します。``mkpart``でパーティションを作成し、``set``でパーティション1にboolのフラグをつけています。
```
$ sudo parted /dev/mmcblk0
(以後はpartedのコマンド入力モードになる)
...
(parted) mkpart primary fat32 2048s 526335s
(parted) set 1 boot on
(parted) mkpart primary ext4 526336s 100%
```
パーティションが作成されたことを確認して、partedから抜けます。
```
(parted) p
モデル: SD SD128 (sd/mmc)
ディスク /dev/mmcblk0: 128GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ:

番号  開始    終了   サイズ  タイプ   ファイルシステム  フラグ
 1    1049kB  269MB  268MB   primary  fat32             boot, lba
 2    269MB   128GB  128GB   primary  ext4              lba
(parted) q
```

#### ファイルシステムのフォーマット
上の状態だとパーティションが作られただけの状態なので、各パーティションを以下のようにフォーマットします。

```
sudo mkfs.fat -F32 /dev/mmcblk0p1
sudo mkfs -t ext4 /dev/mmcblk0p2
```

#### ラズパイはどうやってブートしている？？

ここで一つの疑問が頭をよぎります。
ラズパイが最初に起動した時に、どうやってboot用パーティションやOSルート(``/``)の場所を認識するのだろうか...
ブートローダーがGRUBの場合だと、筆者が[こちらの記事](https://qiita.com/showchan33/items/0900a41bd1f1cb1c27cb#%E6%89%8B%E9%A0%864--%E3%83%96%E3%83%BC%E3%83%88%E3%83%AD%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)で書いたように結構面倒な手順が必要です。ラズパイも同じようにやるのでしょうか。
ざっと調べてみると、**ラズパイのブートローダーはGRUBではない**らしいです。ではその設定とか更新はどうやったらできる？？

すぐにわからないので、とりあえずは ``/etc/fstab``の内容を見てみることにします。

```$ cat /path/to/copy2/etc/fstab
LABEL=writable  /       ext4    discard,errors=remount-ro       0 1
LABEL=system-boot       /boot/firmware  vfat    defaults        0       1
```

今まで私が見たことのあるfstabとは異なる点が2つあります。
* (1) マウント元がパーティションのパス(``/dev/sda1``等)やUUIDではなく、LABELで指定されている
* (2) マウントポイントに ``/boot/firmware``が記載されている

(2)の内容は十分に理解できていませんが、少なくとも(1)のパーティションのラベルづけはやっていた方が良さそうです。

※ 結局ブートローダーの設定や更新の疑問は解決せずに何も対処はしなかったのですが、最終的に起動はできたので結果オーライでした。

#### 各パーティションにラベルをつける

各々次のコマンドでラベルをつけます。ファイルシステムによって使うコマンドが違うようです。

```
sudo dosfslabel /dev/mmcblk0p1 system-boot
sudo e2label /dev/mmcblk0p2 writable
```
それぞれのパーティションにラベルが付いたのを確認します。
```
$ sudo dosfslabel /dev/mmcblk0p1
system-boot
```
```
$ sudo e2label /dev/mmcblk0p2
writable
```

### 2-3. PCにコピーしたデータを新しいmicroSDカードにコピーする

準備が整ったので、新しいmicroSDカードにデータをコピーします。

まずは、新しいmicroSDカードをマウントします。
```
sudo mkdir /mnt/dst1 /mnt/dst2
sudo mount /dev/mmcblk0p1 /mnt/dst1
sudo mount /dev/mmcblk0p2 /mnt/dst2
```

続いて各パーティションのデータをrsyncでコピーします。

```
sudo rsync -ahv /path/to/copy1/ /mnt/dst1/
sudo rsync -ahv /path/to/copy2/ /mnt/dst2/
```

``/path/to/copy2``に今まで使っていたmicroSDカードからコピーした際は一日経っても終わりませんでしたが、今回は37GBのデータのコピーが22分で終わりました。

### 2-4. 新しいmicroSDカードをPCから取り外す

以下のコマンドでアンマウントしてから、microSDカードをPCから取り外します。
```
sudo umount /mnt/dst1
sudo umount /mnt/dst2
```

## 3. ラズパイの起動

ようやくラズパイを起動する所まで辿り着きました。データをコピーした新しいmicroSDカードをラズパイに差し込んで、ドキドキしながら電源スイッチを入れます。
コピー処理が完全に終わらなかったり、ブートの仕組みがわからないまま見切り発車でここまで来てしまいましたが、果たして無事に起動できるのでしょうか...

モニターを見てみましょう。

![Image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/fb54ec22-d6dc-70fa-76ea-a1d60ed832d4.jpeg)

なんと、OSの各サービスの起動の状態まで進んでようです！

そして外付けデバイスの確認エラーは出てますが、ログインを受け付ける状態になったのを確認。

![Image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/87e0a876-65f3-7dde-ba36-e0bf86c4f6b8.jpeg)

また、別のマシンから``ping``,``nmap``, ``ssh``してもちゃんと通りました。

運よく復旧できたようです！

## 起動後の不具合への対処（24/05/10追記）

一応復旧はしてOSは立ち上がるようになったのですが、DNS設定がおかしくなってaptのリポジトリに接続できなくなっていたり、Dockerコンテナが起動しなくなっていたり、不具合があちこちに見られる状態でした。
調べていったら、Systemdが正常に起動していないことが根本原因ということがわかり、以下のコマンドを実行することで解決しました。

```
sudo apt install --reinstall systemd
```

これらの不具合の詳細と対処に関しては、以下の記事にまとめました。

https://qiita.com/showchan33/items/1f27144e697f3191eaa5

# おわりに

ディスク系のデバイスに障害が発生した後にOSをクリーンインストールせずに復旧できたのは初めてで、良い経験になりました。クリティカルなディレクトリが異常になっていたら今回のようにOS起動までは辿り着けなかったはずなので、運にも恵まれたと思います。

私の場合は運良く復旧できたのですが、本記事のやり方で復旧できないケースもあるかと思います。その場合は現状からの復旧を諦めて、必要なファイルを（可能な限り）バックアップした上でクリーンインストールして、OSがきれいな状態で必要なパッケージをインストールする等して設定し直していく方がいいかのもしれません。（実は私もOS起動後の不具合の対応に手こずり、クリーンインストールしようかどうかだいぶ葛藤しました）

最後に、今後筆者が可能ならば知りたい内容について書き遺します。
* fsckでファイルシステムを修復できなかった場合に、別の修復手段があるかどうか
* ラズパイ4のブートの仕組み
* ラズパイ4のOSをmicroSDではなくて、USBで接続したSSD等にインストールしてブートする方法