使用 Qemu 虚拟 ARM64 平台演示 kdump 崩溃转存

栏目: 编程工具 · 发布时间: 5年前

内容简介:自然要做 kdump 的虚拟机内部崩溃演示,首先得准备一下一个完整的虚拟机环境,由于我的宿主机情况比较复杂,我首先进入到一个相对比较完善的 Docker 镜像环境中,这样做的好处就是哪怕虚拟机被我折腾得再乱或者崩溃都不会影响到我的宿主机的其他服务(这台宿主机是一个代码储存服务器,运行着很多相关的服务,不允许我瞎折腾)。在文章《直接启动这个 docker 镜像并进入容器内部,执行相关的虚拟机软件包安装。

准备工作

自然要做 kdump 的虚拟机内部崩溃演示,首先得准备一下一个完整的虚拟机环境,由于我的宿主机情况比较复杂,我首先进入到一个相对比较完善的 Docker 镜像环境中,这样做的好处就是哪怕虚拟机被我折腾得再乱或者崩溃都不会影响到我的宿主机的其他服务(这台宿主机是一个代码储存服务器,运行着很多相关的服务,不允许我瞎折腾)。

启动 docker 环境

在文章《 Ubuntu 下的 Docker 安装与使用 》中我已经介绍了如何安装与配置基本的 docker 服务,现在只需要按照文档中的流程拉取一个需要的 docker 镜像即可,作为演示我选择的目前比较稳定的 debian:buster 版本。

[jackieliu@localhost ~]$ sudo docker pull debian:buster-20190204

安装虚拟机软件包

直接启动这个 docker 镜像并进入容器内部,执行相关的虚拟机软件包安装。

[jackieliu@localhost ~]$ sudo docker run -itd debian:buster-20190204
7d05ac0f566c836d74cebfe9d8d18d09b29bdf1d407686e0584324511bba1f36

[jackieliu@localhost ~]$ sudo docker exec -it 7d05ac0f566c bash

