ラズパイの壊れたSDカードを読みだそう(ddで読めなくてもfsckエラーでも諦めない!)

Rescue a Raspberry Pi SD card with ddrescue! After 10 years, the card failed, and dd couldn’t read it. ddrescue recovered the data, and journal removal fixed the ext4 superblock issue. Finally, PiShrink reduced the image size.

A young boy sitting in front of a Raspberry Pi, looking frustrated while holding an SD card in his hand. Sweat drops on his face indicate his nervousness. Next to him, a cute but intelligent-looking robot is giving advice, appearing helpful and knowledgeable. The scene has a minimalist, flat illustration style with soft, muted color tones. The background is simple and clean, maintaining a calm and focused atmosphere. Illustrated by ChatGPT and DALL-E.

相模原市で IoT 設計を受託しているファームロジックスです。

「諦めない話」が続きます。

私事ですが先日、仕事場の UPS(無停電電源)がトラブルを起こしたとき、長いこと(10年くらいでしょうか)使っていた Raspberry Pi が再起動しなくなりました。そこに特別重要なデータが入っているとは思わなかったので放置していたのですが、先日とある事情で SD カードの中身を確認したくなりました。

再起動しない理由は SD カードの故障(wear)だと予想したのですが、とりあえず Linux(Ubuntu )の dd コマンドで読み出しを試みました。

以下のようなコマンドを実行します。

$ sudo dd if=/dev/sdb of=raspberrypi_backup.img bs=4M status=progress

しかし、全然進みません。dmesg してみると、案の定 SD カードからデータが読めていません。

I/O error, dev sdb, sector 149504 op 0x0:(READ) flags 0x80700 phys_seg 16 prio class 0

やっぱりダメか。諦めかけたのですが、ChatGPT に聞いてみます。すると、ddrescue というツールがあることが分かりました。それは知らなかった!  さっそく試してみます。

GNU ddrescue で読み出す

$ sudo ddrescue -d -r3 /dev/sdb raspberrypi_rescue.img rescue.log

面白いツールです。こんなふうにレスキュー作業が始まりました。

$ sudo ddrescue -d -r3 /dev/sdb raspberrypi_rescue.img rescue.log
GNU ddrescue 1.23
Press Ctrl-C to interrupt
     ipos:    2823 MB, non-trimmed:    5832 kB,  current rate:   60854 B/s
     opos:    2823 MB, non-scraped:        0 B,  average rate:    531 kB/s
non-tried:   13126 MB,  bad-sector:        0 B,    error rate:       0 B/s
  rescued:    2799 MB,   bad areas:        0,        run time:  1h 27m 47s
pct rescued:   17.56%, read errors:       89,  remaining time:      5h 52m
                              time since last successful read:          0s
Copying non-tried blocks... Pass 1 (forwards)

しかし時間がかかります。総計 2日以上は費やしたでしょうか。最終的に、99.99% 以上のブロックが救出できました。(途中で一度うっかり Ctrl-C で停めてしまい再開したので、以下の時間表示はあてになりません。)

GNU ddrescue 1.23
Press Ctrl-C to interrupt
Initial status (read from mapfile)
rescued: 15930 MB, tried: 733184 B, bad-sector: 733184 B, bad areas: 520

Current status
     ipos:   15317 MB, non-trimmed:        0 B,  current rate:       0 B/s
     opos:   15317 MB, non-scraped:        0 B,  average rate:       1 B/s
non-tried:        0 B,  bad-sector:   530944 B,    error rate:      12 B/s
  rescued:   15931 MB,   bad areas:      376,        run time:  1d  9h 41m
pct rescued:   99.99%, read errors:     2779,  remaining time:      8h 11m
                              time since last successful read:     11m  7s
Finished

なんとか希望が持てました。

fsck がスーパーブロックを見つけられない!?

次は fsck でファイルシステムをチェック、および修正します。

その前に、作業を間違えて 2日間の苦労を無駄にしないよう、まずはバックアップを作ります。

$ sudo chown yokoyama.yokoyama raspberrypi_rescue.img
$ cp -p raspberrypi_rescue.img raspberrypi_rescue_backup.img

loop デバイスをセットアップします。

$ sudo losetup -Pf --find raspberrypi_rescue.img
$ losetup -a

fsck をかけます。

$ sudo fsck -y /dev/loop5p2

しかし無情にもエラーです。

