Ubuntu Weekly Recipe

第673回 カーネルのクラッシュ情報を取得する

この記事を読むのに必要な時間:およそ 4 分

Linuxカーネルも人類が生み出したものである以上,既知であれ未知であれなんらかの不具合を抱えています。そしてそれは「都合の悪い時」に限って顕在するものです。今回は「やたらとカーネルがフリーズする」不幸な星のもとに生まれた人に向けて,カーネルがクラッシュしたときのデバッグ方法を紹介しましょう。

カーネルだってつらいときはあるんです

Linuxカーネルには「クラッシュダンプ」と呼ばれる仕組みが存在します。これはカーネルがどうしようもない自体に陥ったとき(=panicしたとき⁠⁠,システムを再起動する前に障害収集用のシステムを起動し,現象発生直後のカーネルのメモリーをストレージに保存する機能です。これを使えば,panic時の原因を追求することが可能です※1⁠。

※1
より正確に言うと「原因追求が可能なケースも運が良ければ存在すると思っておくといいかもしれない」ぐらいです。

UbuntuをはじめとするLinuxディストリビューションにとって,Linuxカーネルはまさに「縁の下の力持ち」と言える存在です。

ハードウェア・ファームウェアに関わるあれやこれやを一手に引き受けることで,機種や世代による細々とした違いを吸収し,新しいハードウェアのサポートを行い,ハードウェア固有のよくわからない不具合を可能な限り隠蔽してくれます。Linuxディストリビューションが広く使われ,さまざまなアプリケーションが登場しているのも,ひとえにLinuxカーネルのおかげと言っても過言ではないでしょう。

言い方を変えると,⁠コンピューターに関するめんどくさいこと」の大半はカーネルに押し付けていることになります。普段から面倒事を押し付けられる人ならわかってもらえると思うのですが,これは結構なストレスです。もちろん調子のいいときならある程度なんとかできるものの,そういうことが続くと気持ちがつらくなってきますし,そのうち爆発してしまうこともあるでしょう。これはカーネルだって同じです。

  • ひたすらスピンロックで待ち続けるお行儀の悪いサードパーティのドライバー
  • 設定が悪いとひたすら割り込みし続けるデバイス
  • 変なトランザクションを受けるとSoCごと停止するコントローラー
  • ソフトリセットかけるとNMI panicを誘発するデバイス
  • リードするとたまに仕様と全然違う値が返ってくるレジスタ
  • 意味もなくメモリーを確保しながらCPU負荷を上げ続けるユーザープロセス

カーネルはできる限り「なんとかしよう」「がんばる」わけではありますが,どうしようもないときはもう「どうしようもない」と言うしかないんです。しかも状況によっては「どうしようもない」と伝える術すら奪われているケースもしばしば存在します。しかしながら,どれもユーザーから見ると「なんかカーネルが固まった」としか見えないため,だいたい「カーネルが悪い」の一言で済まされます。よくある中間管理職の悲哀ですね。

本来はより上位に位置するシステム管理者が,カーネルの状況を把握し不調のサインを見つけたら随時ケアするのが理想です。ただ,よっぽど優秀な組織でない限りは,上位の管理者が下位の存在に対して,日常的にこまめな管理・配慮をすることはありません。よって結果的に「問題が起きてから対応する」という結果にならざるを得ないのです※2⁠。

※2
カーネルの不具合に遭遇したときの話です。

前置きが長くなりましたが,今回はカーネルの「クラッシュダンプ」システムを利用して,⁠問題が起きたときに原因を追求する」方法を紹介します。

情報の引き継ぎは重要です

問題が起きたときにやるべきことは,現象発生時の状況の把握です。たとえばどんな操作したときに発生したのかとか,どんなエラーログが残っているのか,再現性はあるのかとか,そのような情報が必要になります。しかしながらカーネルにおいて回復不能なトラブルが発生した場合,再起動する以外に手は存在しません。つまりなんとかして,再起動後に「問題発生時の情報を引き継ぐ」必要があるのです。

Ubuntuには「Apport」と呼ばれる障害情報収集システムが存在します。これはユーザープロセスがコアダンプしたとき,その中身やプロセスの情報をまとめて,必要に応じてUbuntuのチケットトラッキングシステムであるLaunchpadに報告する仕組みです。Ubuntu 12.04 LTSあたりから,常に有効化されるようになったので,⁠なんかプロセスが落ちた」ときに「残念ながら内部エラーが発生しました」というダイアログを見たことがある人も多いでしょう。

「ユーザープロセスが死ぬ」状態であればカーネルがケアすることは可能です。しかしながら「カーネル内部に問題がある」ときは,カーネル側ではどうしようもないことが多々あります。さらに「問題が起きたことを通知する」方法も限られます。運が良ければコンソールに何か出力することが可能ですが,最近のLinuxシステムだとカーネルメッセージをディスプレイに表示していることは稀です。そこで出てくるのが「クラッシュダンプ」システムです。

Linuxカーネルにはkexecと呼ばれる仕組みが存在します。これはメモリー上にカーネル本体とinitramfsをあらかじめ展開しておき,このカーネルとinitramfsに処理を移す仕組みです。仕組みと見た目上はカーネルの再起動になるのですが,ハードウェアの初期化やUEFI/BIOS,ブートローダーの処理を飛ばせるので「高速な再起動」になります。また,極端な言い方をすると「メモリー上の特定の場所にジャンプする」だけで実現できるので,ストレージが動かないような状況でも実行できます※3⁠。

※3
実際は,ジャンプ前にきちんと後処理をしておかないと,再起動中に変なDMAアクセスや割り込みが発生してうまく起動できなくなります。もちろん誰かがずっとCPUを握り続けているような状況だとジャンプ処理への移行すらおぼつきません。

クラッシュダンプシステムでは,カーネル起動時にあらかじめ障害情報収集用のカーネル(クラッシュカーネル)とinitramfs用のメモリー領域をあらかじめ確保しておき,panic時にはそのカーネルを起動するようになっています。これによりpanic時のカーネルメモリーの中身がほぼそのままの状態でクラッシュカーネルが起動します。クラッシュカーネル側は,それを任意のストレージに保存することで,⁠問題発生時の現場」を保存できるわけです。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。