root@Kylin:/$ apt update
Fetched 1789 kB in 25s (72.6 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done

root@Kylin:/$ apt install qemu-system-aarch64 -y

等待安装 qemu 虚拟机安装完毕即可,需要注意的是在 docker 的文章中我提到的容器内部所有的动作,包括装包或者文件的修改都需要在宿主机上进行 docker commit ,不然等你退出这个虚拟机再次启动镜像时,这些修改又不存在了。

制作 ubuntu 系统镜像 rootfs.img 文件

进入 Qemu 虚拟机系统需要准备好虚拟机的 rootfs 文件系统,我们可以从 Ubuntu 的官方下载一个比较基础的系统即可,如果还需要更为复杂的 rootfs,可以在网上搜寻其他人制作的文件系统镜像文件。

root@Kylin:/$ wget http://cdimage.ubuntu.com/ubuntu-base/releases/18.04/release/ubuntu-base-18.04.1-base-arm64.tar.gz
--2019-03-04 07:37:23--  http://cdimage.ubuntu.com/ubuntu-base/releases/18.04/release/ubuntu-base-18.04.1-base-arm64.tar.gz
Resolving cdimage.ubuntu.com (cdimage.ubuntu.com)... 91.189.88.168, 2001:67c:1360:8001::28
Connecting to cdimage.ubuntu.com (cdimage.ubuntu.com)|91.189.88.168|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 27767381 (26M) [application/x-gzip]
Saving to: 'ubuntu-base-18.04.1-base-arm64.tar.gz'

通过 dd 命令创建一个大小为 4G的文件 rootfs.img 并格式化为 ext4 文件系统。

root@Kylin:/$ dd if=/dev/zero of=rootfs.img bs=1M count=4k oflag=direct
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 38.4543 s, 112 MB/s

root@Kylin:/$ mkfs.ext4 rootfs.img
mke2fs 1.44.5 (15-Dec-2018)
Discarding device blocks: done
Creating filesystem with 1048576 4k blocks and 262144 inodes
Filesystem UUID: 11f935ee-69b8-4f7f-aab7-20b204f83574
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done

接下来就挂载这个文件镜像到系统,并解压 Ubuntu 官方的 tar.gz 系统到该目录,卸载该文件镜像,一个完整的 ubuntu 系统就被导入到 rootfs.img 中。

root@Kylin:/$ mkdir -p rootfs && mount rootfs.img rootfs
root@Kylin:/$ tar -xvf ubuntu-base-18.04.1-base-arm64.tar.gz -C rootfs
root@Kylin:/$ umount rootfs

重编内核 Image

首先需要从官方地址下载最新的 Linux 内核源码,然后拷贝并修改配置文件 arch/arm64/config/defconfig 到 .config,需要打开 CONFIG_KEXEC=yCONFIG_SYSFS=yCONFIG_DEBUG_INFO=yCONFIG_CRASH_DUMP=yCONFIG_PROC_VMCORE=y 配置选项,具体请参考 Linux 内核的 官方内置手册

root@Kylin:/$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

进入 linux 目录修改配置文件之后,执行编译 make Image 命令生成 Image 文件,以便虚拟机能够加载该内核文件。

Kdump 崩溃转存演示

安装 kdump-tools 相关的软件包

由于刚刚下载的 Ubuntu Base 系统中只拥有很少的软件包,所以需要利用 chroot 进入到这个 base 文件系统安装一些 kdump 相关的软件包。

root@Kylin:/$ mount rootfs.img rootfs && chroot rootfs
$ apt install kdump-tools crash kexec-tools makedumpfile systemd -y
$ passwd root << EOF
123123
123123
EOF
$ exit
root@Kylin:/$ umount rootfs

由于默认的 Base 系统没有携带大型的启动管理器,所以为了能够对服务进行管理,我们还需要安装 systemd 启动管理软件。等待安装完毕,并卸载文件系统即可,文件系统镜像中已经保留了当前安装的软件,另外还需要将 Linux 内核的 Image 和 vmlinux 二进制程序也拷贝到 rootfs 中,这两个文件是为了能够让 kdump 的服务正确运行,密码也是需要设置的,不然无法正确登录进入系统。

进入虚拟机中的 Ubuntu 系统

rootfs.img 已经成功安装了 kdump-tools 相关的包,那么现在只需要利用 qemu-system-aarch64 虚拟机启动内核并加载该文件系统镜像即可)。

root@Kylin:/$ qemu-system-aarch64 -enable-kvm -machine virt -M virt,gic_version=3 -cpu cortex-a57 \
                      -machine type=virt -nographic -smp 2 -m 4096 -kernel Image -hda ./rootfs.img \
                      -append "console=ttyAMA0 root=/dev/vda rw crashkernel=256M nr_cpus=2"

此时已经进入了 qemu 虚拟机下的 ubuntu 系统。现在,我们就需要在这个系统下演示如何转存内核崩溃信息。

调试内核转存文件

要启动 kdump-tools 服务,首先需要在内核的启动参数中添加 crashkernel=X[@Y] 这样的参数,表明需要预留一部分内存用以保存 dump 内核的代码,以便在第一个内核崩溃的情况下,通过一系列故障处理之后,迅速切换到第二个内核,也就是所谓的 dump 内核,通过该内核收集第一个内核所产生的崩溃现场信息,并保存到 /var/crash 目录下,方便重启之后可以查看到该奔溃信息,提供给内核开发者调试问题的方向。

确保了启动参数添加了 crashkernel 之后,还需要保证服务正确启动:

root@localhost:~$ /etc/init.d/kdump-tools restart
Restarting kdump-tools (via systemctl): kdump-tools.service[   21.282910] kdump-tools[2539]: Stopping kdump-tools:  * unloaded kdump kernel
[   21.398844] kdump-tools[2564]: Starting kdump-tools:  * Creating symlink /var/lib/kdump/vmlinuz
[   21.401271] kdump-tools[2564]:  * Creating symlink /var/lib/kdump/initrd.img
[   21.915798] kdump-tools[2564]:  * loaded kdump kernel