$ fsck from util-linux 2.37.2
e2fsck 1.46.5 (30-Dec-2021)
ext2fs_open2: Bad magic number in super-block
fsck.ext2: Superblock invalid, trying backup blocks...
/dev/loop5p2: recovering journal
fsck.ext2: unable to set superblock flags on /dev/loop5p2


/dev/loop5p2: ***** FILE SYSTEM WAS MODIFIED *****

/dev/loop5p2: ********** WARNING: Filesystem still has errors **********

どうも、スーパーブロックをちゃんと読めていないようです。予備のスーパーブロックは大丈夫でしょうか。ChatGPT にお伺いを立てたところ、mke2fs というコマンドで、バックアップスーパーブロックの位置を確認できるそうです。(-n オプションを忘れないように!

$ sudo mke2fs -n /dev/loop5p2
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, ...

得られたスーパーブロックのバックアップ位置を参考に、次のようにしてスーパーブロックを明示的に指定して fsck します。

$ sudo fsck.ext4 -b 32768 -y /dev/loop5p2
$ sudo fsck.ext4 -b 98304 -y /dev/loop5p2
(snip)

どれを指定してもやっぱりだめです。ディスクブロックの 99.99% を復旧できているのに、全てのスーパーブロックが壊れているなんてことはあるのでしょうか?  私の作業が何か間違っているのでしょうか。本当に /dev/loop5p2は ext4 なのでしょうか。

$ sudo blkid /dev/loop5p2
/dev/loop5p2: UUID="f24a4949-f4b2-4cad-a780-a138695079ec" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="0009bf4f-02"

大丈夫そうですね。次に、dumpe2fs してみます。

$ sudo dumpe2fs /dev/loop5p2
dumpe2fs 1.46.5 (30-Dec-2021)
Filesystem volume name:   <none>
Last mounted on:          /
Filesystem UUID:          f24a4949-f4b2-4cad-a780-a138695079ec
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
(snip)

これも大丈夫そうです。ChatGPT に再度助けを求めます。

すると、次のような回答が得られました。

問題の可能性

    1. スーパーブロックは読み取れるが、ジャーナル (has_journal) に問題がある
      • fsck で「ジャーナルの回復ができない」とエラーが出ていたので、ジャーナルが破損している可能性 が高い。
      • 解決策: ジャーナルを強制的に削除し、再作成する。
    2. マウントに必要なメタデータが破損
      • スーパーブロックは dumpe2fs で表示されるが、実際のファイルシステム構造が破損している。
      • 解決策: fsckジャーナルを無効化した状態で強制実行 する。

ジャーナルを強制削除する

まずは、ジャーナルの削除から試してみましょう。

$ sudo tune2fs -O ^has_journal /dev/loop5p2

なにも返事がありませんが、次に進みます。

$ sudo fsck.ext4 -f -y /dev/loop5p2

おーっ。無事に fsck が走りました。たくさんのメッセージ(作業)が表示されることもなく、ファイルシステムが復旧されました。

ジャーナルを再作成します。

$ sudo tune2fs -j /dev/loop5p2

ファイルシステムは無事に直りました。

なお、FAT のほうもチェックしておきます。

$ sudo fsck.vfat -y /dev/loop5p1

ファイルシステムを mountしてみると、ちゃんとファイルにアクセスできます。おそらくファイルシステム上のデータにはエラーがある(ファイルの一部が壊れている)のでしょうか、とりあえずできることはしました。

ファイルシステムをシュリンクする

次に、このイメージファイル raspberrypi_rescue.img には無駄な領域があって大きすぎるので、ファイルシステムをシュリンクしましょう。このツールが非常に便利です。

$ sudo pishrink.sh raspberrypi_rescue.img shrunk_rescue.img

無事にシュリンクできました!

まとめ

今回の作業にあたって、ChatGPT のおかげで 2つのことを助けて貰いました。

  1. Raspberry Pi の SD カードが壊れて、dd で読めなくなっていても諦めない!
    GNU ddrescue を使おう!
  2. fsck で ext4 のスーパーブロックが見つからない?
    → ジャーナルの破損を疑おう!  一度ジャーナルを削除してから fsck しよう。

皆さんも、困ったときには諦めずにファイルシステムの復旧にチャレンジしてください。

お問い合わせはお気軽に!

お問い合わせを頂いた後、継続して営業活動をしたり、ニュースレター等をお送りしたりすることはございません。
御返答は 24時間以内(営業時間中)とさせて頂いております。必ず返信致しますが、時々アドレス誤りと思われる返信エラーがございます。返答が届かない場合、大変お手数ではございますが別のメールアドレスで督促頂けますと幸いです。

コメントを残す