linux 的那些hung 检测机制
在dmesg中,看到如下信息:
[424948.577401] ixgbe ::00.0 eth4: Fake Tx hang detected with timeout of seconds
[424949.535143] ixgbe ::00.1 eth5: Fake Tx hang detected with timeout of seconds
[424955.536045] ixgbe :af:00.0 eth6: Fake Tx hang detected with timeout of seconds
[424955.567988] ixgbe :af:00.1 eth7: Fake Tx hang detected with timeout of seconds
[424957.579250] ixgbe ::00.1 eth1: Fake Tx hang detected with timeout of seconds
[424957.579285] ixgbe :3b:00.1 eth3: Fake Tx hang detected with timeout of seconds
[424958.568923] ixgbe ::00.0 eth4: Fake Tx hang detected with timeout of seconds
[424959.526676] ixgbe ::00.1 eth5: Fake Tx hang detected with timeout of seconds
[424975.489166] ixgbe :af:00.0 eth6: Fake Tx hang detected with timeout of seconds
[424975.553019] ixgbe :af:00.1 eth7: Fake Tx hang detected with timeout of seconds
[424977.532376] ixgbe ::00.1 eth1: Fake Tx hang detected with timeout of seconds
[424977.532409] ixgbe :3b:00.1 eth3: Fake Tx hang detected with timeout of seconds
检测超时的函数:
static void fm10k_tx_timeout(struct net_device *netdev)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
bool real_tx_hang = false;
int i; #define TX_TIMEO_LIMIT 16000
for (i = ; i < interface->num_tx_queues; i++) {
struct fm10k_ring *tx_ring = interface->tx_ring[i]; if (check_for_tx_hang(tx_ring) && fm10k_check_tx_hang(tx_ring))
real_tx_hang = true;
} if (real_tx_hang) {
fm10k_tx_timeout_reset(interface);
} else {
netif_info(interface, drv, netdev,
"Fake Tx hang detected with timeout of %d seconds\n",
netdev->watchdog_timeo / HZ); /* fake Tx hang - increase the kernel timeout */
if (netdev->watchdog_timeo < TX_TIMEO_LIMIT)
netdev->watchdog_timeo *= ;-----------按倍数递增,直到大于16s,本文就是5-10-20递增,
}
}
网卡检测是否hung的关键函数是 fm10k_tx_timeout,如果 if (check_for_tx_hang(tx_ring) && fm10k_check_tx_hang(tx_ring)) 条件满足,则会属于real hung,否则是fake hung。
check_for_tx_hang(tx_ring)肯定都是满足的,一般在probe的时候就会设置,fm10k_check_tx_hang 的代码如下:
bool fm10k_check_tx_hang(struct fm10k_ring *tx_ring)
{
u32 tx_done = fm10k_get_tx_completed(tx_ring);
u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
u32 tx_pending = fm10k_get_tx_pending(tx_ring, true); clear_check_for_tx_hang(tx_ring); /* Check for a hung queue, but be thorough. This verifies
* that a transmit has been completed since the previous
* check AND there is at least one packet pending. By
* requiring this to fail twice we avoid races with
* clearing the ARMED bit and conditions where we
* run the check_tx_hang logic with a transmit completion
* pending but without time to complete it yet.
*/
if (!tx_pending || (tx_done_old != tx_done)) {-----------------没有pending的报文,或者pending的值没变过
/* update completed stats and continue */
tx_ring->tx_stats.tx_done_old = tx_done;
/* reset the countdown */
clear_bit(__FM10K_HANG_CHECK_ARMED, &tx_ring->state); return false;
} /* make sure it is true for two checks in a row */
return test_and_set_bit(__FM10K_HANG_CHECK_ARMED, &tx_ring->state);----------------两次alarm,则肯定返回true
}
伴随网卡hung打印的,一般都有cpu的softlock,如果cpu 是softlock,而且tx做了cpu绑定的话,那么该cpu对应的tx则会没有pending报文,从而触发hung。如果没有做绑定,则这个tx可能被多个cpu来使用,如果再出现hung,则要查看对应的tx的锁,是否被拿了没有释放。
阶段性总结一下:
内核中检测hung有不同的对象,不同的级别。
1.本文说的网卡的hung,针对的是某个设备,级别是网卡的队列,原理是检测是否有pending的tx包超时没有处理。它依赖于网卡设备正常。
2.还有一种检测某个调度进程的hung的机制,就是hung_task.c文件中的khungtaskd内核线程,该内核线程检测处于uninterrupt状态的进程持续的时间,如果大于一个阈值,则认为该进程hung住了,这个检测的方法是遍历task,然后看task的调度次数是否变化了,这个是单个进程级别。对象是处于uninterrupt状态的进程如果时间长了,则认为hung,它依赖于调度。
3.一种是检测softlock导致的hung,主要是检测某个cpu级别进程调度是否正常,是watchdog内核线程来做的,因为它是实时进程,如果前后两次它没有获取到调度,则说明调度出了问题,这个前后是指通过hrtimer的硬中断来触发的wakeup来判断。这个对象是某个cpu核(到超线程级别)。它依赖于硬中断,关抢占时间长了没有让出cpu,则会出softlock。
4.一种是检测hardlock的hung,它依赖于nmi,原理就是利用3里面那个hrtimer,每次3里面的hrtimer来了,则增长 当前cpu的 hrtimer_interrupts ,如果前后两次nmi的回调检测这个计数没有增长,则认为cpu遇到了hardlock,也就是关中断时间长了,则会出hardlock。
下面详细描述:
[root@centos7 WakeTest]# ps -ef |grep -i khungtaskd |grep -v grep
root 9月04 ? :: [khungtaskd]----------------------检测处于D状态的进程是否长时间未被调度
名称是khungtaskd,和watchdog注意区分:
static int __init hung_task_init(void)
{
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
watchdog_task = kthread_run(watchdog, NULL, "khungtaskd");--------虽然内核线程的函数是watchdog,但是线程名字却是khungtaskd return ;
}
另外一个名称为watchdog内核线程:
ps |grep -i watchdog
ffff880c11980080 IN 0.0 [watchdog/]
ffff880c11a2b580 IN 0.0 [watchdog/]
ffff880c11a56a80 IN 0.0 [watchdog/]
ffff880c11a62080 IN 0.0 [watchdog/]
ffff880c11a9f580 IN 0.0 [watchdog/]
ffff880c11aa8a80 IN 0.0 [watchdog/]
ffff880c11ab4080 IN 0.0 [watchdog/]
ffff880c11acd580 IN 0.0 [watchdog/]
ffff880c11ad6a80 IN 0.0 [watchdog/]
ffff880c11b04080 IN 0.0 [watchdog/]
ffff880c11b45580 IN 0.0 [watchdog/]
ffff880c11b4ea80 IN 0.0 [watchdog/]
ffff880c11b5e080 IN 0.0 [watchdog/]
ffff880c11b77580 IN 0.0 [watchdog/]
ffff880c11b80a80 IN 0.0 [watchdog/]
ffff880c11baa080 IN 0.0 [watchdog/]
这个是由watchdog.c中,每个cpu一个:
static struct smp_hotplug_thread watchdog_threads = {
.store = &softlockup_watchdog,
.thread_should_run = watchdog_should_run,
.thread_fn = watchdog,
.thread_comm = "watchdog/%u",
.setup = watchdog_enable,
.cleanup = watchdog_cleanup,
.park = watchdog_disable,
.unpark = watchdog_enable,
};
使能的一些函数以及回调:
/*
* common function for watchdog, nmi_watchdog and soft_watchdog parameter
*
* caller | table->data points to | 'which' contains the flag(s)
* -------------------|-----------------------|-----------------------------
* proc_watchdog | watchdog_user_enabled | NMI_WATCHDOG_ENABLED or'ed
* | | with SOFT_WATCHDOG_ENABLED
* -------------------|-----------------------|-----------------------------
* proc_nmi_watchdog | nmi_watchdog_enabled | NMI_WATCHDOG_ENABLED
* -------------------|-----------------------|-----------------------------
* proc_soft_watchdog | soft_watchdog_enabled | SOFT_WATCHDOG_ENABLED
*/
要关闭这些内核线程,使用:
[root@centos7 WakeTest]# echo > /proc/sys/kernel/watchdog
[root@centos7 WakeTest]# ps -ef |grep -w watchdog |grep -v grep
[root@centos7 WakeTest]#
[root@centos7 WakeTest]#
[root@centos7 WakeTest]# echo > /proc/sys/kernel/watchdog
[root@centos7 WakeTest]# ps -ef |grep -w watchdog |grep -v grep
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
root : ? :: [watchdog/]
他们都是实时进程:
top - :: up :, users, load average: 41.97, 45.49, 48.37
Tasks: total, running, sleeping, stopped, zombie
%Cpu(s): 7.1 us, 14.7 sy, 0.0 ni, 54.7 id, 4.2 wa, 2.5 hi, 16.8 si, 0.0 st, 57.3 id_exact, 2.9 hi_exact, 20.0 irq_exact
KiB Mem : +total, free, +used, +buff/cache
KiB Swap: total, free, used. +avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
root rt S 0.0 0.0 :00.10 watchdog/3
watchdog检测的原理是:
watchdog函数负责根据当前时间戳来更新一个自己保存的时间戳percpu变量watchdog_touch_ts (取到s级别)
,然后另外的一个hrtimer负责比较当前时间与watchdog_touch_ts 这个变量的差值,如果这个差值大于某个阈值watchdog,则认为异常。 hrtimer同时负责wakeup watchdog线程,
static int is_softlockup(unsigned long touch_ts)-----------------------touch_ts就是watchdog线程write的时间
{
unsigned long now = get_timestamp(); if ((watchdog_enabled & SOFT_WATCHDOG_ENABLED) && watchdog_thresh){
/* Warn about unreasonable delays. */
if (time_after(now, touch_ts + get_softlockup_thresh()))
return now - touch_ts;
}
return ;
}
这个检测机制,大家可以看到,明显依赖于硬中断的到来,假设某个cpu关闭硬中断很长的时间,那显然就没办法保证watchdog的运行了,所以又必要检测一下,这个hardlock登上舞台。
static bool is_hardlockup(void)
{
unsigned long hrint = __this_cpu_read(hrtimer_interrupts); if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
return true; __this_cpu_write(hrtimer_interrupts_saved, hrint);
return false;
}
linux 的那些hung 检测机制的更多相关文章
- Linux内核死锁检测机制【转】
转自:http://www.oenhan.com/kernel-deadlock-check 死锁就是多个进程(线程)因为等待别的进程已占有的自己所需要的资源而陷入阻塞的一种状态,死锁状态一旦形成,进 ...
- 转:Linux内部的时钟处理机制全面剖析
Linux内部的时钟处理机制全面剖析 在 Linux 操作系统中,很多活动都和时间有关,例如:进程调度和网络处理等等.所以说,了解 Linux 操作系统中的时钟处理机制有助于更好地了解 Linux 操 ...
- linux新内核的时钟机制代码
http://blog.chinaunix.net/uid-22810130-id-384173.html 如果说cfs是linux的一个很有创意的机制的话,那么linux中另一个创意就是nohz,我 ...
- hung task机制
最近在修改内核源码的时候一直出现格式化磁盘的时候,进程会出现状态D,看内核日志会看到如下信息: INFO: task filebench: blocked seconds. Oct :: localh ...
- kernel 3.10内核源码分析--hung task机制
kernel 3.10内核源码分析--hung task机制 一.相关知识: 长期以来,处于D状态(TASK_UNINTERRUPTIBLE状态)的进程 都是让人比较烦恼的问题,处于D状态的进程不能接 ...
- Linux mips64r2 PCI中断路由机制分析
Linux mips64r2 PCI中断路由机制分析 本文主要分析mips64r2 PCI设备中断路由原理和irq号分配实现方法,并尝试回答如下问题: PCI设备驱动中断注册(request_irq) ...
- Linux的原子操作与同步机制
Linux的原子操作与同步机制 .进程1执行完“mov eax, [count]”后,寄存器eax内保存了count的值0.此时,进程2被调度执行,抢占了进程1的CPU的控制权.进程2执行“cou ...
- U3D-页游-检测机制-webplayer-调试方法
前言 页游目前有两个客户端入口: 网页端 (unity webplayer) 游戏微端 (unity standalone) 关于微端的技术,可参考我之前的文章: dotNet开发游戏微端 游戏微端的 ...
- 【Linux下进程机制】从一道面试题谈linux下fork的运行机制
今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #include "stdio.h" #includ ...
随机推荐
- centos7共享文件夹到windows访问--samba
第一步:安装samba服务 yum install samba 第二步:启动samba服务 systemctl start smb 查看samba的状态 systemctl status smb 看到 ...
- leetcode题解 5. Longest Palindromic Substring
题目: Given a string s, find the longest palindromic substring in s. You may assume that the maximum l ...
- video自动填充满父级元素
想要video能自动填充慢父div的大小,只要给video标签加上style="width= 100%; height=100%; object-fit: fill"即可. obj ...
- (转)junit简介
什么是单元测试? 所谓单元测试是测试应用程序的功能是否能够按需要正常运行,并且确保是在开发人员的水平上,单元测试生成图片.单元测试是一个对单一实体(类或方法)的测试.单元测试是每个软件公司提高产品质量 ...
- EasyUI datagrid 序列 化后时间 处理 九
@{ ViewBag.Title = "Home Page"; Layout = null; } <!DOCTYPE html> <html> <he ...
- APK重编译
最近沉迷某游戏 尝试了一些不可描述的东西 , 记录一下研究过程 具体是哪个app不公开 ... 准备工具 APKtool && signapk && jre .net ...
- 生产redis client 链接报:ERR max number of clients reached 含义: 达到最大客户端数错误
1.通过netstat 命令查看TCP又11822个连接 (netstat命令是一个监控TCP/IP网络的非常有用的工具) 2.默认redis最大的连接数10000 ,但是此时无法连接redis客户 ...
- PythonStudy——字符串扩展方法 String extension method
')) ')) print('***000123123***'.lstrip('*')) print('***000123123***'.rstrip('*')) print('华丽分割线'.cent ...
- Centos7.3 之mysql5.7二进制安装
#!/bin/bash #注意,该脚本是在centos7.3非生产环境下测试的,其他版本的系统可能不适用,要根据情况修改.需要先下载好mysql二进制包到本地(我一般都是在root家目录下操作,文件也 ...
- Linux-入门配置jdk,tomcat,mysql
Mysql安装 大家可以在这里下 http://mirrors.163.com/mysql/Downloads/MySQL-5.7/ 1)查看CentOS自带的mysql rpm -qa | grep ...