kexec、kdump

kexec/kdumpについて調べている。
Kexecはウォームブートといって電源を落とさずに再起動するツール。Linuxカーネルのメインラインに入っている。
Kdumpはカーネルクラッシュの際にkexecで新しいカーネルを起動して、ダンプ内容からデバッグを行うツール。

Kexecを利用するにはカーネルオプションを有効にする(最近はデフォ?)。そしてyumなどでkexec-toolsをインストールすれば使える。
kexecはkexec-toolsとシステムコールが協力することで可能となっている。
ソースコードを読むときはkexec-toolsのkexec/kexec.cのmain()がエントリポイントになる

kexecの動作

kexec-tools
起動前にkexec-toolsでカーネルを読み込んでおく、例えばこんな感じ

$ sudo kexec -l /boot/vmlinuz-2.6.38-8-generic --initrd=/boot/initrd.img-2.6.38-8-generic

引数にカーネルとinitrdに取る。カーネルに渡すカーネルオプションもここで渡せる(はず)
kexec-toolsはカーネルのelfヘッダの情報を読み、これを以下の構造体で表されるセグメントに分割して読み込む。
読み込んだら、このセグメントを引数にしてシステムコールを呼び出し、カーネルの中のkexecを呼び出す。

struct kexec_segment {
		 void *buf;
		 size_t bufsz;
		 void *mem;
		 size_t memsz;
};

bufとbufszはユーザ空間上のバッファー(セグメントが入っている)とそのサイズを表し、
memとmemszはセグメントの最終的な宛先が入っている。
この後rebootすれば、マシンのシャットダウンの代わりにkexecが実行される。

試しにkexec-toolsの中でシステムコールに渡されるセグメントの各メンバを表示していみた

nr_segments = 4
segment[0].buf   = 0x15ce9b0
segment[0].bufsz = 447c
segment[0].mem   = 0x3000
segment[0].memsz = 5000
segment[1].buf   = 0x15c6890
segment[1].bufsz = 80e0
segment[1].mem   = 0x95000
segment[1].memsz = a000
segment[2].buf   = 0x7faf973fb410
segment[2].bufsz = 216300
segment[2].mem   = 0x100000
segment[2].memsz = 217000
segment[3].buf   = 0x7faf98409010
segment[3].bufsz = 1b2a4d
segment[3].mem   = 0x7fe4c000
segment[3].memsz = 1b3000

buf、bufszのアドレス(ユーザメモリ)は何のアライメントもされていないが、宛先アドレスであるmem、memszはページサイズでアライメントされている。
この宛先にセグメントを配置するのは再起動時である。それまでは確保された領域でカーネルイメージが保存された状態になる