ブート時にパニック起こして死んでいるときありますよね?
自宅ラズパイサーバーをかれこれ4年ほど起動しっぱなし。
unattended-upgradeを使って、週に1度のタイミングでリブートされることがある(カーネル更新など)のですが、ごくたまにパニック起こして死んでることがある。感覚的には半年〜1年に1回くらい。
使用環境
- Raspberry Pi4b
- Ubuntu OS 22.04 LTS
- SDカードの2枚刺し (/dev/mmcblk0 + /dev/sda)
- rootファイルシステムに NILFS2を使用。
$ df -h -t nilfs2
Filesystem Size Used Avail Use% Mounted on
/dev/mmcblk0p2 107G 85G 17G 84% /
/dev/sda2 107G 81G 21G 80% /mnt/rootfs
パニックを起こしたときのスクリーンショット
・・・はうまく取れませんでした。
なぜか btrfsを探しに行って見つからない、みたいなメッセージだった。
現象を確認
○ lsblkコマンドでブロックデバイス自体は見える。
○ mount -t nilfs2 /dev/sda2 /mnt/rootfs、と明示的にファイルシステムを指定するとマウントできる。
× ファイルシステムタイプを指定しないと、マウントに失敗する。
× lsblk -fオプション付きで動かしても、ファイルシステムが認識されない。(FSTYPE, FSVER, LABEL, UUIDがいずれも表示なし)
$ sudo lsblk -f /dev/sda2
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda2 20.6G 76% /mnt/rootfs
$ lsblk -f /dev/mmcblk0p2
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
mmcblk0p2 nilfs2 2 writable 1327de89-f140-4feb-bab0-2d55a6e4eeb1 16.7G 79% /var/snap/firefox/common/host-hunspell
/
・・・確かに、これじゃパニック起こすかもしれない。
何が問題なのか?
ChatGPTさんから、wipefs(8)コマンドを使ってみましょう、と助言される。
$ sudo wipefs /dev/sda2
DEVICE OFFSET TYPE UUID LABEL
sda2 0x2c000 xfs_external_log
sda2 0x406 nilfs2 d0deb1ac-5692-4167-b136-47d275a294c6 writable
sda2 0x1aa0fff006 nilfs2 d0deb1ac-5692-4167-b136-47d275a294c6 writable
おいおい、xfs_external_logなんて知らないよ?
$ sudo hexdump -C -n 512 -s 0x2c000 /dev/sda2
0002c000 fe ed ba be 00 00 13 3b 00 00 00 02 00 00 fc 00 |.......;........|
0002c010 00 00 13 3b 00 00 3f 80 00 00 13 3b 00 00 3f 00 |...;..?....;..?.|
0002c020 70 d3 89 39 00 00 3f 00 00 00 00 05 75 44 e3 79 |p..9..?.....uD.y|
0002c030 00 00 13 3b 00 00 13 3b 00 00 13 3b 00 00 13 3b |...;...;...;...;|
*
0002c120 00 00 13 3b 00 00 13 3b 00 00 13 3b 00 00 00 01 |...;...;...;....|
0002c130 4d bd fd c5 91 ec 4e 58 bf 16 2a a4 7c c6 ee eb |M.....NX..*.|...|
0002c140 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0002c150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0002c200
0xfeedbabe、ってマジックナンバーが誤検出されているようだ。
たまたま16KB境界にいたのがまずかった・・・?
で、これってどうすりゃいいんだい?
wipefs(8)で明示的に不要なファイルシステムシグニチャを消せば復活。
$ sudo umount /dev/sda2
$ sudo wipefs --offset 0x2c000 /dev/sda2
/dev/sda2: 4 bytes were erased at offset 0x0002c000 (xfs_external_log): fe ed ba be
$ sudo wipefs /dev/sda2
DEVICE OFFSET TYPE UUID LABEL
sda2 0x406 nilfs2 d0deb1ac-5692-4167-b136-47d275a294c6 writable
sda2 0x1aa0fff006 nilfs2 d0deb1ac-5692-4167-b136-47d275a294c6 writable
ぉいぉい。それって安全なの?色々気になる。
- 今回、ご検出されたデータセグメントはNILFS2的に未使用な領域(#0, unused segment)だったので気兼ねなく消しました。
- とはいえ、NILFS2みたいなログストラクチャファイルシステムだと、こういう誤検出は普通に起きそうな気がするが。。。どうなの?
- ってことで、ChatGPTさんに聞いてみました。結論:起きてもおかしくない。
①「どのセグメントの内容に xfs_external_log のシグネチャが紛れ込んだのか?」
wipefs の出力で:
OFFSET TYPE
0x2c000 xfs_external_log
と出ていました。この 0x2c000 バイトはセグメント番号に換算すると以下の通りです:
セグメントサイズ(ブロック数):2048
ブロックサイズ:4096バイト
⇒ 1セグメント = 2048 × 4096 = 8,388,608 バイト (=0x800000)
したがって、
0x2c000 ÷ 4096 = 44
つまり セグメント番号 44(未使用セグメント) の先頭に 0xFEEDBABE(XFS external logのマジック)が残存していたということになります。
✨ 補足:
lssu の出力でも、セグメント 44 は状態 ---(未使用)であり、古い内容がクリーンされずに物理的に残っていた状態と一致しています。
②「ファイルシステムのシグネチャが誤検出されることは起こり得るのか?」
✅ はい、起こり得ます。理由は以下のとおり:
🔸 blkid / file -s / lsblk の仕組み
これらのコマンドは デバイスの先頭付近 or 特定オフセットにある「マジックナンバー(ファイルシステム識別子)」を元に判断します。
これはあくまで「バイト列の一致によるパターンマッチ」であり:
未使用領域に残っていた古いデータ
セグメントの先頭に残った過去のマジック番号
を検出してしまうことがあります。
感想
- NILFSって安心感高いんだけど、ハマるときはハマる。
- マジックナンバーによるファイルシステム検知は危険。DockerやKVMなどで、今どきはファイル上にブロックデータが乗っかっていることがあり得るし。
- ChatGPTさん、優秀。wipefs(8)なんて知らんし。w
- 0xfeedbabeとか知らん。0xdeadbeefってのを使ってた例は見たことある。