在dmesg中,看到如下信息:

[424948.577401] ixgbe 0000:86:00.0 eth4: Fake Tx hang detected with timeout of 5 seconds
[424949.535143] ixgbe 0000:86:00.1 eth5: Fake Tx hang detected with timeout of 5 seconds
[424955.536045] ixgbe 0000:af:00.0 eth6: Fake Tx hang detected with timeout of 10 seconds
[424955.567988] ixgbe 0000:af:00.1 eth7: Fake Tx hang detected with timeout of 10 seconds
[424957.579250] ixgbe 0000:18:00.1 eth1: Fake Tx hang detected with timeout of 10 seconds
[424957.579285] ixgbe 0000:3b:00.1 eth3: Fake Tx hang detected with timeout of 10 seconds
[424958.568923] ixgbe 0000:86:00.0 eth4: Fake Tx hang detected with timeout of 10 seconds
[424959.526676] ixgbe 0000:86:00.1 eth5: Fake Tx hang detected with timeout of 10 seconds
[424975.489166] ixgbe 0000:af:00.0 eth6: Fake Tx hang detected with timeout of 20 seconds
[424975.553019] ixgbe 0000:af:00.1 eth7: Fake Tx hang detected with timeout of 20 seconds
[424977.532376] ixgbe 0000:18:00.1 eth1: Fake Tx hang detected with timeout of 20 seconds
[424977.532409] ixgbe 0000:3b:00.1 eth3: Fake Tx hang detected with timeout of 20 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 16000for (i = 0; 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 *= 2;-----------按倍数递增,直到大于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状态的进程,它依赖于调度。

3.一种是检测softlock导致的hung,主要是检测某个cpu级别进程调度是否正常,是watchdog内核线程来做的,因为它是实时进程,如果前后两次它没有获取到调度,则说明调度出了问题,这个前后是指通过hrtimer的硬中断来触发的wakeup来判断。这个对象是某个cpu核(到超线程级别)。它依赖于硬中断。

4.一种是检测hardlock的hung,它依赖于nmi,原理就是利用3里面那个hrtimer,每次3里面的hrtimer来了,则增长 当前cpu的 hrtimer_interrupts ,如果前后两次nmi的回调检测这个计数没有增长,则认为cpu遇到了hardlock。

下面详细描述:

[root@centos7 WakeTest]# ps -ef |grep -i khungtaskd |grep -v grep
root        93     2  0 9月04 ?       00:00:00 [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,但是线程名字却是khungtaskdreturn 0;
}

另外一个名称为watchdog内核线程:

ps |grep -i watchdog6      2   0  ffff880c11980080  IN   0.0       0      0  [watchdog/0]10      2   1  ffff880c11a2b580  IN   0.0       0      0  [watchdog/1]14      2   2  ffff880c11a56a80  IN   0.0       0      0  [watchdog/2]18      2   3  ffff880c11a62080  IN   0.0       0      0  [watchdog/3]22      2   4  ffff880c11a9f580  IN   0.0       0      0  [watchdog/4]26      2   5  ffff880c11aa8a80  IN   0.0       0      0  [watchdog/5]30      2   6  ffff880c11ab4080  IN   0.0       0      0  [watchdog/6]34      2   7  ffff880c11acd580  IN   0.0       0      0  [watchdog/7]38      2   8  ffff880c11ad6a80  IN   0.0       0      0  [watchdog/8]42      2   9  ffff880c11b04080  IN   0.0       0      0  [watchdog/9]46      2  10  ffff880c11b45580  IN   0.0       0      0  [watchdog/10]50      2  11  ffff880c11b4ea80  IN   0.0       0      0  [watchdog/11]54      2  12  ffff880c11b5e080  IN   0.0       0      0  [watchdog/12]58      2  13  ffff880c11b77580  IN   0.0       0      0  [watchdog/13]62      2  14  ffff880c11b80a80  IN   0.0       0      0  [watchdog/14]66      2  15  ffff880c11baa080  IN   0.0       0      0  [watchdog/15]

这个是由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 0 > /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 1 > /proc/sys/kernel/watchdog
[root@centos7 WakeTest]# ps -ef |grep -w watchdog |grep -v grep
root     13496     2  0 11:34 ?        00:00:00 [watchdog/0]
root     13497     2  0 11:34 ?        00:00:00 [watchdog/1]
root     13498     2  0 11:34 ?        00:00:00 [watchdog/2]
root     13499     2  0 11:34 ?        00:00:00 [watchdog/3]
root     13500     2  0 11:34 ?        00:00:00 [watchdog/4]
root     13501     2  0 11:34 ?        00:00:00 [watchdog/5]
root     13502     2  0 11:34 ?        00:00:00 [watchdog/6]
root     13503     2  0 11:34 ?        00:00:00 [watchdog/7]
root     13504     2  0 11:34 ?        00:00:00 [watchdog/8]
root     13505     2  0 11:34 ?        00:00:00 [watchdog/9]
root     13506     2  0 11:34 ?        00:00:00 [watchdog/10]
root     13507     2  0 11:34 ?        00:00:00 [watchdog/11]
root     13508     2  0 11:34 ?        00:00:00 [watchdog/12]
root     13509     2  0 11:34 ?        00:00:00 [watchdog/13]
root     13510     2  0 11:34 ?        00:00:00 [watchdog/14]
root     13511     2  0 11:34 ?        00:00:00 [watchdog/15]

他们都是实时进程:

top - 11:07:00 up 20:49, 10 users,  load average: 41.97, 45.49, 48.37
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 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 : 36231846+total, 50661748 free, 11323638+used, 19842035+buff/cache
KiB Swap:        0 total,        0 free,        0 used. 16986171+avail MemPID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND403 root      rt   0       0      0      0 S   0.0  0.0   0:00.10 watchdog/3

watchdog检测的原理是:

watchdog函数负责根据当前时间戳来更新一个自己保存的时间戳percpu变量watchdog_touch_ts (取到s级别)

,然后另外的一个hrtimer负责比较当前时间与watchdog_touch_ts 这个变量的差值,如果这个差值大于某个阈值watchdog,则认为异常。 hrtimer同时负责wakeup watchdog线程,

hrtimer 中用 is_softlockup 用来确定是否已经软锁,按道理唤醒watchdog之后,watchdog应该要调度,同时更新时间戳,如果没有更新,说明没有获得调度,由于watchdog内核线程是
绑定cpu核的实时线程,实时线程未能调度,则代表这个cpu出现了软锁。
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 0;
}

