记录linux tty的一次软锁排查
本过程参照了某大侠的https://github.com/w-simon/debug/blob/master/tty_lock_cause_sytemd_hung ,
当第二次出现的时候,还是排查了一段时间,所以记录下来很有必要。
出现carsh,敲入命令如下:
crash> bt
PID: 357 TASK: ffff881fd2096780 CPU: 21 COMMAND: "khungtaskd"
#0 [ffff881fcf2d7cb8] machine_kexec at ffffffff81051c5b
#1 [ffff881fcf2d7d18] crash_kexec at ffffffff810f3ec2
#2 [ffff881fcf2d7de8] panic at ffffffff816326d1
#3 [ffff881fcf2d7e68] watchdog at ffffffff8111c8fe
#4 [ffff881fcf2d7ec8] kthread at ffffffff810a661f
#5 [ffff881fcf2d7f50] ret_from_fork at ffffffff81649858
这个是因为1200s(默认值是120s,我们把它改成1200,/proc/sys/kernel/hung_task_timeout_secs)没有调度更新,导致狗进行的panic。
craash中敲入log查看日志:
[935516.524086] INFO: task bash:3857 blocked for more than 1200 seconds.
[935516.524120] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[935516.524150] bash D ffff881fffc947c0 0 3857 39198 0x00000082
[935516.524154] ffff883ed26e3cb0 0000000000000046 ffff883ed26e3fd8 ffff883ed26e3fd8
[935516.524160] ffff883ed26e3fd8 00000000000147c0 ffff881fd3170000 ffff883e7f0d3980
[935516.524163] 7fffffffffffffff ffff8803ba0da278 0000000000000001 ffff8803ba0da270
[935516.524167] Call Trace:
[935516.524178] [<ffffffff8163e879>] schedule+0x29/0x70
[935516.524182] [<ffffffff8163c329>] schedule_timeout+0x209/0x2d0
[935516.524188] [<ffffffff810b6a15>] ? check_preempt_curr+0x75/0xa0
[935516.524190] [<ffffffff810b6a7c>] ? ttwu_do_wakeup+0x3c/0xd0
[935516.524193] [<ffffffff810b6d3d>] ? ttwu_do_activate.constprop.85+0x5d/0x70
[935516.524196] [<ffffffff8164061a>] ldsem_down_write+0xea/0x255
[935516.524198] [<ffffffff81640cd8>] tty_ldisc_lock_pair_timeout+0x88/0x120
[935516.524202] [<ffffffff813b8dc4>] tty_ldisc_hangup+0xc4/0x220
[935516.524208] [<ffffffff813b0594>] __tty_hangup+0x344/0x490
[935516.524211] [<ffffffff813b1739>] disassociate_ctty+0x69/0x2e0
[935516.524216] [<ffffffff81081a97>] do_exit+0x777/0xa60
[935516.524221] [<ffffffff81644e1d>] ? __do_page_fault+0x16d/0x450
[935516.524224] [<ffffffff81090931>] ? __set_task_blocked+0x41/0xa0
[935516.524227] [<ffffffff81081dff>] do_group_exit+0x3f/0xa0
[935516.524230] [<ffffffff81081e74>] SyS_exit_group+0x14/0x20
[935516.524233] [<ffffffff81649909>] system_call_fastpath+0x16/0x1b
根据堆栈分析,是因为ldisc的锁拿不到,然后把所有的堆栈打一遍,看谁拿着锁不释放。
>crash bt >>each_bt.txt
然后搜索tty的锁涉及的堆栈:
# grep tty -A 10 -B 5 each_bt.txt
PID: 3857 TASK: ffff883e7f0d3980 CPU: 4 COMMAND: "bash"
#0 [ffff883ed26e3c50] __schedule at ffffffff8163df9b
#1 [ffff883ed26e3cb8] schedule at ffffffff8163e879
#2 [ffff883ed26e3cc8] schedule_timeout at ffffffff8163c329
#3 [ffff883ed26e3d78] ldsem_down_write at ffffffff8164061a
#4 [ffff883ed26e3de0] tty_ldisc_lock_pair_timeout at ffffffff81640cd8
#5 [ffff883ed26e3e10] tty_ldisc_hangup at ffffffff813b8dc4
#6 [ffff883ed26e3e38] __tty_hangup at ffffffff813b0594
#7 [ffff883ed26e3e88] disassociate_ctty at ffffffff813b1739
#8 [ffff883ed26e3eb0] do_exit at ffffffff81081a97
#9 [ffff883ed26e3f40] do_group_exit at ffffffff81081dff
#10 [ffff883ed26e3f70] sys_exit_group at ffffffff81081e74
#11 [ffff883ed26e3f80] system_call_fastpath at ffffffff81649909
RIP: 00007f4eca34f9c9 RSP: 00007ffefaa3c940 RFLAGS: 00010246
RAX: 00000000000000e7 RBX: ffffffff81649909 RCX: 00007f4eca07e940
RDX: 000000000000007f RSI: 0000000000000000 RDI: 000000000000007f
RBP: 00007f4eca647840 R8: 000000000000003c R9: 00000000000000e7
R10: ffffffffffffff80 R11: 0000000000000246 R12: ffffffff81081e74
R13: ffff883ed26e3f78 R14: 0000000000000000 R15: 00007f4eca64ce80
--
RBP: 00007ff4df7fdd08 R8: 0000000000000000 R9: 0000000000000000
R10: 0000000000000000 R11: 0000000000000286 R12: 00000000000000aa
R13: 0000000000000720 R14: 00000000ffffffee R15: 00000000000000c4
ORIG_RAX: 00000000000000ca CS: 0033 SS: 002b
PID: 4362 TASK: ffff881fc62d8b80 CPU: 3 COMMAND: "agetty"
#0 [ffff881fcf817ca0] __schedule at ffffffff8163df9b
#1 [ffff881fcf817d08] schedule at ffffffff8163e879
#2 [ffff881fcf817d18] schedule_timeout at ffffffff8163c295
RIP: 00007f22590e7c30 RSP: 00007ffebd732a78 RFLAGS: 00000246
RAX: 0000000000000000 RBX: ffffffff81649909 RCX: ffffffffffffffff
RDX: 0000000000000001 RSI: 00007ffebd732e60 RDI: 0000000000000000
RBP: 00007ffebd732e70 R8: 00000000025bb700 R9: 00000000025bb770
R10: 0000000000000005 R11: 0000000000000246 R12: 00007ffebd7336b0
R13: 000000000000000a R14: 00000000006083a0 R15: 00007ffebd7331c0
ORIG_RAX: 0000000000000000 CS: 0033 SS: 002b
--
PID: 10910 TASK: ffff883e8a486780 CPU: 46 COMMAND: "ConsoleOutTask"
#0 [ffff883fcf677cb0] __schedule at ffffffff8163df9b
#1 [ffff883fcf677d18] schedule at ffffffff8163e879
#2 [ffff883fcf677d28] schedule_timeout at ffffffff8163c329
#3 [ffff883fcf677dd8] ldsem_down_read at ffffffff816403d8
#4 [ffff883fcf677e48] tty_ldisc_ref_wait at ffffffff813b83a3
#5 [ffff883fcf677e60] tty_write at ffffffff813b0b31
#6 [ffff883fcf677ec0] redirected_tty_write at ffffffff813b0de5
#7 [ffff883fcf677ef8] vfs_write at ffffffff811e0b3d
#8 [ffff883fcf677f38] sys_write at ffffffff811e15df
#9 [ffff883fcf677f80] system_call_fastpath at ffffffff81649909
RIP: 00007fcea73d543d RSP: 00007fcea9cb1d28 RFLAGS: 00000206
RAX: 0000000000000001 RBX: ffffffff81649909 RCX: 0000000000000000
RDX: 0000000000000083 RSI: 00007fcea9cb1d70 RDI: 0000000000000003
RBP: 00007fcea9cb1d60 R8: 0000000001c31070 R9: 0000000000000000
R10: 0000000001c31090 R11: 0000000000000293 R12: 0000000000000003
R13: 00007fcea9cb1d70 R14: 0000000000000083 R15: 0000000000000083
ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b
--
PID: 20618 TASK: ffff883f89e05c00 CPU: 9 COMMAND: "ConsoleOutTask"
#0 [ffff882114463cb0] __schedule at ffffffff8163df9b
#1 [ffff882114463d18] schedule at ffffffff8163e879
#2 [ffff882114463d28] schedule_timeout at ffffffff8163c329
#3 [ffff882114463dd8] ldsem_down_read at ffffffff816403d8
#4 [ffff882114463e48] tty_ldisc_ref_wait at ffffffff813b83a3
#5 [ffff882114463e60] tty_write at ffffffff813b0b31
#6 [ffff882114463ec0] redirected_tty_write at ffffffff813b0de5
#7 [ffff882114463ef8] vfs_write at ffffffff811e0b3d
#8 [ffff882114463f38] sys_write at ffffffff811e15df
#9 [ffff882114463f80] system_call_fastpath at ffffffff81649909
RIP: 00007f6dfecd643d RSP: 00007f6e01aaed30 RFLAGS: 00000293
RAX: 0000000000000001 RBX: ffffffff81649909 RCX: 00000000006d6f00
RDX: 0000000000000084 RSI: 00007f6e01aaed70 RDI: 0000000000000005
RBP: 00007f6e01aaed60 R8: 00000000006d3c00 R9: 0000000000000000
R10: 00000000006d3c20 R11: 0000000000000293 R12: 0000000000000005
R13: 00007f6e01aaed70 R14: 0000000000000084 R15: 0000000000000084
ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b
--
RBP: 0000000000000041 R8: 00007f63a2defe70 R9: 00000000000063bf
R10: 00007f64200010c8 R11: 0000000000003293 R12: 000000000d616e40
R13: 00007f63a2df0700 R14: 000000000d616e41 R15: 0000000000000000
ORIG_RAX: 0000000000000017 CS: 0033 SS: 002b
PID: 25548 TASK: ffff883fcefa8b80 CPU: 37 COMMAND: "agetty"
#0 [ffff88213fa1bca0] __schedule at ffffffff8163df9b
#1 [ffff88213fa1bd08] schedule at ffffffff8163e879
#2 [ffff88213fa1bd18] schedule_timeout at ffffffff8163c329
RIP: 00007f8d31776c30 RSP: 00007fff6f7c0a88 RFLAGS: 00000246
RAX: 0000000000000000 RBX: ffffffff81649909 RCX: ffffffffffffffff
RDX: 0000000000000001 RSI: 00007fff6f7c0e70 RDI: 0000000000000000
RBP: 00007fff6f7c0e80 R8: 00000000022a4700 R9: 00000000022a4770
R10: 00007fff6f7c0850 R11: 0000000000000246 R12: 00007fff6f7c16c0
R13: 0000000000000012 R14: 00000000006083a0 R15: 00007fff6f7c11d0
ORIG_RAX: 0000000000000000 CS: 0033 SS: 002b
走查相关的代码,发现是10910占着锁不放。
反汇编相关的代码,需要将tty找出来,
crash> dis tty_ldisc_ref_wait
0xffffffff813b8380 <tty_ldisc_ref_wait>: nopl 0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffff813b8385 <tty_ldisc_ref_wait+5>: push %rbp
0xffffffff813b8386 <tty_ldisc_ref_wait+6>: movabs $0x7fffffffffffffff,%rsi
0xffffffff813b8390 <tty_ldisc_ref_wait+16>: mov %rsp,%rbp
0xffffffff813b8393 <tty_ldisc_ref_wait+19>: push %rbx
0xffffffff813b8394 <tty_ldisc_ref_wait+20>: mov %rdi,%rbx
0xffffffff813b8397 <tty_ldisc_ref_wait+23>: lea 0x270(%rdi),%rdi------------------------rdi+0x270保存了tty指针,这步比较耗时,因为通过寄存器或者堆栈找变量需要一定的汇编基础和经验。
0xffffffff813b839e <tty_ldisc_ref_wait+30>: callq 0xffffffff816402b0 <ldsem_down_read>
通过查看20618的堆栈,找对关联tty的file指针:
crash> files 20618 | grep console
3 ffff880217011700 ffff883fd100a900 ffff883fd0b32038 CHR /dev/console
5 ffff8801acf06b00 ffff883fd100a900 ffff883fd0b32038 CHR /dev/console
crash> struct file.private_data ffff880217011700
private_data = 0xffff882146f23180
crash> struct tty_file_private.tty 0xffff882146f23180
tty = 0xffff8803ba0da000
crash> struct tty_struct.disc_data 0xffff8803ba0da000
disc_data = 0xffff8803ba0dd800
crash> struct n_tty_data.icanon 0xffff8803ba0dd800
icanon = 1 '\001'
发现属性被设置为了1,而根据PID: 10910 TASK: ffff883e8a486780 CPU: 46 COMMAND: "ConsoleOutTask"的用户态代码,走查发现,我们通过设置VTIME
属性来保证超时,
tcgetattr(s_pm,&term);
term.c_cc[VMIN] = 1;-------------最少读一个字符
term.c_cc[VTIME] = 2;-----------200ms超时
tcsetattr(s_pm,TCSANOW,&term);
根据tty的属性,这个代码要生效,前提是icanon 属性不能被设置为1,但我们的代码逻辑是:
/* 设置伪终端模式,非规范,无回显 */
tcgetattr(slavefd, &term);
term.c_lflag = term.c_lflag & (~(ICANON));
term.c_lflag = term.c_lflag & (~(ISIG));
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 2;
第一次设置完ICANON属性之后,就不管了,那么中途如果有人修改了这个属性,则会导致read阻塞,也就是ConsoleOutTask阻塞。
那么属性被修改,有两种情况,一种是被异常修改,一种是正常,我们通过走查内核代码,决定在n_tty_set_termios函数中打点:
probe kernel.function("n_tty_set_termios").return
{
if (kernel_string($tty->name) =~"tty*")---------------tty1到ttyn都能记录
printf ("pid=%d,ICANON=%d,ttyname=%s,cmd=%s\r\n", pid(),($tty->termios->c_lflag)&0x0000002,kernel_string($tty->name), execname())
}
这样只要修改tty属性,我们都能记录下来。
然后是漫长的复现过程,好在经过几天的加压,复现出来了。
pid=1,ICANON=2,ttyname=tty2,cmd=systemd
pid=1,ICANON=2,ttyname=tty2,cmd=systemd
pid=1,ICANON=2,ttyname=tty2,cmd=systemd
pid=1,ICANON=2,ttyname=tty2,cmd=systemd
pid=2019,ICANON=2,ttyname=tty2,cmd=systemd-logind
pid=2019,ICANON=2,ttyname=tty4,cmd=systemd-logind
pid=2019,ICANON=2,ttyname=tty5,cmd=systemd-logind
pid=11250,ICANON=0,ttyname=tty3,cmd=bash
pid=1,ICANON=2,ttyname=tty3,cmd=systemd
pid=1,ICANON=2,ttyname=tty3,cmd=systemd
pid=32642,ICANON=2,ttyname=tty2,cmd=(agetty)
pid=32642,ICANON=2,ttyname=tty2,cmd=(agetty)
pid=32642,ICANON=2,ttyname=tty2,cmd=(agetty)
pid=32642,ICANON=2,ttyname=tty2,cmd=(agetty)
确实会有进程去修改ICANON属性为1。
我们操作tty使用如下方式:
s_ConsoleOutFd = open("/dev/console",O_RDWR,0);
由于没有设置非阻塞模式,导致了这个问题。
记录linux tty的一次软锁排查的更多相关文章
- 记录linux tty的一次软锁排查2
在复现tty的死锁问题的时候,文洋兄使用了如下的方式: #include <fcntl.h> #include <unistd.h> #include <stdio.h& ...
- Smart210学习记录------linux串口驱动
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...
- linux下创建和删除软、硬链接
linux下创建和删除软.硬链接 在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复制 ...
- Linux TTY框架【转】
本文转载自:http://ju.outofmemory.cn/entry/281168 1. 前言 由于串口的缘故,TTY是Linux系统中最普遍的一类设备,稍微了解Linux系统的同学,对它都不陌生 ...
- 通过登入IP记录Linux所有用户登录所操作的日志
通过登入IP记录Linux所有用户登录所操作的日志 对于Linux用户操作记录一般通过命令history来查看历史记录,但是如果在由于误操作而删除了重要的数据的情况下,history命令就不会有什么作 ...
- 记录Linux下安装elasticSearch时遇到的一些错误
记录Linux下安装elasticSearch时遇到的一些错误 http://blog.sina.com.cn/s/blog_c90ce4e001032f7w.html (2016-11-02 22: ...
- Linux TTY驱动--Serial Core层【转】
转自:http://blog.csdn.net/sharecode/article/details/9197567 版权声明:本文为博主原创文章,未经博主允许不得转载. 接上一节: Linux TTY ...
- 如何记录linux终端下的操作日志
如何记录linux终端下的操作日志 在linux终端下,为方便检查操作中可能出现的错误,以及避免屏幕滚屏的限制,我们可以把操作日志记录下来.常用的工具有 screen,script,以及tee等,通过 ...
- Linux tty驱动架构
Linux tty子系统包含:tty核心,tty线路规程和tty驱动.tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱 ...
随机推荐
- [Java] 在 jar 文件中读取 resources 目录下的文件
注意两点: 1. 将资源目录添加到 build path,确保该目录下的文件被拷贝到 jar 文件中. 2. jar 内部的东西,可以当作 stream 来读取,但不应该当作 file 来读取. 例子 ...
- Geohash-》基本使用
我把类文件放到了以上这个路径,在要使用的文件引入使用. 以下是测试代码, 1.先实例化类 2.再调用函数 3.这个函数返回GeoHash编码
- [Spark內核] 第42课:Spark Broadcast内幕解密:Broadcast运行机制彻底解密、Broadcast源码解析、Broadcast最佳实践
本课主题 Broadcast 运行原理图 Broadcast 源码解析 Broadcast 运行原理图 Broadcast 就是将数据从一个节点发送到其他的节点上; 例如 Driver 上有一张表,而 ...
- [Spark性能调优] 第二章:彻底解密Spark的HashShuffle
本課主題 Shuffle 是分布式系统的天敌 Spark HashShuffle介绍 Spark Consolidated HashShuffle介绍 Shuffle 是如何成为 Spark 性能杀手 ...
- 第四章 go语言 数组、切片和映射
文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ 数组是由同构的元素组成.结构体是由异构的元素组成.数据和结构体都是有固定内存大小的数 ...
- mimtproxy和arpspoof实现局域网MITM
本地环境 环境:kali系统 目标机器:192.168.0.101 局域网网关:192.168.0.1 当前网络网卡端口:wlan0 arp欺骗流程 命令行开启本地数据转发: echo > /p ...
- Spring框架入门之Spring简介
一.Spring简介(由Rod Johnson创建的一个开源框架) Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿 ...
- while循环写3次用户名密码验证程序
#变量来自原始用户名和密码 username = 'admin' password = 'nimda' #变量来自计数器 count = 0 #循环条件计数器小于3,则执行while代码块 while ...
- [转载]阿里云MySQL优化主从同步,降低数据延迟
1. 背景 为了提高系统的可用性和数据保护,MySQL通常采用master-slave的部署结构,简单高效,master和slave之间使用binlog来复制数据. binlog支持statement ...
- node 和git 在linux(centos) 上的安装
1. wget命令下载Node.js安装包. (该安装包是编译好的文件,解压之后,在bin文件夹中就已存在node和npm,无需重复编译.) wget https://nodejs.org/dist ...