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はページサイズでアライメントされている。
この宛先にセグメントを配置するのは再起動時である。それまでは確保された領域でカーネルイメージが保存された状態になる