hogeとはワイルドカードのようなものです。日々起こった、さまざまなこと −すなわちワイルドカード− を取り上げて日記を書く、という意味で名付けたのかというとそうでもありません。適当に決めたらこんな理由が浮かんできました。
08/19/2023 ほげ [長年日記]
■ [Gentoo][小ネタ] systemd な Gentoo で kdump
最近どうも自宅デスクトップ PC の調子が悪く,たまに (たぶん) kernel がクラッシュして止まってしまうことがある.使ってない時に止まってることもあるし,使ってる時に止まることもある. ほぼ X を起動しているので trace が見えず,何が原因なのかよく分からないなあ,などと悠長に思っていたのだけれど,どうも頻度が上がってきたような気がするので,重い腰を上げて,まずは原因を探れるように環境を整えることにした.
とりあえずは trace だけ見えればいいから netconsole でログだけどっかに飛ばすか,などと思ったのだけれど,よく考えたら自宅に常時稼働な syslog サーバなんかなかったので,これは断念.
PC 1台で完結するために選択肢に上がるのが kdump になる. 予め専用に確保しておいたメモリ領域に dump-capture kernel イメージをロードしておき,クラッシュ時にこれを実行する.その際クラッシュした kernel のメモリイメージが /proc/vmcore として見える状態になるので,これを保全した後で安全に reboot すれば良い,というもの.
この dump-capture kernel はなるべく小さい方が望ましいのだけれど,今回は面倒くさいので普段使っている kernel をそのまま使うことにする. Gentoo で single kernel で kdump するには,基本的には Kernel Crash Dumps (Gentoo Wiki) に従って環境を整えれば良いのだけれど,このドキュメントは少し古めの kernel について書かれているのと,OpenRC 用に書かれているので,そこをちょっとだけ工夫する. ちなみにこのドキュメントでは crashkernel=64M となっているが,今回の環境には小さすぎるようなので 512M にしておいた (これが小さいと,dump-capture kernel 上で動く systemd-udevd 等の daemon が OOM で死んだりしてまともに動かなかった).
まず kernel のコンフィグ. CONFIG_DEBUG_INFO=y とするのは良いのだけれど,最近の kernel ではそれに加えて DWARF のバージョンを選択することになっているようなので, "Rely on the toolchain's implicit default DWARF version" (CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y) とする.
次いで OpenRC の部分を systemd 化する. runscript で行われていることを systemd.service(5) で代替すれば良いので,下記のような service unit を適当に作って enable する.
$ cat /etc/systemd/system/kdump-load.service [Unit] Description=Load the second kernel for kdump After=boot.mount [Service] Type=oneshot ExecStart=/bin/bash -x -c '. <(sed -e "s/ /\\n/g" /proc/cmdline | grep =); kexec -p /boot$${BOOT_IMAGE} --append="root=$${root} single irqpoll maxcpus=1 reset_devices"' [Install] WantedBy=multi-user.target
普段使いの kernel で dump-capture kernel をロードしておく必要があるので,multi-user.target に突っ込んでおく. なおここで /boot から kernel のイメージを読み込む必要があるので,/boot パーティションが分かれている場合は注意.
次に,実際にクラッシュした時に動き出すことを想定した service unit を用意する.
$ cat /etc/systemd/system/kdump-save.service [Unit] Description=Save the vmcore when the kernel crashes ConditionFileNotEmpty=/proc/vmcore [Service] Type=oneshot ExecStart=/bin/bash -x -c 'd="$$(date +%%Y%%m%%d-%%H%%M%%S)"; cp --sparse=always /proc/vmcore "/var/crash/vmcore.$${d}" && reboot' [Install] WantedBy=rescue.target
単に /proc/vmcore を保全して reboot するだけ. /var/crash ディレクトリは予め作っておくこと. dump-capture kernel は single mode で起動するように指定しているので,rescue.target に突っ込んでいる. システムによっては emergency.target を利用しても良いかも知れない (この場合 crashkernel= のサイズが小さくても大丈夫かも). rescue.target や emergency.target 等の systemd ターゲットについては systemd.special(7) を参照のこと.
ここまで出来たら後はテスト. Kernel Crash Dumps (Gentoo Wiki) にも書かれている通り /proc/sysrq-trigger に "c" を書き込むとシステムがクラッシュするので,sync(1) した後で実行してみよう. クラッシュした後すぐに dump-capture kernel が起動し,kdump-save.service が動いて /var/crash 以下に vmcore が保全されて reboot が行われたら成功. ちなみに vmcore ファイルは搭載物理メモリ量と同じサイズなのでかなり大きい.保全には結構時間がかかる.
ここまでで vmcore ファイルを保全することはできたけれど,では実際にここから「何が起きていたのか」を知るにはどうすれば良いか. vmcore の解析といえば言わずもがな crash コマンド. Gentoo にも dev-util/crash としてパッケージが存在するのだけれど,なぜか ~ になっているので,accept_keywords に追加する等してから emerge する. このコマンドを使えば gdb ベースのデバッガが起動するので,あとは log とか bt とか打てば trace を見ることができる.
# crash /usr/src/linux/vmlinux /var/crash/vmcore.20230818-171346 crash 8.0.3 Copyright (C) 2002-2022 Red Hat, Inc. Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation Copyright (C) 1999-2006 Hewlett-Packard Co Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. Copyright (C) 2005, 2011, 2020-2022 NEC Corporation Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. Copyright (C) 2015, 2021 VMware, Inc. This program is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Enter "help copying" to see the conditions. This program has absolutely no warranty. Enter "help warranty" for details. GNU gdb (GDB) 10.2 Copyright (C) 2021 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... KERNEL: /usr/src/linux/vmlinux [TAINTED] DUMPFILE: /var/crash/vmcore.20230818-171346 CPUS: 8 DATE: Fri Aug 18 17:13:34 JST 2023 UPTIME: 00:01:16 LOAD AVERAGE: 0.28, 0.13, 0.05 TASKS: 180 NODENAME: hostname RELEASE: 6.1.41-gentoo VERSION: #4 SMP PREEMPT_DYNAMIC Fri Aug 18 15:57:01 JST 2023 MACHINE: x86_64 (3400 Mhz) MEMORY: 31.9 GB PANIC: "Kernel panic - not syncing: sysrq triggered crash" PID: 550 COMMAND: "bash" TASK: ffff8881026bc000 [THREAD_INFO: ffff8881026bc000] CPU: 6 STATE: TASK_RUNNING (PANIC) crash> bt PID: 550 TASK: ffff8881026bc000 CPU: 6 COMMAND: "bash" #0 [ffffc90000b83c80] machine_kexec at ffffffff810dbbcc #1 [ffffc90000b83cd0] __crash_kexec at ffffffff8126a615 #2 [ffffc90000b83d90] panic at ffffffff823d8995 #3 [ffffc90000b83e10] sysrq_handle_crash at ffffffff819a6451 #4 [ffffc90000b83e18] __handle_sysrq.cold at ffffffff82405783 #5 [ffffc90000b83e48] write_sysrq_trigger at ffffffff819a6eff #6 [ffffc90000b83e58] proc_reg_write at ffffffff8147dc00 #7 [ffffc90000b83e70] vfs_write at ffffffff813f36a0 #8 [ffffc90000b83f00] ksys_write at ffffffff813f3c6e #9 [ffffc90000b83f38] do_syscall_64 at ffffffff82469cea #10 [ffffc90000b83f50] entry_SYSCALL_64_after_hwframe at ffffffff8260009b RIP: 00007f836d5b8b50 RSP: 00007fff8375c3a8 RFLAGS: 00000202 RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007f836d5b8b50 RDX: 0000000000000001 RSI: 000055f0fe7bed70 RDI: 0000000000000001 RBP: 00007f836d68f780 R8: 0000000000000007 R9: 000055f0fe8b8200 R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000001 R13: 000055f0fe7bed70 R14: 0000000000000a68 R15: 0000000000000001 ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b