Linux 内核中的 Soft 和 Hard Lockup

这周遇到了一个内核关于 softlockup 和 hardlockup 相关的 bug, 首先在内核文档中找到了关于他们的定义和实现的介绍的非常详细,还在网上找到了更多关于他们的介绍和很细可以查看文后参考的博客1. 首先来介绍下 softlockup 和 hardlockup 在内核中怎么定义的:softlockup 是导致内核在内核态下循环超过20秒(这个时间是可以通过内核参数设置的)...
摘要由CSDN通过智能技术生成

这周遇到了一个内核关于 softlockuphardlockup 相关的 bug, 首先
内核文档中找到了关于他们的定义和实现的介绍的非常详细,还在网上找到了
更多关于他们的介绍和很细可以查看文后参考的博客

1. 首先来介绍下 softlockuphardlockup 在内核中怎么定义的:

softlockup 是导致内核在内核态下循环超过20秒(这个时间是可以通过内核参数设置的)
的错误,而不给其他任务提供运行机会。检测时显示当前堆栈跟踪,默认情况下,系统将保持
锁定状态。或者,内核可以配置为 kernel panic; 通过 sysctl kernel.softlockup_panic,内
核提供了一个参数 softlockup_panic,并为此提供了编译选项 BOOTPARAM_SOFTLOCKUP_PANIC

hardlockup 是导致 CPU 在内核态下循环超过10秒的错误,而不会让其他中断有机会运行。
softlockup 情况类似,当检测到时会显示当前堆栈跟踪,除非更改默认行为,否则系统将保持锁定
状态,这个状态也可以通过 sysctl hardlockup_panic进行修改,编译内核的选项是BOOTPARAM_HARDLOCKUP_PANIC,还有一个和其有关的内核参数 nmi_watchdog

panic 选项可以与 panic_timeout 结合使用(可以kernel.panic sysctl设置),以使系统在指定的时间后自动重启。

具体相关的详细参数可以参考内核中的 “Documentation/admin-guide/kernel-parameters.rst”

总的说来:

  • softlockup 是该 CPU 的无法调度到其他的进程运行
  • hardlockup 是该 CPU 不仅进程无法调度,而且中断也不能运行了(NMI除外, NMI是不可屏蔽的中断)

这里说的 lockup 是指运行在内核态的代码 lockup,用户态的代码是可以被抢占的,还有就是内核代码必须处于
禁止内核抢占的状态(preemption disabled), 因为Linux内核是支持抢占的,只有在一些特定的代码段中才
禁止内核抢占,在这些代码段中才有可嫩发生 lockup

2. softlockup 和 hardlockup 原理

soft 和 hard lockup 是基于 hrtimerperf 子系统实现的

hardlockup 实现的原理:

hardlockup 利用周期性的 hrtimer 运行以生成中断并启动监视任务。每个 watchdog_thresh
(编译时初始化为 10, 并可通过sysctl进行配置)秒生成 NMI perf事件,以检查hardlockup。
如果系统中的任何CPU在此期间没有收到任何 hrtimer 中断,则 hardlockup detector(NMI perf事件的处理程序)
将生成内核警告或调用恐慌,具体取决于配置。

softlockup 实现的原理:

watchdog 任务是一个高优先级内核线程,每次调度时都会更新一个时间戳。如果该时间戳没有更新 2 * watchdog_thresh 秒(软锁定阈值),则 softlockup detector (在hrtimer回调函数内编码)会将有用的调试信息转储到系统日志中,之后
它将根据系统设置是 调用 panic 或 继续执行其他内核代码

hrtimer 的周期是 2 * watchdog_thresh / 5,这意味着它有两到三次机会在硬件锁定检测器启动之前产生中断。

默认情况下,每个激活的 CPU 上都运行一个 watchdog 线程,命名为 [watchdog/%d]。但是,在配置了 NO_HZ_FULL
的内核上,默认情况下,watchdog 仅在核心上运行,而不在 nohz_full 引导参数中指定的核心上运行。
如果我们允许看门狗默认运行在“nohz_full”内核上,我们必须运行定时器滴答来激活调度程序,这将阻止 nohz_full
功能保护这些内核上的用户代码不受内核影响。

当然,默认情况下在 nohz_full 核心上禁用它意味着当这些 CPU核 进入内核时,默认情况下我们将无法检测它们是否锁定。
但是,允许 watchdog 继续在 housekeeping(non-tickless)核上运行意味着我们将继续在这些内核上正确检测锁定。

在任何一种情况下,可以通过 kernel.watchdog_cpumask sysctl调整排除运行看门狗的核心集。对于 nohz_full核,
这可能对调试内核似乎挂在 nohz_full 内核上的情况很有用。

softlockup_panic=
        [KNL] Should the soft-lockup detector generate panics.
        Format: <integer>

nmi_watchdog=   [KNL,BUGS=X86] Debugging features for SMP kernels
        Format: [panic,][nopanic,][num]
        Valid num: 0 or 1
        0 - turn hardlockup detector in nmi_watchdog off
        1 - turn hardlockup detector in nmi_watchdog on
        When panic is specified, panic when an NMI watchdog
        timeout occurs (or 'nopanic' to override the opposite
        default). To disable both hard and soft lockup detectors,
        please see 'nowatchdog'.
        This is useful when you use a panic=... timeout and
        need the box quickly up again.

watchdog_cpumask:

This value can be used to control on which cpus the watchdog may run.
The default cpumask is all possible cores, but if NO_HZ_FULL is
enabled in the kernel config, and cores are specified with the
nohz_full= boot argument, those cores are excluded by default.
Offline cores can be included in this mask, and if the core is later
brought online, the watchdog will be started based on the mask value.

Typically this value would only be touched in the nohz_full case
to re-enable cores that by default were not running the watchdog,
if a kernel lockup was suspected on those cores.

The argument value is the standard cpulist format for cpumasks,
so for example to enable the watchdog on cores 0, 2, 3, and 4 you
might say:

  echo 0,2-4 > /proc/sys/kernel/watchdog_cpumask

3. 代码实现与分析

下面我们以 Linux 4.14 的内核版本来分析 Linux 如何实现这两种lockup的探测的:

soft 和 hard lockup 是基于 hrtimerperf 子系统实现的

这里我们可以看到要把 watchdog 注册到内核中去,这里的 watchdog 不是硬件的 watchdog,而是通过 NMI 来模拟
一个监控程序起个名字叫 watchdog 而已

从下面的代码可以看到在系统启动转载这个模块的时候,会为每个 CPU core 注册一个 kernel 线程,名字为 watchdgo/%u
这个线程会定期调用 watchdog 函数

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,
};

/*
 * Create the watchdog thread infrastructure and configure the detector(s).
 *
 * The threads are not unparked as watchdog_allowed_mask is empty.  When
 * the threads are sucessfully initialized, take the proper locks and
 * unpark the threads in the watchdog_cpumask if the watchdog is enabled.
 */
static __init void lockup_detector_setup(void)
{
   
        int ret;

        /*
         * If sysctl is off and watchdog got disabled on the command line,
         * nothing to do here.
         */
        lockup_detector_update_enable();

        if (!IS_ENABLED(CONFIG_SYSCTL) &&
            !(watchdog_enabled && watchdog_thresh))
                return;

        ret = smpboot_register_percpu_thread_cpumask(&watchdog_threads,
                                                     &watchdog_allowed_mask);
        if (ret) {
   
                pr_err("Failed to initialize soft lockup detector threads\n");
                return;
        }

   
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值