root@localhost:~$ kdump-config show
DUMP_MODE:        kdump
USE_KDUMP:        1
KDUMP_SYSCTL:     kernel.panic_on_oops=1
KDUMP_COREDIR:    /var/crash
crashkernel addr: 0xefe00000
   /var/lib/kdump/vmlinuz: symbolic link to /boot/vmlinuz-5.0.0-rc3-00473-g957491e4ebfe
kdump initrd:
   /var/lib/kdump/initrd.img: symbolic link to /var/lib/kdump/initrd.img-5.0.0-rc3-00473-g957491e4ebfe
current state:    ready to kdump
kexec command:
  /sbin/kexec -p --command-line="console=ttyAMA0 root=/dev/vda rw nr_cpus=2 nr_cpus=1 systemd.unit=kdump-tools.service" --initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz

可以看到当前的服务状态已经成功,接下来只需要将内核弄得崩溃即可:

root@localhost:~$ echo c > /proc/sysrq-trigger
root@localhost:/boot# echo c > /proc/sysrq-trigger
[   52.026012] sysrq: SysRq : Trigger a crash
[   52.027357] Kernel panic - not syncing: sysrq triggered crash
[   52.028997] CPU: 0 PID: 2481 Comm: bash Kdump: loaded Not tainted 5.0.0-rc3-00473-g957491e4ebfe-dirty #49
[   52.031751] Hardware name: linux,dummy-virt (DT)
[   52.033126] Call trace:
[   52.034059]  dump_backtrace+0x0/0x140
[   52.035726]  show_stack+0x14/0x20
[   52.037385]  dump_stack+0x90/0xb4
[   52.038770]  panic+0x134/0x2c0
[   52.040175]  sysrq_handle_reboot+0x0/0x18
[   52.041720]  __handle_sysrq+0x84/0x170
[   52.043524]  write_sysrq_trigger+0x64/0x80
[   52.045179]  proc_reg_write+0x64/0xa0
[   52.046902]  __vfs_write+0x30/0x170
[   52.048243]  vfs_write+0xa4/0x1b0
[   52.049767]  ksys_write+0x5c/0xc0
[   52.051018]  __arm64_sys_write+0x18/0x20
[   52.052614]  el0_svc_common+0x84/0xf0
[   52.054060]  el0_svc_handler+0x2c/0x80
[   52.055556]  el0_svc+0x8/0xc
[   52.056715] SMP: stopping secondary CPUs
[   52.059009] Starting crashdump kernel...
[   52.060559] Bye!

然后就会自动启动第二个内核,并且启动 kdump-tools 服务的 savecore 功能保存崩溃现场信息。

[  OK  ] Reached target System Initialization.
         Starting Kernel crash dump capture service...
[    2.431304] kdump-tools[1564]: Starting kdump-tools:  * running makedumpfile -c -d 31 /proc/vmcore /var/crash/201903050735/dump-incomplete
[    2.451777] kdump-tools[1564]: get_mem_section: Could not validate mem_section.
[    2.454372] kdump-tools[1564]: get_mm_sparsemem: Can't get the address of mem_section.
[    2.458981] kdump-tools[1564]: The kernel version is not supported.
[    2.464283] kdump-tools[1564]: The makedumpfile operation may be incomplete.
[    2.470796] kdump-tools[1564]: makedumpfile Failed.
[    2.476827] kdump-tools[1564]:  * kdump-tools: makedumpfile failed, falling back to 'cp'
[   12.020359] kdump-tools[1564]:  * kdump-tools: saved vmcore in /var/crash/201903050735
[   15.444973] kdump-tools[1564]:  * running makedumpfile --dump-dmesg /proc/vmcore /var/crash/201903050735/dmesg.201903050735
[   15.460068] kdump-tools[1564]: get_mem_section: Could not validate mem_section.
[   15.463537] kdump-tools[1564]: get_mm_sparsemem: Can't get the address of mem_section.
[   15.471594] kdump-tools[1564]: The kernel version is not supported.
[   15.478798] kdump-tools[1564]: The makedumpfile operation may be incomplete.
[   15.484190] kdump-tools[1564]: makedumpfile Failed.
[   15.489301] kdump-tools[1564]:  * kdump-tools: makedumpfile --dump-dmesg failed. dmesg content will be unavailable
[   15.496868] kdump-tools[1564]:  * kdump-tools: failed to save dmesg content in /var/crash/201903050735
[   15.507109] kdump-tools[1564]: Tue, 05 Mar 2019 07:35:58 +0000
[   15.807040] reboot: Restarting system

