本过程参照了某大侠的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的一次软锁排查的更多相关文章

  1. 记录linux tty的一次软锁排查2

    在复现tty的死锁问题的时候,文洋兄使用了如下的方式: #include <fcntl.h> #include <unistd.h> #include <stdio.h& ...

  2. Smart210学习记录------linux串口驱动

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...

  3. linux下创建和删除软、硬链接

    linux下创建和删除软.硬链接 在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复制 ...

  4. Linux TTY框架【转】

    本文转载自:http://ju.outofmemory.cn/entry/281168 1. 前言 由于串口的缘故,TTY是Linux系统中最普遍的一类设备,稍微了解Linux系统的同学,对它都不陌生 ...

  5. 通过登入IP记录Linux所有用户登录所操作的日志

    通过登入IP记录Linux所有用户登录所操作的日志 对于Linux用户操作记录一般通过命令history来查看历史记录,但是如果在由于误操作而删除了重要的数据的情况下,history命令就不会有什么作 ...

  6. 记录Linux下安装elasticSearch时遇到的一些错误

    记录Linux下安装elasticSearch时遇到的一些错误 http://blog.sina.com.cn/s/blog_c90ce4e001032f7w.html (2016-11-02 22: ...

  7. Linux TTY驱动--Serial Core层【转】

    转自:http://blog.csdn.net/sharecode/article/details/9197567 版权声明:本文为博主原创文章,未经博主允许不得转载. 接上一节: Linux TTY ...

  8. 如何记录linux终端下的操作日志

    如何记录linux终端下的操作日志 在linux终端下,为方便检查操作中可能出现的错误,以及避免屏幕滚屏的限制,我们可以把操作日志记录下来.常用的工具有 screen,script,以及tee等,通过 ...

  9. Linux tty驱动架构

    Linux tty子系统包含:tty核心,tty线路规程和tty驱动.tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱 ...

随机推荐

  1. iOS开发系列

    因为最近面试了一些人,校招.初中级.高级.架构师,各种级别的,发现大家水平差异很大,有的高级的工程师很多问题都回答不上来,所以想梳理下iOS的知识点,写成一个系列,如果时间允许的话,会录制成视频放到网 ...

  2. 在阿里云 ECS 搭建 nginx https nodejs 环境(三、nodejs)

    在阿里云 ECS 搭建 nginx https nodejs 环境(三.nodejs) 在阿里云 ECS 搭建 nginx https nodejs 环境(三.nodejs) 第一步 指定版本源 执行 ...

  3. JavaScript(四)操作符

      6种表达式 原始表达是  初始化表达式 函数定义表达式 函数调用表达式 属性访问表达式 对象创建表达式 操作符 操作符的优先级 属性访问[] .  >  一元操作符 >  */ > ...

  4. Vim 在 windows 环境下的初步配置

    一..下载工具包 vim 程序:下载安装程序 vim-plug 插件: 下载插件管理文件 二. 安装 VIM 1.如果无特别要求,一路选择默认, 在类型选择时,选择 full 2. 配置 vim-pl ...

  5. 登录模块的进化史,带大家回顾java学习历程(二)

    接着前面的登录模块的进化史,带大家回顾java学习历程(一) 继续往下面讲 前面我们去实现登录功能,都是想着要完成这个功能,直接在处理实际业务的类中去开始写具体的代码一步步实现,也就是面向过程的编程. ...

  6. Zabbix实战-简易教程系列

    一.基础篇(安装和接入) Zabbix实战-简易教程--总流程  Zabbix实战-简易教程--整体架构图 Zabbix实战-简易教程--DB安装和表分区 Zabbix实战-简易教程--Server端 ...

  7. 如何调用sklearn模块做交叉验证

    终于搞明白了如何用sklearn做交叉验证!!! 一般在建立完模型之后,我们要预测模型的好坏,为了试验的可靠性(排除一次测试的偶然性)我们要进行多次测试验证,这时就要用交叉验证. sklearn中的s ...

  8. HUST 1555 A Math Homework

    1555 - A Math Homework 时间限制:1秒 内存限制:128兆 338 次提交 131 次通过 题目描述     QKL is a poor and busy guy, and he ...

  9. vijos 1213:80人环游世界

    描述 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. ...

  10. 二维字符数组利用gets输入

    char a[10][81];for(int i=0;i<10;i++)gets(a[i]); a是二维数组的数组名,相当于一维数组的指针,所以a[i]就相当于指向第i个数组的指针,类型就相当于 ...