前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个AB锁死锁问题分析

一个AB锁死锁问题分析

原创
作者头像
cdh
修改2020-06-03 10:14:51
1.6K0
修改2020-06-03 10:14:51
举报
文章被收录于专栏:笔记+笔记+

一,问题描述:

Cgroup OOM导致node异常重启

二,问题分析

1,查看dmesg日志可以看到node在重启前确实出现频繁的cgroup oom:

2,查看vmcore log日志可以知道机器是由watchdog触发的自动重启:

3,Watchdog触发重启的原因是由于出现了cpu 21持有spin lock超过20s,导致watchdog/21线程无法被调度执行触发panic重启:

4,查看spinlock信息可以知道一个进程持有锁,另外有7个进程在等待spinlock:

5,找到占有spinlock的进程

搜索栈信息找到跟spinlock相关的进程:

查看上面8个进程的栈信息可以确认当前持有spinlock的进程是27033,其他进程在等待spinlock锁

从上面截图可知27033没有释放spinlock的原因是因为在等mutex信号量,获取mutex信号

量失败而进入UN状态:

6,找到占有mutex的进程

结合27033进程栈信息以及代码可以知道27033在等待cpu_hotplug锁:

正常情况下mutex 里的owner记录的是当前持有mutex信号量的进程,这个问题因为mutex的owner值为0,因此无法直接找到当前占有mutex的进程是哪个:

列出所有在等待该mutex的进程:

将所有正在等待mutex锁的进程列出保存到task_list.txt文件中:

list mutex_waiter.list -s mutex_waiter.task 0xffff88078f2cbb20 | grep task | grep -v 0x0 > task_list.txt

vi打开task_list.txt:

vi task_list.txt

在vi下输入如下命令将task = 替换为task_struct:

:%s/task\ =/struct\ task_struct/g

回到crash控制台,执行<./task_list.txt | grep -wE 'state|pid' | grep , 列出

所有正在等待mutex锁的进程state以及PID

crash> <./task_list.txt | grep -wE 'pid|state' | grep ,

state = 0,

pid = 13339,

state = 2,

pid = 26954,

state = 2,

pid = 26844,

state = 2,

pid = 27024,

state = 2,

pid = 26827,

state = 2,

pid = 27033,

state = 2,

pid = 27025,

state = 2,

pid = 27046,

state = 2,

pid = 26825,

state = 2,

pid = 26614,

state = 2,

pid = 26974,

state = 2,

pid = 26757,

state = 2,

pid = 27020,

state = 2,

pid = 26952,

state = 2,

pid = 21451,

state = 2,

pid = 21545,

state = 2,

pid = 27044,

state = 2,

pid = 21492,

state = 2,

pid = 27031,

state = 2,

pid = 26826,

state = 2,

pid = 27009,

state = 2,

pid = 21547,

state = 2,

pid = 27023,

state = 2,

pid = 26822,

state = 2,

pid = 27063,

state = 2,

pid = 26978,

state = 2,

pid = 27037,

state = 2,

pid = 21501,

state = 2,

pid = 27065,

state = 2,

pid = 26618,

state = 2,

pid = 27018,

state = 2,

pid = 27068,

state = 2,

pid = 27066,

state = 2,

pid = 27057,

state = 2,

pid = 27212,

state = 2,

pid = 27211,

state = 2,

pid = 27386,

state = 2,

pid = 27485,

state = 2,

pid = 27524,

state = 2,

pid = 27538,

state = 2,

pid = 27573,

crash>

从上面的输出信息可以看到13339进程的state值为0,而其他进程的值为2,查看内核代码可以知道state值为0代表TASK_RUNNING状态:

如果进程13339是在等待mutex锁,那么其状态应该是TASK_UNINTERRUPTIBLE,而不应该是当前的TASK_RUNNING状态,因此从其状态可以推断出进程13339持有mutex锁,从mutex_lock实现可以知道该函数是先拿锁,再将owner设置为当前进程task,因此13339进程在刚获取到mutex lock后设置owner前刚好被调度出去就会出现owner为0的情况:

7,为什么13339进程一直不释放mutex锁:

从vmcore的runq信息可以看到kdump时13339进程是等待在cpu 1 队列上,而由于13339进程被做了绑核,所以无法被调度到其他cpu上执行:

CPU 1 RUNQUEUE: ffff88081fc31dc0

CURRENT: PID: 27050 TASK: ffff8806b5f7cb30 COMMAND: "ps"

RT PRIO_ARRAY: ffff88081fc31f40

[ 0] PID: 12 TASK: ffff8808145a3220 COMMAND: "watchdog/1"

CFS RB_ROOT: ffff88081fc31e58

[120] PID: 20698 TASK: ffff8807aa36b220 COMMAND: "TSW/worker/1"

[120] PID: 27478 TASK: ffff8806d9189910 COMMAND: "node"

[120] PID: 24371 TASK: ffff880f22598000 COMMAND: "sleep"

[120] PID: 13339 TASK: ffff880714669910 COMMAND: "TSW/worker/1"

[120] PID: 10377 TASK: ffff8807a89a1910 COMMAND: "kworker/1:0"

[120] PID: 14 TASK: ffff8808145a6440 COMMAND: "ksoftirqd/1"

而当前cpu1上运行的是进程27050,进程27050因获取不到spin_lock锁而一直占有cpu 1,因此13339进程因一直无法得到cpu资源而不释放mutex 锁:

8,27050为什么无法获取spinlock锁?

在栈中搜索锁变量地址ffffea003fe216b0可知道进程27033,27041和27050是在等待同一把spin_lock锁,而当前spinlock锁被进程27033占有。

9,结论:

27033进程获取了spin_lock锁后尝试获取mutex失败进入UN状态,占有mutex锁的进程13339因cpu 1资源一直被27050进程占用而无法得到调度执行导致mutex锁无法正常释放,而27050进程之所以一直占有cpu 1资源是因为其在等待被27033进程占有的spinlock锁。

简单来讲就是:

27033等待13339的mutex锁,13339等待cpu 1资源,cpu 1资源被进程27050占住,27050进程等待27033进程占有的锁,这样就造成了内核死锁。

本文仅限于介绍死锁问题怎么分析,具体该问题的修复方法涉及到代码的实现就不在这里进一步阐述了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档