内容简介:自然要做 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=y
、 CONFIG_SYSFS=y
、 CONFIG_DEBUG_INFO=y
、 CONFIG_CRASH_DUMP=y
、 CONFIG_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 版本才可以。
演示视频
这里奉上我自己调试演示的视频信息,视频可能比较复杂,请结合文档提示进行理解消化。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用Spark进行数据统计并将结果转存至MSSQL
- Flume将 kafka 中的数据转存到 HDFS 中
- 堆排序动画演示,Python代码演示,看不懂你砍我!
- GraphQL案例演示
- Kubernetes身份验证机制演示
- 中心极限定理的Matlab演示
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Go Web编程
谢孟军 / 电子工业出版社 / 2013-6-1 / 65.00元
《Go Web编程》介绍如何用Go语言进行Web应用的开发,将Go语言的特性与Web开发实战组合到一起,帮读者成功地构建跨平台的应用程序,节省Go语言开发Web的宝贵时间。有了这些针对真实问题的解决方案放在手边,大多数编程难题都会迎刃而解。 在《Go Web编程》中,读者可以更加方便地找到各种编程问题的解决方案,内容涵盖文本处理、表单处理、Session管理、数据库交互、加/解密、国际化和标......一起来看看 《Go Web编程》 这本书的介绍吧!