等待其完成保存完毕之后,会自动重新启动系统,此时 /var/crash/ 目录就保存了一个 vmcore 的调试文件(此处也可能是 dump.xxx 文件),然后通过 crash 工具对其进行调试即可。

root@localhost:~$ crash /vmlinux /var/crash/201903050735/vmcore.201903050735
Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, 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.

      KERNEL: /vmlinux
    DUMPFILE: /var/crash/201903050735/vmcore.201903050735
        CPUS: 2
        DATE: Tue Mar  5 07:35:35 2019
      UPTIME: 00:00:51
LOAD AVERAGE: 0.00, 0.00, 0.00
       TASKS: 67
    NODENAME: localhost.localdomain
     RELEASE: 5.0.0-rc3-00473-g957491e4ebfe-dirty
     VERSION: #49 SMP PREEMPT Tue Mar 5 06:34:21 UTC 2019
     MACHINE: aarch64  (unknown Mhz)
      MEMORY: 4 GB
       PANIC: "sysrq: SysRq : Trigger a crash"
         PID: 2481
     COMMAND: "bash"
        TASK: ffff8000f7f3ec00  [THREAD_INFO: ffff8000f7f3ec00]
         CPU: 0
       STATE: TASK_RUNNING (SYSRQ)

crash>

具体的命令就在 crash 的命令行提示符上输入 help 获得帮助即可,命令都很简单,稍微使用一下就可以上手。

其他

遇到的问题

不清楚是宿主机的原因还是代码原因,目前主线的 Linux kernel 代码在执行命令使第一个内核崩溃之后,跳转到第二个内核的过程中卡死,在社区上也有其他人遇到了类似的情况并给出了补丁,但是并没有合并到主线,不过目前为了演示暂时不考虑为何原因导致这个问题的出现,如果你的 arm64 宿主机不存在这个问题,那么就不需要打这个补丁了。奉上补丁如下:

diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index aa9c94113700..3b0350d20e31 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -234,19 +234,12 @@ static void machine_kexec_mask_interrupts(void)

        for_each_irq_desc(i, desc) {
                struct irq_chip *chip;
-               int ret;

                chip = irq_desc_get_chip(desc);
                if (!chip)
                        continue;

-               /*
-                * First try to remove the active state. If this
-                * fails, try to EOI the interrupt.
-                */
-               ret = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false);
-
-               if (ret && irqd_irq_inprogress(&desc->irq_data) &&
+               if (irqd_irq_inprogress(&desc->irq_data) &&
                    chip->irq_eoi)
                        chip->irq_eoi(&desc->irq_data);

还有一点需要说明的就是在 Ubuntu 默认仓库的 crash 不支持最新版本的 Linux 内核,需要更新到 7.2.5 版本才可以。

演示视频

这里奉上我自己调试演示的视频信息,视频可能比较复杂,请结合文档提示进行理解消化。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go Web编程

Go Web编程

谢孟军 / 电子工业出版社 / 2013-6-1 / 65.00元

《Go Web编程》介绍如何用Go语言进行Web应用的开发,将Go语言的特性与Web开发实战组合到一起,帮读者成功地构建跨平台的应用程序,节省Go语言开发Web的宝贵时间。有了这些针对真实问题的解决方案放在手边,大多数编程难题都会迎刃而解。 在《Go Web编程》中,读者可以更加方便地找到各种编程问题的解决方案,内容涵盖文本处理、表单处理、Session管理、数据库交互、加/解密、国际化和标......一起来看看 《Go Web编程》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具