这个检测机制,大家可以看到,明显依赖于硬中断的到来,假设某个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;
}

转载于:https://www.cnblogs.com/10087622blog/p/9558024.html

linux 的那些hung 检测机制相关推荐

  1. Linux中基于eBPF的恶意利用与检测机制(rootkit、驱动)

    目录 前言 现状分析 海外资料 国内资料 eBPF技术恶意利用的攻击原理 网络层恶意利用 Linux系统运行时恶意利用 综述 检测防御 运行前 运行时 运行后 防御 工程实现 系统兼容性 CO-RE ...

  2. Linux驱动——mmc card热插拔检测机制(十)

    Linux驱动--mmc card热插拔检测机制(十) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0   3. 参考博客: [sd card] ...

  3. Linux系列之soft lockup机制 浅析

    Linux系列之soft lockup机制 浅析 1.背景 2.什么是lockup? 2.1 lockup检测机制 2.2 softlockup的工作原理 3.soft lockup机制分析 3.1 ...

  4. Linux内部的时钟处理机制全面剖析

    Linux内部的时钟处理机制全面剖析 在 Linux 操作系统中,很多活动都和时间有关,例如:进程调度和网络处理等等.所以说,了解 Linux 操作系统中的时钟处理机制有助于更好地了解 Linux 操 ...

  5. 依赖包的添加和自动检测机制

    为什么80%的码农都做不了架构师?>>>    xmake将依赖库.依赖头文件.依赖类型.依赖接口统一用 option 选项机制进行了封装,更在上一层引入package包的机制,使得 ...

  6. 专门入侵检测linux叫什么,入侵检测系统分析及其在Linux下的实现(上)

    一.入侵检测系统分析 1.1 什么是入侵检测系统 所谓入侵,是指任何试图危及计算机资源的完整性.机密性或可用性的行为.而入侵检测,顾名思义,便是对入侵行为的发觉.它通过从计算机网络或系统中的若干关键点 ...

  7. Linux中的中断管理机制

    1.中断相关基础知识介绍 1.1.中断产生背景 假设现在CPU需要去获取一个键盘的时间,如果处理器发出一个请求信号之后一直在轮询键盘的响应,由于键盘响应速度比处理器慢得多并且需要等待用户输入,这对于C ...

  8. Linux内存管理:分页机制

    <Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> < ...

  9. (两百八十八)Android R data stall检测机制学习

    1.简介 data stall检测机制就我现在的理解看来是Android 在网络校验成功后,对网络的一种持续监控措施,一旦发现当前网络断网,则通知ConnectivityService,进行相应的处理 ...

最新文章

  1. 利用mysql建立随机森林_随机森林算法实例 - osc_4imme0wh的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. 014、Linux下vim搜索与替换
  3. 【数理知识】《积分变换与场论》王振老师-第4章-矢量分析
  4. 【数据迁移】使用传输表空间迁移数据
  5. matlab 里try用法,matlab在整个程序(全局)中使用try-catch来报告错误
  6. 照片打印预览正常打印空白_照片打印机怎么挑选 照片打印机的选购技巧分享 - 台式电脑...
  7. 摩托罗拉edge X30屏下版真机首曝:四边等宽 屏下显示效果出众
  8. 日志平台查询异常,没有打印异常信息
  9. java中文乱码怎么解决_java中文乱码解决总结
  10. 高中数学建模优秀论文_高中数学建模优秀论文
  11. 自制纯正弦波 12V转220V 1000瓦逆变器做家用太阳能电源
  12. 在ArcCatalog中通过图标来认识ArcGIS中的数据
  13. Python 追加 Excel 数据
  14. (转载)解决电脑同时使用有线网上内网,无线网上外网的冲突
  15. Pandas快速合并多张excel表格
  16. js过滤检测敏感词汇
  17. 准备就绪的定义被认为是有害的
  18. 洞察问题本质的思维,你知道吗?
  19. 华为设备配置Telnet与SSH服务实现运程连接网络设备
  20. d3.js——箭头的绘制

热门文章

  1. laravel route函数 404_laravel生成及获取不同类型的URL地址总结
  2. h5打开麦克风权限录音_原来电脑上自带录音功能,很多人还不知道,真的太实用了...
  3. 天使玩偶/SJY摆棋子
  4. Selenium WebDriver的工作原理
  5. 使用WebStorm将项目部署到IIS
  6. Django运行项目时候出现DisallowedHost at / Invalid HTTP_HOST header:
  7. while;do while; for循环
  8. 【收集】腾讯AlloyTeam
  9. Android之使用ThumbnailUtils类来获取视频第一帧缩略图
  10. 二进制漏洞挖掘_漏洞挖掘的艺术-面向二进制的静态漏洞挖掘