さくらVPSでKernel Panicを起こす場合(Linuxのインストール時、アップデート時)　その2

別のブログで書いた記事の転載です。
http://trid-miracle.blogspot.jp/2015/06/qemukernel-panic-vfs.html

環境:QEMU/KVS
・仮想化IO(VirtIO)が有効な場合

# Net9P/9Pfsとデバイスのメジャー番号に由来する現象
## 現象
起動時に
Kernel Panic - not syncing: VFS: Unnable to mount root fs on unknown-block (0, 0)
が表示されます。
※(0, 0)は、設定によって、(253, 0)、(254, 0)などになる場合があります。

## 原因1
・カーネルのビルド時のconfigで、9Pfs関連の設定がNになっているため発生します。
(例えば、CentOS7では、デフォルトがNになったと、どこかに書いてあったと思います。)

設定はあちこちに分散しています。
関連する設定:
Networking support / Plan 9 Resource Shareing Support (9P2000)
CONFIG_NET_9P

File systems / Network File Systems
CONFIG_9P_FS
など。

## 対策1
9Pfs関連の設定項目をYにして、カーネルをビルドします。

----
## 原因2
設定時と起動時などで、デバイスのメジャー番号が変わるために発生します。
udev、devicemapperがメジャー番号を付け替えるのが原因です。

## 対策2
### LILOの場合
`root=`ではなく、`addappend=" root="`を使います。
※メジャー番号を認識するタイミングの問題です。

`root=/dev/vda1`の場合は、(lilo.confを書き換えた後に)liloを実行した時に決まります。
言い換えると、liloの実行後に、メジャー番号が変わると、Kernel Panicが発生します。

`addappend=" root=/dev/vda1"`の場合は、起動時に(文字列で指定する)起動オプションに" root=/dev/vda1"を付け加えるので、正常に起動します。
言い換えると、すでに/dev/vda1メジャー番号は決まった。その/dev/vda1で行ってくれ！という感じです。
appendの設定を間違えると、「メジャー番号は決まった。さあ、どこから起動する?」という状態でLILOの表示が止まるので、挙動がわかりやすいと思います。

----
appendに相当する設定は、Linuxの起動時に、Tabキーなどを押下すると入力できます。
appendの設定を試したい時などに。

ちなみにliloの設定ファイルの、
`append=`は、全てのイメージに共通する設定、
`addappend=`は、イメージ毎に設定を追加したい時などに使います。
addが付いている方は、その名の通り、`append=`の設定にadd(追加)する設定です。

----
SlackwareのDocumentなどから。
(LILOを使用する場合) /boot、/(root)をLVMに置くのは非推奨です。
また、/(root)と/usrは同じパーティションに置いた方がよい(そうでないと、起動処理が複雑になる) ともされています。

LVMに/(root)などを配置した場合は、(initrdなどで)LVM用のモジュールなどの読込オプションが必要になります。
(カーネルをビルドして使う場合は、ディスク、ファイルシステム関連のオプションはM(モジュール)でなくY(組み込み)の方がよいと思います。)

----
*LILOは、GPTディスクに非対応です。また、2015年いっぱいで開発終了とのことです。*
(ELILOは2014年で開発終了になっています。)
とはいっても、VPS環境で、GPTを使うメリットがあまりないように思います。
(ディスクの容量的にも、障害対応的にも。)
パーティションテーブルのバックアップを戻す機会も無いでしょうし・・
(障害を起こしたセクタに、書き戻しても・・ということで、交換になると思います。)

----
余談:
起動時に表示される"LILO"は、実は意味があるのです。
"LI"が1st boot loader、"LO"が2nd boot loader。
(開始と終了で、1文字ずつ進んで行きます。)
ハードディスクからの起動では、早すぎてわからないと思いますが・・
覚えておくと役に立つかもしれない、ワンポイント。

