目录
1、实验目的:使用crash 解决自旋锁(spinlock)死锁问题
4.3、ps |grep RU 找到可执行状态线程,在使用bt命令查看栈回溯确定死锁线程
环境:arm64,Linux version 5.10.66
1、实验目的:使用crash 解决自旋锁(spinlock)死锁问题
实验程序如下,当程序编译成ko并使用insmod加载到设备后,串口输入 echo kdump-3 > /proc/dbug/dump 命令之后执行我们的测试程序,测试程序是典型的AB-BA死锁,等待20秒后 soft lockup 检测到某个cpu上20s没有发生调度。(spinlock死锁情况),调用panic触发kdump。kdump产生vmcore文件后使用crash命令来分析下自旋锁(spinlock)死锁问题。
2、实验步骤
前提:设备linux支持了kdump功能,支持方法参考此专题文章
a、编译测试模块:将上述源码编译成kdump.ko驱动模块,在设备串口中使用insmod命令加载此驱动到设备中。此时会生成 /proc/dbug/kdump 调试文件
b、触发panic:执行 echo kdump-4 > /proc/dbug/kdump 命令执行测试程序,测试程序会执行 panic 触发kdump机制,启动捕获内核,并在捕获内核中生成 /proc/vmcore 文件。
c、保存vmcore文件:执行 cd /proc;tar -czf /tmp/3588/vmcore.tar.gz ./vmcore 将捕获内核下的vmcore文件压缩并拷贝到u盘或者nfs挂载的目录中。
d、使用crash分析vmcore文件:执行 crash vmlinux vmcore 命令使用crash分析vmcore文件。
e、由于vmcore文件只会保留kdump.ko的代码部分,因此需要在crash中使用 mod加载kdump.ko 驱动模块的调试以及符号信息。这样执行 crash> dis -l kdump_proc_write 命令才会正确显示汇编代码对应的行号信息
mod -s kdump /kdump/demo/stack/kdump.ko
3、soft lockup 机制简述
soft lockup 机制的作用是检测cpu是否发生调度,如果某个cpu上20秒时间没有发生调度则认为有异常情况。
a、soft lockup 核心思想
为每个cpu启动一个内核线程(watchdog/x),此线程为优先级最高的实时线程,在该线程得到调度时,会更新相应的计数(时间戳),同时会启动定时器,当定时器到期时检查相应的时间戳,如果超过指定时间(默认为20s)都没有更新,则说明这段时间内都没有发生调度(因为此线程优先级最高),则打印相应告警或根据配置可以进入panic流程。
b、触发 soft lockup 机制的可能原因
(1)在未开启内核抢占的linux上,有内核线程进入死循环。(CONFIG_PREEMPT=y)
(2)线程等待自旋锁,等待时间超过 20 秒
(3)线程内部循环次数太多,程序执行时间超过20秒
c、soft lockup 机制的proc接口
/proc/sys/kernel/soft_watchdog /* soft lockup开关 */
/proc/sys/kernel/softlockup_all_cpu_backtrace
/proc/sys/kernel/softlockup_panic
/proc/sys/kernel/sysctl_writes_strict
4、spinlock 死锁问题分析
解决自旋锁的死锁问题,只需要找到持有锁和等待锁的线程即可,根据自旋锁的特点,等待锁的线程会进入死循环自旋等待锁释放,因此持有锁和等待锁的线程一定是可执行状态并且占用cpu正在运行,可执行状态(RU: R (TASK_RUNNING))并不意味着进程一定在运行中,也可以在运行队列里;这里提供3种思路查找死锁线程。
4.1、从cpu正在执行的线程中找死锁线程
spinlock 锁是自旋死循环检测,因此等待锁线程会一直占用着cpu,根据percpu变量 runqueues 来找到每个cpu正在运行什么线程即可。
a、percpu变量 runqueues 的定义
(1) struct rq runqueues 定义
X:\work\linux\linux-6.0\kernel\sched\core.c
DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
struct rq {
/* 三个不同的runqueue,供3个不同的调度器分别使用 */
struct cfs_rq cfs;
struct sched_entity *curr; /* 当前运行的进程的调度实体 struct task_struct *curtask->se */
struct rt_rq rt;
struct dl_rq dl;
/* 记录当前cpu正在执行的线程 */
struct task_struct __rcu *curr;
}
(2) struct task_struct __rcu *curr 成员赋值
通过下面函数赋值:
static inline int task_current(struct rq *rq, struct task_struct *p)
{
return rq->curr == p;
}
static inline int task_running(struct rq *rq, struct task_struct *p)
{
#ifdef CONFIG_SMP
return p->on_cpu;
#else
return task_current(rq, p);
#endif
}
(3)关于 struct cfs_rq cfs 成员中 curr 的简单说明
struct cfs_rq cfs;
struct sched_entity *curr; /* 当前运行的进程的调度实体 struct task_struct *curtask->se */

本文围绕使用crash解决Linux自旋锁死锁问题展开。介绍了实验目的、步骤,简述soft lockup机制及触发原因,还提供三种查找死锁线程的思路,包括从cpu正在执行的线程中查找、利用soft lookup机制确定、通过ps |grep RU结合bt命令确定。
最低0.47元/天 解锁文章
3239

被折叠的 条评论
为什么被折叠?



