什么是Kdump?
Kdump是一個(gè)基于kexec的內(nèi)核崩潰轉(zhuǎn)儲(chǔ)機(jī)制,當(dāng)系統(tǒng)崩潰時(shí),kdump使用kexec啟動(dòng)到第二個(gè)內(nèi)核。地?zé)醾€(gè)內(nèi)核叫做捕獲內(nèi)核或者又叫“2nd kernel”,它以很少的內(nèi)存啟動(dòng)捕獲內(nèi)核,并捕獲轉(zhuǎn)儲(chǔ)鏡像。Kdump的概念是目前最可靠的內(nèi)核轉(zhuǎn)儲(chǔ)技術(shù),已被主要的linux廠商使用。(例如Red Hat系列)
什么是Kexec?
Kexec是一種能夠根據(jù)已經(jīng)運(yùn)行內(nèi)核的上下文快速啟動(dòng)新內(nèi)核的一種機(jī)制,而不經(jīng)過(guò)BIOS。BIOS的啟動(dòng)在一些大型機(jī)器或者有大量外設(shè)的機(jī)器上時(shí)特別耗時(shí)。這種機(jī)制能夠節(jié)省需要在不同內(nèi)核之間切換的開(kāi)發(fā)人員的時(shí)間。
Kexec在內(nèi)核空間和用戶空間都有對(duì)應(yīng)的組件,內(nèi)核提供了幾個(gè)kexec重啟功能的系統(tǒng)調(diào)用。用戶空間的軟件包"kexec-tools"使用這些系統(tǒng)調(diào)用,并執(zhí)行加載和引導(dǎo)第二個(gè)內(nèi)核(捕獲內(nèi)核)。
Kexec由兩部分組成,一是內(nèi)核空間的系統(tǒng)調(diào)用kexec_load,負(fù)責(zé)在生產(chǎn)內(nèi)核(或者叫第一個(gè)內(nèi)核)啟動(dòng)時(shí)將捕獲內(nèi)核(或者叫第二個(gè)內(nèi)核)加載到指定的位置。而是用戶空間的kexec-tools,它將捕獲內(nèi)核(second kernel)的地址傳遞給生產(chǎn)內(nèi)核(first kernel),讓系統(tǒng)在崩潰的時(shí)候能夠找到捕獲內(nèi)核(second kernel)的地址并運(yùn)行。
Kdump怎么工作?
在當(dāng)前系統(tǒng)發(fā)生崩潰時(shí),新的捕獲內(nèi)核被加載,然后根據(jù)已設(shè)置的命令去將當(dāng)前之前發(fā)生崩潰的系統(tǒng)的內(nèi)存保存到一個(gè)特殊的文件(vmcore)中。
下面以Fedora26做為測(cè)試演示。(Fedora和CentOS系列的系統(tǒng)已經(jīng)在kenrel中打開(kāi)了CONFIG_KEXEC*選項(xiàng)。)
首先需要在系統(tǒng)啟動(dòng)時(shí)預(yù)留出給第二個(gè)內(nèi)核運(yùn)行的內(nèi)存。內(nèi)核參數(shù)"crashkernel=160M"會(huì)在系統(tǒng)啟動(dòng)時(shí)預(yù)留出160M內(nèi)存的空間給捕獲內(nèi)核運(yùn)行使用。"crashkerel=xM"還支持其他的參數(shù),詳細(xì)的可以參考內(nèi)核參數(shù)文檔 內(nèi)核參數(shù)。
# dmesg | grep -i reserving
[ 0.000000] Reserving 160MB of memory at 656MB for crashkernel (System RAM: 2047MB)
系統(tǒng)啟動(dòng)后我們可以從上面的命令中看到已經(jīng)預(yù)留出了160M的內(nèi)存從內(nèi)存的656M處。
安裝用戶態(tài)的包"kexec-tools",軟件包中會(huì)提供kdump所需的服務(wù)和"kexec"快速內(nèi)核啟動(dòng)命令,和壓縮過(guò)濾內(nèi)存的"makedumpfile"命令。
[root@localhost ~]# dnf install -y kexec-tools
配置,修改kdump相關(guān)的配置文件。
[root@localhost ~]# grep -v ^# /etc/kdump.conf
path /var/crash
core_collector makedumpfile -l --message-level 1 -d 31
[root@localhost ~]# grep -v ^# /etc/sysconfig/kdump
KDUMP_KERNELVER=""
KDUMP_COMMANDLINE=""
KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug quiet"
KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug transparent_hugepage=never nokaslr"
KEXEC_ARGS=""
KDUMP_IMG="vmlinuz"
KDUMP_IMG_EXT=""
配置文件/etc/kdump.conf設(shè)置了kdump發(fā)生時(shí)vmcore文件的存儲(chǔ)方式,此文件修改后需要重啟kdump的服務(wù)。
配置文件/etc/sysconfig/kdump,如果只是修改了COMMANDLINE相關(guān)的參數(shù),則不需要去重新build生成新的initramfs文件。
啟動(dòng)kdump服務(wù):
[root@localhost ~]# systemctl restart kdump
[root@localhost ~]# systemctl status kdump
● kdump.service - Crash recovery kernel arming
Loaded: loaded (/usr/lib/systemd/system/kdump.service; enabled; vendor preset: disabled)
Active: active (exited) since Sat 2017-07-15 10:46:22 UTC; 36s ago
Process: 2172 ExecStop=/usr/bin/kdumpctl stop (code=exited, status=0/SUCCESS)
Process: 2180 ExecStart=/usr/bin/kdumpctl start (code=exited, status=0/SUCCESS)
Main PID: 2180 (code=exited, status=0/SUCCESS)
Jul 15 10:46:21 localhost dracut[4264]: -rw-r--r-- 1 root root 127 Mar 28 02:15 usr/share/zoneinfo/Etc/UTC
Jul 15 10:46:21 localhost dracut[4264]: drwxr-xr-x 3 root root 0 Jun 22 13:38 var
Jul 15 10:46:21 localhost dracut[4264]: lrwxrwxrwx 1 root root 11 Jun 22 13:38 var/lock -> ../run/lock
Jul 15 10:46:21 localhost dracut[4264]: lrwxrwxrwx 1 root root 6 Jun 22 13:38 var/run -> ../run
Jul 15 10:46:21 localhost dracut[4264]: drwxr-xr-x 2 root root 0 Jun 22 13:38 var/tmp
Jul 15 10:46:21 localhost dracut[4264]: ========================================================================
Jul 15 10:46:21 localhost dracut[4264]: *** Creating initramfs image file '/boot/initramfs-4.11.9-300.fc26.x86_64kdump.img' done ***
Jul 15 10:46:22 localhost kdumpctl[2180]: kexec: loaded kdump kernel
Jul 15 10:46:22 localhost kdumpctl[2180]: Starting kdump: [OK]
Jul 15 10:46:22 localhost systemd[1]: Started Crash recovery kernel arming.
所有的服務(wù)都配置完成,如果此時(shí)系統(tǒng)發(fā)生了panic或者其他的一些導(dǎo)致系統(tǒng)崩潰的現(xiàn)象,這是kdump服務(wù)會(huì)將當(dāng)時(shí)的內(nèi)存鏡像按照用戶的配置保存起來(lái)。一個(gè)簡(jiǎn)單的方式是通過(guò)命令來(lái)觸發(fā):
[root@localhost ~]# echo c > /proc/sysrq-trigger
[some console log]
... ...
Starting Kdump Vmcore Save Service...
kdump: dump target is /dev/vda1
kdump: saving to /sysroot//var/crash/127.0.0.1-2017-07-16-04:21:36/
[ 2.718001] EXT4-fs (vda1): re-mounted. Opts: data=ordered
kdump: saving vmcore-dmesg.txt
kdump: saving vmcore-dmesg.txt complete
kdump: saving vmcore
Copying data : [100.0 %] -
kdump: saving vmcore complete
... ...
[/some console log]
當(dāng)系統(tǒng)重啟后就能在指定的目錄下看到生成的vmcore文件??梢詤⒖寂渲梦募?/etc/kdump.conf"里的"path"字段。
[root@localhost ~]# ls -lt /var/crash/*/
total 33492
-rw-------. 1 root root 34253115 Jul 16 04:21 vmcore
-rw-r--r--. 1 root root 40360 Jul 16 04:21 vmcore-dmesg.txt
轉(zhuǎn)儲(chǔ)文件被保存后可以用"crash"這個(gè)軟件包來(lái)分析這個(gè)"vmcore"文件。
開(kāi)始提到了Kexec內(nèi)核部分提供了一些系統(tǒng)調(diào)用,"kexec_load()" 和 "kexec_file_load()",其中一個(gè)用來(lái)加載捕獲內(nèi)核 - "kexec -l",另外一個(gè)來(lái)提供系統(tǒng)重啟 - "kexec -e"。
系統(tǒng)調(diào)用"kexec_load()"可以加載一個(gè)新的內(nèi)核并之后能夠被"reboot()"調(diào)用。它是被這樣定義的:
long kexec_load(unsigned long entry, unsigned long nr_segments,
struct kexec_segment *segments, unsigned long flags);
其中一個(gè)比較重要的是"kexec_segment"結(jié)構(gòu)體:
struct kexec_segment {
void *buf; /* Buffer in user space */
size_t bufsz; /* Buffer length in user space */
void *mem; /* Physical address of kernel */
size_t memsz; /* Physical address length */
};
當(dāng)reboot()的參數(shù)為"LINUX_REBOOT_CMD_KEXEC"并被調(diào)用時(shí),則啟動(dòng)新的內(nèi)核時(shí)就調(diào)用"kexec_load()"系統(tǒng)調(diào)用。另外“CONFIG_KEXEC”必須在編譯kernel時(shí)被打開(kāi)。
系統(tǒng)調(diào)用"kexec_load_file()"會(huì)設(shè)置2個(gè)參數(shù)"kernel"和"initramfs"給"kexec"命令。"kexec"會(huì)讀取這些數(shù)據(jù)來(lái)創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)段。
long kexec_file_load(int kernel_fd, int initrd_fd,
unsigned long cmdline_len, const char *cmdline,
unsigned long flags);
同樣的"CONFIG_KEXEC_FILE"參數(shù)也要在內(nèi)核編譯時(shí)被打開(kāi)。
目前的大多數(shù)發(fā)行版都已經(jīng)打開(kāi)了"KEXEC"相關(guān)的配置參數(shù)。
以上就是一個(gè)kdump的簡(jiǎn)單流程。有關(guān)"kdump"能夠捕獲到的內(nèi)核崩潰時(shí)間可以參考文檔"/usr/share/doc/kexec-tools/kexec-kdump-howto.txt"?;蛘哒?qǐng)參考我們寫(xiě)的測(cè)試用例 kdump-test。