genkernelで作成したinitramfsがOut Of Memoryで起動しないことへの対処
背景
私は今のラップトップPCでは以下のようなコマンドでinitramfsを作っていました。
alias genkernel-update='sudo genkernel --no-lvm --btrfs --luks --firmware initramfs && grub-update'
カーネル直接起動ではなく、 initramfsを使っている理由は、 rootのBtrfsによるソフトウェアRAIDと暗号化を使っていることです。
dracutではなくgenkernelをinitramfsの生成に使っている理由は、 BtrfsのRAIDで使うデバイスがそれぞれdm-cryptで暗号化されていることです。 genkernelでは、 694778 – sys-kernel/genkernel initramfs support for multiple crypt_roots で示された、 duxsco/gentoo-genkernel-patches: sys-kernel/genkernel initramfs support for multiple crypt_roots and crypt_swaps のパッチによって複数の暗号化デバイスの解除をサポートしています。
少し前は、 Sabayon/genkernel-next: An improved and modern remake of Gentoo genkernel (in: udev, plymouth; out: cross compiler support) を使っていてこれも似たようなサポートをしていたのですが、公式portageから削除されてしまったのでgenkernel本流にパッチが当たったものに乗り換えました。
もしかするとdracutでもcrypttabなどで対応しているのかもしれませんが、とりあえずgenkerelで起動できるので特に移行の必要性は感じていませんでした。
問題
とある日カーネルをアップデートすると、起動時にout of memory
エラーが発生してOSが起動しなくなりました。
grubで前のカーネルを参照すると正常に起動できたので見てみたところ、確かにinitramfsのサイズが増えています。
しかし、増えていると言っても合計で300MB前後を左右していたので、 32GBのメモリを備えている自分のラップトップPCでメモリ不足になるのだろうか? と疑問でした。
その時は何度かinitramfsを作り直すことで問題なくブート出来るようになったので放置したのですが、またアップデートした時に起きてしまったので、ちゃんと調査しようと思いました。
原因
initramfsにファームウェアを全部xz圧縮でコピーしているのが原因です。 xzが解けるとファームウェアのサイズがメモリ量を超えたりするんですかね?
--firmware
オプションを消すとwifiが動かなくなる
では--firmware
オプションを消せば問題ないのだな、と思って消してみました。
そしたらinitramfsのサイズは20MB程度の超軽量になりました。
しかしそれを行うと、 iwlwifiによるWi-Fi通信が行えなくなります。
ファームウェアが読み込まれなくなりますからね。 initramfsの起動後に読み込んで欲しいのですが。
iwlwifi - Gentoo Wiki
を見てモジュール化などがちゃんと行われていることを確認します。
Gentoo Forums :: View topic - [SOLVED] iwlwifi fails to load after upgrade to 3.17.0
を見てCONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
とします。
そうするとmodprobe iwlwifi
するとWi-Fiが動くようになります。
動くのは良いんですが、起動時に動いてくれないとxmobarとかがネットワークの観測を諦めてしまうので起動時に迅速に有効になってほしい。
解決策1: modprobe.confに記述する
有効になるスピードが遅そうだなあと思って却下。実際に手動でmodprobe iwlwifi
した時も無線が有効になるにはちょっとタイムラグがあるんですよね。
解決策2: --firmware
オプションを有効にして、savedconfigで不要なファームウェアを除去する
ハードウェアは追加・変更されうるので、必要なファームウェアを絞るのが難しいので却下。組み込まれるだけではなく、ルートのファイルシステムのファームウェアにも影響してきそうですし。
解決策3: iwlwifiだけカーネルに組み込んでしまう
Device Drivers
-> Generic Driver Options
-> Firmware loader
でiwlwifiのファームウェアだけ組み込んでしまうことにしました。
これはこれで負けた気はしますが、動作には全く問題ないので問題ないとします。
急に別のハードウェアが来ても途中からの読み込みならファームウェアがユーザ側で読み込まれるので多分問題ないでしょう。まあそういうのは結局カーネルを再コンパイルする必要があるのかもしれませんけど。
副産物: 起動が速くなった気がする
xz圧縮されてるinitramfsが300MBから20MBぐらいになった影響なのか、 initramfsの構築が爆速になって、起動も少し速くなった気がします。