ダンプの解析をするためには実際のダンプがなければ話が始まりませんので、今回は、ダンプの取り方を簡単に説明します。
本講座では、プラットホームとして、Redhat Enterprise Linux 5(以下RHEL5)を例に取って、解説を進めていきます。RHEL5を使用するのは、ダンプを取るまでの設定が簡単であることと、ダンプの解析環境が整っていることが理由です。
RHEL5のカーネルは、2.6.18をベースにしています。2.6.13からサポートされたkdumpというダンプ採取機能が使えます。
ダンプを取るための設定から、実際にダンプを取るまでの手順は以下のとおりです。

1 kdumpの設定
# system-config-kdump
「kdumpを有効にする」にチェックをする。
# chkconfig kdump on

2 リブート
最初に設定したときは、リブートする必要があります。

3 ダンプの採取
# echo 1 > /proc/sys/kernel/sysrq
# echo c > /proc/sysrq-trigger

システムが再起動した際に、
/var/crash/日付ディレクトリの下にvmcoreという名前でダンプが取れているはずです。

# ls /var/crash
2007-09-05-09:52
# ls -l /var/crash/2007-09-05-09:52
total 868484
-r——– 1 root root 937493152 Sep 5 09:53 vmcore
#

これでダンプの準備ができました。
念のために、ダンプを取れない人のためにサンプルを用意しました。以下のURLからダウンロードしてください。

http://people.valinux.co.jp/~oda/dump-analysis/sample-dump-1.tar.gz

内容物は以下のとおりです。ダンプ以外にも解析を行うために必要となるファイルも同梱してあります。

 

  • System.map-2.6.18-8.el
  • vmcore
  • vmlinux

ダンプを取る仕組み

さて、今回はダンプの準備が主眼ですが、何事も原理を知っておくことは重要ですので、ダンプを取る仕組みについて、簡単に触れておきます。(実装の詳細は、別講で紹介する機会もあるかと思います。)
kdumpの最大の特徴は、ダンプの採取を運用で使用していたのとは別のカーネルで行うことです。ここでは便宜的に運用で使用するカーネルをファーストカーネル、ダンプを採取するカーネルをセカンドカーネルと呼びます。
ファーストカーネルは、予めセカンドカーネル用のメモリ領域をリザーブし、そこにセカンドカーネルをロードしておきます。(図1参照)

  • ダンプ採取ルートが壊れた管理データを参照してしまう
  • リソース不足でダンプ採取ルートが動けない
  • ダンプ採取ルートで必要なリソースがロックされている

ファーストカーネルが異常を検知し、処理続行不可能と判断すると、セカンドカーネルを起動します。セカンドカーネルは、予めリザーブされた領域のみを使用して動作します。つまり、ファーストカーネルが使用していたメモリには手を付けません。但し、参照は全メモリについて行うことができます。セカンドカーネルの動作の元、メモリの内容をディスクに退避します。
この方式の良い点は、異常の起きたファーストカーネルの制御構造とは無関係にダンプの採取が実行されることです。ファーストカーネルがダンプ採取を実行しようとすると、以下に示すような、いろいろな”罠”が待っています。

そのため、ダンプ採取に失敗するケースが多々あったわけです。また、ダンプ採取ルートの実行により、見たかった制御データを上書きしてしまうこともあります。kdumpの方式ではそうした問題がなくなります。(※1)

ダンプ採取の設定と流れ

ダンプ採取の設定から実際の採取までの流れについても、簡単に見ておきます。処理を理解する助けになると思います。処理の詳細については、みなさんの自習課題としておきましょう。
まず、セカンドカーネル用の領域の確保から始めましょう。この領域は、カーネルの起動時パラメタの指定により確保されます。以下は、/etc/grub/grub.confの記述例ですが、「crashkernel=128M@16M」の部分がその指定部分に当たります。この記述例は、16MBのアドレスから128MB分の領域を確保することを意味しています。セカンドカーネル用の領域は、ファーストカーネルの起動処理時にリザーブされます。

title Red Hat Enterprize Linux AS 5 (2.6.18-8.el5)
root (hd0,7)
kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/1 rhgb quiet 
crashkernel=128M@16M
initrd /boot/initrd-2.6.18-8.el5.img

次にセカンドカーネルのロードについてです。RHEL5の場合、/etc/init.d/kdumpスクリプトの中で行われます。このスクリプトに関連して、/etc/sysconfig/kdumpファイルが様々なパラメタ定義のために使用されています。このスクリプトの中の最も重要な部分は、kexecコマンドの実行です。セカンドカーネルのロードは、kexecコマンドで行うのです。kexecコマンド、およびkdump全体については、カーネルソースのDocumentation/kdump/kdump.txtも参考になります。
セカンドカーネルがロードされているかどうかは、/sys/kernel/kexec_crash_loadedを参照すれば分かります。1であれば、ロードされています。

t# cat /sys/kernel/kexec_crash_loaded
1

ここまでできていれば、ファーストカーネルに異常が起きたときに自動にセカンドカーネルが起動されることになります。また、ダンプの採取は、手動で起動することもできます。それには、「Sysrq-c」キーを押下します(前記のように「echo c > /proc/sysrq-trigger」も同等です)。システムハングが生じた場合でも、キーボードがまだ反応すれば、このようにしてダンプを取ることが可能です。
セカンドカーネルでは、どのようにダンプを取っているのでしょうか?
実は、セカンドカーネル自体は何もしていません。セカンドカーネルでは、システムの全メモリを/proc/vmcoreファイルを通して見ることができます。したがって、実際には、cpコマンドやddコマンドを使用して、/proc/vmcoreファイルの内容をディスクに退避することになります。
RHEL5では、/etc/init.d/kdumpスクリプトで行っています。/etc/init.d/kdumpスクリプトでは、ファーストカーネルが立ち上がっているのか、セカンドカーネルが立ち上がっているのかを、/proc/vmcore の大きさが0か0でないかで区別しています。
参考までに、RHEL5では、セカンドカーネルは、ファーストカーネルと同じものを使用しています。initrdについては、セカンドカーネル用にファーストカーネルとは別のものを使用します。セカンドカーネル用のinitrdは、最初に「/etc/init.c/kdump start」
を実行したときに生成されます。(※2)

  • ※1 但し、弱点もないわけではありません。ファーストカーネルからセカンドカーネルを起動するとき、デバイスの終了処理などは動きません(動かすことによりダンプが取れなくなるリスクを避けるため)。そのため、セカンドカーネル起動時に各種ドライバが初期化を行う際にデバイスの状態がドライバの予期していないものであることがあります。ドライバの作りが悪いと、ここでカーネルがこけてしまう状況が発生します。この点は、本来、ドライバの初期化処理を修正すべき問題ですので、問題のあるドライバについては修正するという方針で徐々に対策が進んでいっています。
  • ※2 ダンプの退避については、initramfsやinitrdの中で行うことも考えられます。RHEL5でも将来のアップデートでそうしてくると予想されます。なお、ダンプの退避をinitramfs(initrd)で行い、また、セカンドカーネルとして、必要最小限の機能に絞ったカスタムカーネルを用意すれば、セカンドカーネル用のリザーブ領域の大きさをずっと小さくすることができます。そのあたりの技については、別講で紹介する機会もあるでしょう。