watchdog: BUG: soft lockup - CPU#0 stuck for 23s!

虚拟机

创建目录

soft_lock_up

源程序

soft_lock_up_module.c

#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>

struct task_struct *task0;
static spinlock_t spinlock;
int val;

int task(void *arg) {
  printk(KERN_INFO "%s:%d\n", __func__, __LINE__);
  /* To generate panic uncomment following */
  /* panic("softlockup: hung tasks"); */

  while (!kthread_should_stop()) {
    printk(KERN_INFO "%s:%d\n", __func__, __LINE__);
    spin_lock(&spinlock);
    printk(KERN_INFO "%s:%d\n", __func__, __LINE__);
    /* busy loop in critical section */
    while (1) {
      
    }

    spin_unlock(&spinlock);
  }

  return val;
}

static int softlockup_init(void) {
  printk(KERN_INFO "%s:%d\n", __func__, __LINE__);

  val = 1;
  spin_lock_init(&spinlock);
  task0 = kthread_run(&task, (void *)val, "softlockup_thread");
  set_cpus_allowed_ptr(task0, cpumask_of(0));

  return 0;
}

static void softlockup_exit(void) {
  printk(KERN_INFO "%s:%d\n", __func__, __LINE__);
  kthread_stop(task0);
}

module_init(softlockup_init);
module_exit(softlockup_exit);
MODULE_LICENSE("GPL v2"); // 表示模块代码接受的软件许可协议
MODULE_AUTHOR("www");     // 描述模块的作者信息
MODULE_DESCRIPTION("soft lock up module"); // 对模块的简单介绍
MODULE_ALIAS("soft_lock_up_module");       // 给模块设置一个别名

Makefile

# 指向编译出来的 linux 内核具体路径
KERNEL_DIR = /usr/lib/modules/4.19.113-300.axs7.14.aarch64/build
# 定义变量,并且导出变量给子 Makefile 使用
#ARCH = arm
#CROSS_COMPILE = arm-linux-gnueabihf-
#export ARCH CROSS_COMPILE
# obj-m := <模块名>.o: 定义要生成的模块
# soft_lock_up_module.o 自动搜索soft_lock_up_module.c进行编译,即:该模块C文件必须是soft_lock_up_module.c
obj-m := soft_lock_up_module.o

# 选项 "-C":让 make 工具跳转到 linux 内核目录下读取顶层 Makefile
# "M=" 表示内核模块源码目录
# $(CURDIR): Makefile 默认变量,值为当前目录所在路径
# make modules: 执行 Linux 顶层 Makefile 的伪目标,它实现内核模块的源码读取并编译为.ko文件
all:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules

.PHONY:clean copy

clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean

copy:
	cp *.ko /tmp/

进入该目录,执行make,得到

安装内核模块

insmod soft_lock_up_module.ko

 此时,bash被瞬间卡主。

宿主机

虚拟机卡主后,过几分钟,在宿主机上dump虚拟机内核

virsh dump --memory-only redflag1 qemu-virtual-machine/redflag1-memonly.dump

重启虚拟机

virsh destroy redflag1
virsh start redflag1

虚拟机

nfs挂载目录后,crash调试

此时状态为:TASK_RUNNING 

实际上,虚拟机已经处于假死状态,bash交互界面已无法操作

输入指令:log

输入gg,快速下翻到页尾,可以看到内核打印了watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [softlockup_thre:1079],pc(Program Counter:程序计数器)指向地址为task+0xac/0xb8 [soft_lock_up_module]

dis反汇编

 

反汇编.ko

objdump -d soft_lock_up_module.ko > soft_lock_up_module.s

内容一致

其中:ARM64汇编指令 b 为跳转指令,即执行到ac地址处,跳转到ac地址处,对应while(1){}循环体。

objddump -S获取更多信息

 

addr2line查找源码行(不确定方法是否正确)

 addr2line 定位到的位置在进入死循的环前一行。

bt查看调用栈

 

rcu: INFO: rcu_sched detected stalls on CPUs/tasks(hard lock up?)

源程序

hard_lock_up_module.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/spinlock.h>

MODULE_LICENSE("GPL");

static int hog_thread(void *data) {
  static DEFINE_SPINLOCK(lock);
  unsigned long flags;

  printk(KERN_INFO "Hogging a CPU now\n");
  spin_lock_irqsave(&lock, flags);
  while (1)
    ;

  /* unreached */
  return 0;
}

static int __init hog_init(void) {
  kthread_run(&hog_thread, NULL, "hog");
  return 0;
}

module_init(hog_init);
MODULE_LICENSE("GPL v2"); // 表示模块代码接受的软件许可协议
MODULE_AUTHOR("www");     // 描述模块的作者信息
MODULE_DESCRIPTION("soft lock up module"); // 对模块的简单介绍
MODULE_ALIAS("soft_lock_up_module");       // 给模块设置一个别名

Makefile

# 指向编译出来的 linux 内核具体路径
KERNEL_DIR = /usr/lib/modules/4.19.113-300.axs7.14.aarch64/build
# 定义变量,并且导出变量给子 Makefile 使用
#ARCH = arm
#CROSS_COMPILE = arm-linux-gnueabihf-
#export ARCH CROSS_COMPILE
# obj-m := <模块名>.o: 定义要生成的模块
# hard_lock_up_module.o 自动搜索hard_lock_up_module.c进行编译,即:该模块C文件必须是hard_lock_up_module.c
obj-m := hard_lock_up_module.o

# 选项 "-C":让 make 工具跳转到 linux 内核目录下读取顶层 Makefile
# "M=" 表示内核模块源码目录
# $(CURDIR): Makefile 默认变量,值为当前目录所在路径
# make modules: 执行 Linux 顶层 Makefile 的伪目标,它实现内核模块的源码读取并编译为.ko文件
all:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules

.PHONY:clean copy

clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean

copy:
	cp *.ko /tmp/

编译,安装模块

make
insmod hard_lock_up.ko

参考软锁,dump内核,crash调试

 

总结 

触发软锁关键代码

spin_lock(&spinlock);

触发rcu_sched detected stalls关键代码:

spin_lock_irqsave(&lock, flags);

差别:spin_lock_irqsave关闭当前CPU上的中断

参考:

NMI watchdog: BUG: soft lockup - CPU#2 stuck for 23s!_rtoax的博客-CSDN博客

INFO: rcu_sched detected stalls on CPU/tasks_MIPSA的博客-CSDN博客

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