参考資料:
[LILO "the Linux Loader" の動作について](http://archive.linux.or.jp/JF/JFdocs/inside-lilo.html)

GRUBの場合も、似たような動作なので、さらっと目を通しておくとよいかも。
(ブートセクターの先頭 438 bytes とか、ね！)

### GRUB (+ systemd)の場合
LILOと同じように、/dev/vdaのデバイス番号が決まった後に、どのrootを使うかを指定できれば・・解決するはずなのですが・・・・・

GRUB環境で実験した場合、起動時に手入力で`linux=`～～などを設定すると起動できた・・と思います。
(その時は、grub.confなどでは回避できなかった記憶があります。)

/bootと/(root)を別パーティションに置いている時は、/(root)をLVMに置くと起動できたような気もしますが・・・

----
一見、起動がある程度すすんだ後に(cdを認識したタイミングなどで)Kernel Panicが発生したように見えるので、原因を知らずに見ると、解析が非常に困難です。
GRUB(のモジュール) -> Linux(のモジュール) -> systemdのどこで出た表示かを正しく推理しましょう。
BIOS環境なのか、UEFI環境なのかも、把握しておきましょう。(システム、Linuxそれぞれの環境を。)
EFIパーティションがあるからといって、UEFI環境とは限りません。
(一旦ハードディスクをまっさらにしてみたら、UEFIシェルが表示されなかった・・なんてことも。)
・・ということで、GRUB環境でこの手の問題にはまると、解決まで相当時間がかかります。

標準でGRUB以外を使用しているDebianなどがデフォルトで用意されている場合は、一旦、それをインストールしてみるのも一手です。

新規のインストール(デフォルトの「動く」環境から乗り換える場合など)の場合は、Linuxが動く状態で十分に情報収集してからOSを差し替えることをお勧めします。
特に、/boot やEFI関連、/etc、/var/log、dmesgやlspciの結果などは、可能であれば手元にコピーしておきましょう。

`/sys/firmware/efi`が存在するか　も重要です。
(BIOS環境なのかUEFI環境なのかの判定用に)
参考:ArchWiki
[Unified Extensible Firmware Interface](https://wiki.archlinuxjp.org/index.php/Unified_Extensible_Firmware_Interface#UEFI_.E3.83.95.E3.82.A1.E3.83.BC.E3.83.A0.E3.82.A6.E3.82.A7.E3.82.A2.E3.81.AE.E3.83.93.E3.83.83.E3.83.88.E6.95.B0.E3.82.92.E8.AA.BF.E3.81.B9.E3.82.8B)

----
(BIOSとUEFIの)ハイブリッド起動ディスクだと起動しない(または、画面が真っ黒のまま)　という場合もあります。
その場合は、一旦、BIOS専用の起動ディスクを作って起動してみましょう。

起動ディスクに必要なファイル。
Slackwareの場合
/isolinux/initrd.imgなど
/kernel/huge.s/bzImageなど (カーネルを差し替える場合は、これを入替えます)
他のディストリビューションでも、基本は同じだと思います。
あとは、mkisofsの-bオプション、-cオプションで、起動可能ディスクを作ります。

あと、必要なモジュールもどこかに。
(Linuxのインストール後にコピーするために。)
※カーネルのconfigで、ハードディスクとCD-ROM/DVDにアクセスするための項目は、必ずYにします。M(モジュール)だとだめです。

----
追記:
RedHat製品マニュアル から、一部抜粋。
[付録A デバイスマッパー](https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Logical_Volume_Manager_Administration/device_mapper.html)
[A.3. デバイスマッパーによる udev デバイスマネージャーのサポート](https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Logical_Volume_Manager_Administration/udev_device_manager.html)

> 表A.1 デバイスマッパーデバイス向けの udev ルール
> 10-dm.rules
> 11-dm-lvm.rules
> 13-dm-disk.rules

> 以下の変数は、10-dm.rules で設定されています。 
> DM_UUID: デバイスマッパーデバイスのUUID 

> 以下の変数は、11-dm-lvm.rules で設定されています。 
> DM_LV_NAME: 論理ボリューム名 

> 10-dm.rules
> 基本的/一般的なデバイスマッパールールを格納し、/dev/mapper 内に /dev/dm-N をターゲットとするシンボリックリンクを作成します。ここで N は、カーネルによってデバイスに動的に割り当てられる数です。 (/dev/dm-N はノードです)
> 注意: /dev/dm-N ノードは、デバイスにアクセスするスクリプトには 決して 使用されるべきではありません。N の数は動的に割り当てられ、デバイスがアクティブ化される順序によって変化するためです。

> 11-dm-lvm.rules
> LVM デバイス用に適用されるルールを格納し、ボリュームグループの論理ボリュームのシンボリックリンクを作成します。このシンボリックリンクは、/dev/vgnameディレクトリーに、/dev/dm-N をターゲットとして作成されます。 

> 13-dm-disk.rules
> /dev/disk/by-id、/dev/disk/by-uuid、および /dev/disk/by-uuid ディレクトリー内にシンボリックリンクを作成します。
(注:by-uuidが2つ並んでいますが、おそらくby-pathまたはby-labelの誤記です)

まとめると、LVM管理化のディスクと、それ以外で、挙動が変わるということです。
また、LVM管理化にないディスクにUUIDでアクセスするためには、13-dm-disk.rulesの処理が終了している必要があります。

・・・では、これらのディスクに、起動時にどうやったらアクセスできるでしょう?というのが、今回の話題の根底にある問題。

(ブートローダは、基本的には、1番目のディスクの、指定セクタを読み込むという動作なので、/bootなどにアクセスできます。)


----
どのデバイス名でアクセスしたらよいか についての参考資料。

RedHat製品マニュアル
[4.4.8. 永続的なデバイス番号]
(https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Logical_Volume_Manager_Administration/persistent_numbers.html)
[4. Persistent Naming]
(https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/5/html/Online_Storage_Reconfiguration_Guide/persistent_naming.html)

Archlinux Wiki
[Persistent block device naming]
(https://wiki.archlinux.org/index.php/Persistent_block_device_naming)
※by-idやby-pathで`-ide-`などを含むから使えないと書かれていますが、KVMなどの仮想化環境では、(ホスト側の設定で固定で割り振った)`-PCI-`などになっているかと思います。

----
ふぅ。