【解決】NILFS2のファイルシステムがブート時に認識されなくなる

# ブート時にパニック起こして死んでいるときありますよね？
自宅ラズパイサーバーをかれこれ４年ほど起動しっぱなし。
unattended-upgradeを使って、週に１度のタイミングでリブートされることがある（カーネル更新など）のですが、ごくたまにパニック起こして死んでることがある。感覚的には半年〜１年に１回くらい。

# 使用環境
- Raspberry Pi4b
- Ubuntu OS 22.04 LTS
- SDカードの２枚刺し (/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)なんて知らんし。ｗ
- 0xfeedbabeとか知らん。0xdeadbeefってのを使ってた例は見たことある。