VPN クライアントの起動は都合のよい時刻の目印であって原因ではなく、その区別が次に何が起きるかを決めます。その瞬間の前後でカーネル Oops が起きたとき、選ぶべきは使える障害報告を集めることか、実運用機で同じクラッシュをさらに五回起こすことかです。再起動の前に、正確なカーネルビルド、最初の障害トレース、taint の状態、そして同じ分に変わったその他すべての短い説明という四つを保存します。残りは解釈であり、解釈は証拠が安全な場所に置かれるまで待てます。

最後の行ではなく最初の障害を捉える

後続の障害はすでに不健全なカーネルによる二次的な被害かもしれないため、ログの最初の Oops こそが重要です。ヘッダーには障害を起こした命令とコード経路を特定するレジスタ状態が含まれているので、呼び出しトレースと一緒にコピーしてください。最後の行から始まる報告は、一週間後に読む人にとってほとんど価値がありません。

マシンがすでに再起動していても、前回起動のカーネルバッファーは、その時点で永続ストレージが有効だった場合に限り、多くの場合ジャーナルに残っています。二度目の再現は必要なものを上書きする可能性があるので、作業負荷を再現するのではなく保存済みのファイルから読んでください。再起動をまたいでジャーナルを保持できない環境では、シリアルコンソールか netconsole だけが障害を可視化する手段です。

シンボルを読む前にビルドを固定する

関数名とオフセットは、それらを生み出したバイナリに対してのみ意味を持つので、カーネルのリリース文字列とディストリビューションのビルド識別子を一緒に記録します。別のビルドのシンボルファイルは、まったく自信たっぷりに間違った行を指すため、シンボルがまったくないより悪い状況です。ディストリビューションは多くのものをバックポートするので、上流の番号だけでなくカーネルパッケージの版を残します。

ツリー外のモジュールは、taint されたカーネルが保守担当者の下せる結論を制限するため、記録に独自の行を持つべきです。モジュール一覧から推測するのではなく、taint の値を読み取ってください。

ゼロでない taint は告発ではなく、報告を無価値にもしません。これは障害時の読み込み済みコンポーネントを読者に伝え、一部のフラグは判断ではなく方針によって報告の優先度を下げさせます。値、モジュール名、そして同じハードウェアと作業負荷がそれらなしでカーネルを動かしたことがあるかどうかを記録します。この最後の比較こそが、新しい回帰と長年のバグを分けます。

引き金と欠陥を切り分ける

トンネルの起動は通常、ネットワークドライバー、キューイング規律、オフロード機能、電力状態といったすでに存在していた経路を使います。引き金は障害がいつ現れるかを説明するもので、どのコードが誤っているかではなく、引き金を原因として扱うと何も直らない設定変更を連鎖させます。

以前のイメージが動くことは証拠であって、証明ではありません。比較するときは起動ごとに一つのコンポーネントだけを変え、結果はマシンより長く残る場所に保管します。

保守担当者が実際に使えるものを確認する

送る前に、部外者が読むように報告を読んでください。設定、正確な手順、ビルドの同一性がそろい、認証情報が消えていれば、その報告は使えます。スタックトレースのスクリーンショットであれば、同じ情報を求めて返ってきます。カーネルのバグ探しガイドには、有用なトレースと対応するシンボルがどんなものか書かれています。

uname -r
cat /proc/sys/kernel/tainted
journalctl -k -b -1 --no-pager | sed -n '/BUG:/,/Call Trace/p'
dmesg -T | grep -A 40 'RIP:'

上のコマンドはいずれも状態を読むだけで、マシンがまだ応答できるなら最初の二つは次の再起動の前に実行すべきです。ジャーナルが永続しない環境では、その二つだけが今後も機能します。

鍵、パスワード、無関係な通信は伏せますが、トレースを読むために必要な関数名とオフセットは残します。資料はディストリビューションやカーネルに該当する報告経路で送り、ホスト名を添えた公開の貼り付けは使いません。その後は、一致するビルドに対する位置特定済みの障害だけが報告を前進させるので、さらなるクラッシュを集めるのではなく質問を待ちます。何も返ってこない場合の代替は、予備のハードウェアでの統制された再現であり、他の人が依存するマシンでは決して行いません。

関連記事