###導入###
kdump は、クラッシュした Linux カーネル ダンプを取得する方法の 1 つですが、その使用方法と内部構造を説明するドキュメントを見つけるのが少し難しい場合があります。この記事では、kdump の基本的な使用法と、kdump/kexec がカーネルにどのように実装されるかを学習します。
kexec は、最初のカーネルのコンテキストから 2 番目のカーネルへのブートを支援する Linux カーネル間のブートローダーです。 kexec は、BIOS またはファームウェア段階をバイパスして最初のコアをシャットダウンし、2 番目のコアにジャンプします。したがって、BIOS ステージを使用しない場合、再起動が高速になります。
kdump は kexec アプリケーションで使用できます。たとえば、最初のカーネルがクラッシュすると 2 番目のカーネルが起動し、2 番目のカーネルを使用して最初のカーネルのメモリ ダンプをコピーしたり、gdb を使用してクラッシュしたりできます。 . このツールはクラッシュの原因を分析します。 (この記事では、現在実行中のカーネルとして「最初のカーネル」、kexec で実行中のカーネルとして「2 番目のカーネル」、および現在のカーネルがクラッシュしたときに実行中のカーネルを意味する「キャプチャ カーネル」という用語を使用します。)
kexec メカニズムには、ユーザー空間だけでなくカーネルにもコンポーネントがあります。カーネルは、kexec 再起動機能用のいくつかのシステム コールを提供します。 kexec-tools と呼ばれるユーザー空間ツールはこれらの呼び出しを使用し、「2 番目のカーネル」をロードしてブートするための実行可能ファイルを提供します。一部のディストリビューションでは、kexec-tools にラッパーを追加しています。これは、さまざまなダンプ ターゲット構成のダンプをキャプチャして保存するのに役立ちます。この記事では、アップストリームの kexec ツールとディストリビューション固有の kexec-tools コード間の混乱を避けるために、distro-kexec-tools というツールを使用します。私の例では、Fedora Linux ディストリビューションを使用します。
Fedora kexec-tools ツール
dnf install kexec-tools コマンドを使用して、fedora マシンに fedora-kexec-tools をインストールします。 fedora-kexec-tools をインストールした後、systemctl start kdump コマンドを実行して kdump サービスを開始できます。このサービスが開始すると、ターゲットの場所にマウントされるリソース、vmcore を保持するリソース、および vmcore をターゲットの場所にコピーしてダンプするコマンドを含むルート ファイル システム (initramfs) が作成されます。次に、サービスはカーネルと initramfs をクラッシュしたカーネル領域内の適切な場所にロードし、カーネルがクラッシュした場合に実行できるようにします。
Fedora ラッパーは 2 つのユーザー設定ファイルを提供します:
/etc/kdump.conf は、変更後に再構築する必要がある構成パラメーターを指定します。たとえば、ダンプ ターゲットをローカル ディスクから NFS マウントされたディスクに変更する場合は、Capture Kernel によってロードされた NFS 関連のカーネル モジュールが必要です。
/etc/sysconfig/kdump は、変更後に initramfs を再構築する必要のない構成パラメーターを指定します。たとえば、「キャプチャ カーネル」に渡されるコマンド ライン パラメータのみを変更する必要がある場合は、initramfs を再構築する必要はありません。
kdump サービスの開始後にカーネルが失敗した場合は、「キャプチャ カーネル」が実行され、initramfs で vmcore 保存プロセスがさらに実行され、安定したカーネルに再起動されます。
kexec-toolsツール
kexec-tools のソース コードをコンパイルして、kexec という名前の実行可能ファイルを取得します。この名前の付いた実行可能ファイルは、「2 番目のカーネル」をロードして実行したり、カーネルがクラッシュしたときに実行できる「キャプチャ カーネル」をロードしたりするために使用できます。
「2 番目のカーネル」をロードするコマンド:
リーリー
--reuse-command パラメーターは、「最初のカーネル」と同じコマンド ラインを使用することを示します。 --initrd を使用して initramfs を渡します。 -l は、kexec アプリケーション自体 (kexec -e) によって実行できる「2 番目のカーネル」をロードしていることを示します。 -l でロードされたカーネルは、カーネル パニック時に実行できません。カーネルクラッシュ時に実行できる「キャプチャカーネル」をロードするには、-l の代わりに引数 -p を渡す必要があります。
キャプチャ カーネルをロードするコマンド:
リーリー
echo c > /pros/sysrq-trigger は、テストのためにカーネルをクラッシュするために使用できます。 kexec-tools によって提供されるオプションの詳細については、「man kexec」を参照してください。次のセクションに進む前に、kexec_dump のデモを見てください:
https://www.linuxprobe.com/wp-content/uploads/2017/08/kexec_kdump_demo-iOq_rJhrKhA.mp4
kdump: エンドツーエンドのストリーミング
下の図はフローチャートを示しています。クラッシュカーネルのメモリは、「最初のカーネル」の起動中にキャプチャ カーネル用に予約する必要があります。カーネル コマンド ラインで crashkernel=Y@X を渡すことができます (@X はオプションです)。 crashkernel=256M はほとんどの x86_64 システムで機能しますが、クラッシュカーネルに適切なメモリの選択は、カーネルと initramfs のサイズ、initramfs に含まれるモジュール、アプリケーションのメモリ要件などの多くの要因によって決まります。ランタイム。クラッシュ カーネル パラメーターを渡すその他の方法については、カーネル パラメーターのドキュメントを参照してください。
pratyush_f1.png
您可以将内核和 initramfs 镜像传递给 kexec 可执行文件,如(kexec-tools)部分的命令所示。“捕获内核”可以与“第一内核”相同,也可以不同。通常,一样即可。Initramfs 是可选的;例如,当内核使用 CONFIG_INITRAMFS_SOURCE 编译时,您不需要它。通常,从第一个 initramfs 中保存一个不一样的捕获 initramfs,因为在捕获 initramfs 中自动执行 vmcore 的副本能获得更好的效果。当执行 kexec 时,它还加载了 elfcorehdr 数据和 purgatory 可执行文件(LCTT 译注:purgatory 就是一个引导加载程序,是为 kdump 定作的。它被赋予了“炼狱”这样一个古怪的名字应该只是一种调侃)。 elfcorehdr 具有关于系统内存组织的信息,而 purgatory 可以在“捕获内核”执行之前执行并验证第二阶段的二进制或数据是否具有正确的 SHA。purgatory 也是可选的。
当“第一内核”崩溃时,它执行必要的退出过程并切换到 purgatory(如果存在)。purgatory 验证加载二进制文件的 SHA256,如果是正确的,则将控制权传递给“捕获内核”。“捕获内核”根据从 elfcorehdr 接收到的系统内存信息创建 vmcore。因此,“捕获内核”启动后,您将看到 /proc/vmcore 中“第一内核”的转储。根据您使用的 initramfs,您现在可以分析转储,将其复制到任何磁盘,也可以是自动复制的,然后重新启动到稳定的内核。
内核系统调用
内核提供了两个系统调用:kexec_load() 和 kexec_file_load(),可以用于在执行 kexec -l 时加载“第二内核”。它还为 reboot() 系统调用提供了一个额外的标志,可用于使用 kexec -e 引导到“第二内核”。
kexec_load():kexec_load() 系统调用加载一个可以在之后通过 reboot() 执行的新的内核。其原型定义如下:
long kexec_load(unsigned long entry, unsigned long nr_segments,
struct kexec_segment *segments, unsigned long flags); ログイン後にコピー
用户空间需要为不同的组件传递不同的段,如内核,initramfs 等。因此,kexec 可执行文件有助于准备这些段。kexec_segment 的结构如下所示:
struct kexec_segment {
void *buf;
/* 用户空间缓冲区 */
size_t bufsz;
/* 用户空间中的缓冲区长度 */
void *mem;
/* 内核的物理地址 */
size_t memsz;
/* 物理地址长度 */
}; ログイン後にコピー
当使用 LINUX_REBOOT_CMD_KEXEC 调用 reboot() 时,它会引导进入由 kexec_load 加载的内核。如果标志 KEXEC_ON_CRASH 被传递给 kexec_load(),则加载的内核将不会使用 reboot(LINUX_REBOOT_CMD_KEXEC) 来启动;相反,这将在内核崩溃中执行。必须定义 CONFIG_KEXEC 才能使用 kexec,并且为 kdump 定义 CONFIG_CRASH_DUMP。
kexec_file_load():作为用户,你只需传递两个参数(即 kernel 和 initramfs)到 kexec 可执行文件。然后,kexec 从 sysfs 或其他内核信息源中读取数据,并创建所有段。所以使用 kexec_file_load() 可以简化用户空间,只传递内核和 initramfs 的文件描述符。其余部分由内核本身完成。使用此系统调用时应该启用 CONFIG_KEXEC_FILE。它的原型如下:
long kexec_file_load(int kernel_fd, int initrd_fd, unsigned long
cmdline_len, const char __user * cmdline_ptr, unsigned long
flags); ログイン後にコピー
请注意,kexec_file_load 也可以接受命令行,而 kexec_load() 不行。内核根据不同的系统架构来接受和执行命令行。因此,在 kexec_load() 的情况下,kexec-tools 将通过其中一个段(如在 dtb 或 ELF 引导注释等)中传递命令行。
目前,kexec_file_load() 仅支持 x86 和 PowerPC。
当内核崩溃时会发生什么
当第一个内核崩溃时,在控制权传递给 purgatory 或“捕获内核”之前,会执行以下操作:
准备 CPU 寄存器(参见内核代码中的 crash_setup_regs());
更新 vmcoreinfo 备注(请参阅 crash_save_vmcoreinfo());
关闭非崩溃的 CPU 并保存准备好的寄存器(请参阅 machine_crash_shutdown() 和 crash_save_cpu());
您可能需要在此处禁用中断控制器;
最后,它执行 kexec 重新启动(请参阅 machine_kexec()),它将加载或刷新 kexec 段到内存,并将控制权传递给进入段的执行文件。输入段可以是下一个内核的 purgatory 或开始地址。
ELF 程序头
kdump 中涉及的大多数转储核心都是 ELF 格式。因此,理解 ELF 程序头部很重要,特别是当您想要找到 vmcore 准备的问题。每个 ELF 文件都有一个程序头:
由系统加载器读取,
描述如何将程序加载到内存中,
可以使用 Objdump -p elf_file 来查看程序头。
vmcore 的 ELF 程序头的示例如下:
# objdump -p vmcore
vmcore:
file format elf64-littleaarch64
Program Header:
NOTE off 0x0000000000010000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**0 filesz
0x00000000000013e8 memsz 0x00000000000013e8 flags ---
LOAD off 0x0000000000020000 vaddr 0xffff000008080000 paddr 0x0000004000280000 align 2**0 filesz
0x0000000001460000 memsz 0x0000000001460000 flags rwx
LOAD off 0x0000000001480000 vaddr 0xffff800000200000 paddr 0x0000004000200000 align 2**0 filesz
0x000000007fc00000 memsz 0x000000007fc00000 flags rwx
LOAD off 0x0000000081080000 vaddr 0xffff8000ffe00000 paddr 0x00000040ffe00000 align 2**0 filesz
0x00000002fa7a0000 memsz 0x00000002fa7a0000 flags rwx
LOAD off 0x000000037b820000 vaddr 0xffff8003fa9e0000 paddr 0x00000043fa9e0000 align 2**0 filesz
0x0000000004fc0000 memsz 0x0000000004fc0000 flags rwx
LOAD off 0x00000003807e0000 vaddr 0xffff8003ff9b0000 paddr 0x00000043ff9b0000 align 2**0 filesz
0x0000000000010000 memsz 0x0000000000010000 flags rwx
LOAD off 0x00000003807f0000 vaddr 0xffff8003ff9f0000 paddr 0x00000043ff9f0000 align 2**0 filesz
0x0000000000610000 memsz 0x0000000000610000 flags rwx ログイン後にコピー
在这个例子中,有一个 note 段,其余的是 load 段。note 段提供了有关 CPU 信息,load 段提供了关于复制的系统内存组件的信息。
vmcore 从 elfcorehdr 开始,它具有与 ELF 程序头相同的结构。参见下图中 elfcorehdr 的表示:
pratyush_f2.png
kexec-tools 读取 /sys/devices/system/cpu/cpu%d/crash_notes 并准备 CPU PT_NOTE 的标头。同样,它读取 /sys/kernel/vmcoreinfo 并准备 vmcoreinfo PT_NOTE 的标头,从 /proc/iomem 读取系统内存并准备存储器 PT_LOAD 标头。当“捕获内核”接收到 elfcorehdr 时,它从标头中提到的地址中读取数据,并准备 vmcore。
Crash note
Crash notes 是每个 CPU 中用于在系统崩溃的情况下存储 CPU 状态的区域;它有关于当前 PID 和 CPU 寄存器的信息。
vmcoreinfo
该 note 段具有各种内核调试信息,如结构体大小、符号值、页面大小等。这些值由捕获内核解析并嵌入到 /proc/vmcore 中。 vmcoreinfo 主要由 makedumpfile 应用程序使用。在 Linux 内核,include/linux/kexec.h 宏定义了一个新的 vmcoreinfo。 一些示例宏如下所示:
VMCOREINFO_PAGESIZE()
VMCOREINFO_SYMBOL()
VMCOREINFO_SIZE()
VMCOREINFO_STRUCT_SIZE()
makedumpfile
vmcore 中的许多信息(如可用页面)都没有用处。makedumpfile 是一个用于排除不必要的页面的应用程序,如:
填满零的页面;
没有私有标志的缓存页面(非专用缓存);
具有私有标志的缓存页面(专用缓存);
用户进程数据页;
可用页面。
此外,makedumpfile 在复制时压缩 /proc/vmcore 的数据。它也可以从转储中删除敏感的符号信息; 然而,为了做到这一点,它首先需要内核的调试信息。该调试信息来自 VMLINUX 或 vmcoreinfo,其输出可以是 ELF 格式或 kdump 压缩格式。
典型用法:
# makedumpfile -l --message-level 1 -d 31 /proc/vmcore makedumpfilecore ログイン後にコピー
详细信息请参阅 man makedumpfile。
kdump 调试
新手在使用 kdump 时可能会遇到的问题:
kexec -p kernel_image 没有成功
检查是否分配了崩溃内存。
cat /sys/kernel/kexec_crash_size の値をゼロにすることはできません。
cat /proc/iomem | grep "クラッシュ カーネル" 割り当てられた範囲があるはずです。
割り当てられていない場合は、コマンド ラインで正しい crashkernel= パラメータを渡します。
表示されない場合は、kexec コマンドにパラメーター -d を渡し、出力情報を kexec-tools メーリング リストに送信します。
「最初のカーネル」の最後のメッセージの後、コンソールには何も表示されません (「バイ」など)
kexec -e の後の kexec -l kernel_image コマンドが機能するかどうかを確認します。
サポートされているアーキテクチャまたはマシン固有のオプションが欠落している可能性があります。
煉獄のSHA認証に失敗した可能性があります。アーキテクチャが煉獄のコンソールをサポートしていない場合、デバッグが困難になる可能性があります。
「2 番目のカーネル」がすでにクラッシュしている可能性があります。
システムのearlycon または Earlyprintk オプションを「2 番目のカーネル」コマンド ラインに渡します。
kexec-tools メーリング リストを使用して、最初のカーネルを共有し、カーネルの dmesg ログをキャプチャします。
###リソース###
fedora-kexec-tools
GitHub リポジトリ: git://pkgs.fedoraproject.org/kexec-tools
メールリスト: [email protected]
説明: 仕様ファイルとスクリプトは、さまざまなユーザー シナリオで kexec-tools を自動化できるように、ユーザーフレンドリーなコマンドとサービスを提供します。
kexec-tools
GitHub リポジトリ: git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
メールリスト: [email protected]
説明: カーネル システム コールを使用し、ユーザー コマンド kexec を提供します。
Linux カーネル
GitHub リポジトリ: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
メールリスト: [email protected]
説明: kexec_load()、kexec_file_load()、reboot() システム コールと、machine_kexec() や machine_crash_shutdown() などのアーキテクチャ固有のコードを実装します。
メイクダンプファイル
GitHub リポジトリ: git://git.code.sf.net/p/makedumpfile/code
メールリスト: [email protected]
説明: ダンプ ファイルから不要なコンポーネントを圧縮してフィルタリングします。
(タイトル: ペンギン、ブート、変更: Opensource.com. CC BY-SA 4.0)
###著者について:###
Pratyush Anand - Pratyush は Linux カーネルの専門家として Red Hat と協力しています。彼は、Red Hat 製品およびアップストリームが直面するいくつかの kexec/kdump 問題を担当しています。彼は、Red Hat がサポートする ARM64 プラットフォームに関する他のカーネルのデバッグ、トレース、およびパフォーマンスの問題も扱います。 Linux カーネルに加えて、アップストリームの kexec-tools プロジェクトと makedumpfile プロジェクトにも貢献しました。彼はオープンソースの愛好家であり、教育機関でボランティアの講義を行うことで FOSS を推進しています。