kdump+crash 解决自旋锁(spinlock)死锁问题

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

目录

1、实验目的:使用crash 解决自旋锁(spinlock)死锁问题

2、实验步骤

3、soft lockup 机制简述

4、spinlock 死锁问题分析

4.1、从cpu正在执行的线程中找死锁线程

4.2、soft lookup  机制确定死锁线程

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 */


                
[ 116.079461][ C5] watchdog: BUG: soft lockup - CPU#5 stuck for 49s! [kswapd0:91] [ 116.079472][ C5] CPU#5 Utilization every 4s during lockup: [ 116.079475][ C5] #1: 100% system, 0% softirq, 0% hardirq, 0% idle [ 116.079479][ C5] #2: 100% system, 0% softirq, 1% hardirq, 0% idle [ 116.079482][ C5] #3: 100% system, 0% softirq, 1% hardirq, 0% idle [ 116.079485][ C5] #4: 100% system, 0% softirq, 0% hardirq, 0% idle [ 116.079489][ C5] #5: 100% system, 0% softirq, 1% hardirq, 0% idle [ 116.080193][ C5] Kernel panic - not syncing: softlockup: hung tasks [ 116.080196][ C5] CPU: 5 PID: 91 Comm: kswapd0 Tainted: G C OEL 6.6.77-android15-8-maybe-dirty-debug #1 87d0bdbac97ce09587b16630b722a5b52b4aa5e1 [ 116.080201][ C5] Hardware name: Qualcomm Technologies, Inc. Kunzite QRD (DT) [ 116.080204][ C5] Call trace: [ 116.080206][ C5] dump_backtrace+0xf0/0x140 [ 116.080210][ C5] show_stack+0x18/0x28 [ 116.080213][ C5] dump_stack_lvl+0x70/0xa4 [ 116.080218][ C5] panic+0x158/0x3e4 [ 116.080222][ C5] watchdog_timer_fn+0x394/0x494 [ 116.080227][ C5] __hrtimer_run_queues+0x1d8/0x40c [ 116.080232][ C5] hrtimer_interrupt+0xf4/0x3b8 [ 116.080237][ C5] arch_timer_handler_virt+0x50/0x64 [ 116.080241][ C5] handle_percpu_devid_irq+0x100/0x320 [ 116.080246][ C5] generic_handle_domain_irq+0x5c/0x88 [ 116.080251][ C5] gic_handle_irq+0x4c/0x114 [ 116.080255][ C5] call_on_irq_stack+0x3c/0x70 [ 116.080258][ C5] do_interrupt_handler+0x7c/0xe8 [ 116.080263][ C5] el1_interrupt+0x34/0x58 [ 116.080267][ C5] el1h_64_irq_handler+0x18/0x24 [ 116.080270][ C5] el1h_64_irq+0x68/0x6c [ 116.080273][ C5] queued_spin_lock_slowpath+0x9c/0x51c [ 116.080278][ C5] do_raw_spin_lock+0x104/0x120 [ 116.080282][ C5] _raw_spin_lock+0x74/0x98 [ 116.080286][ C5] __swap_duplicate+0xa4/0x1fc [ 116.080290][ C5] swap_duplicate+0x24/0x58 [ 116.080294][ C5] try_to_unmap_one+0x620/0xf40 [ 116.080299][ C5] rmap_walk_anon+0x1f8/0x294 [ 116.080304][ C5] try_to_unmap+0x5c/0x9c [ 116.080309][ C5] shrink_folio_list+0x7f8/0x15bc [ 116.080314][ C5] shrink_inactive_list+0x2a0/0x574 [ 116.080319][ C5] shrink_lruvec+0x54c/0xa1c [ 116.080323][ C5] shrink_node+0x270/0x11c4 [ 116.080327][ C5] balance_pgdat+0x8c0/0x1140 [ 116.080331][ C5] kswapd+0x35c/0x6cc [ 116.080335][ C5] kthread+0x118/0x158 [ 116.080340][ C5] ret_from_fork+0x10/0x20 [ 116.080344][ C5] SMP: stopping secondary CPUs 基线升级后等锁触发watchdog,我要怎么看所被谁占有了
最新发布
10-27
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值