在Linux环境机器上面进行测试的时候,经常会报softlockup问题,而导致系统panicSoftlockup是内核中进行死锁检查的一种机制,在2.6.X内核中是在softlockup.c文件中实现,在新的3.X内核中是在watchdog.c文件中实现的。


Softlockup是用来检测内核长时间不发生调度的情况,它的工作原理是在内核中启动一个优先级为MAX_RT_PRIO – 1FIFO进程,在此进程里面会刷新时间戳。如果此时间戳超过设定的时间阈值没有更新,则会报softlockup错误


下面结合代码来分析softlockup实现。系统启动调用

lockup_detector_init函数

àwatchdog_enable_all_cpus函数

watchdog_enable_all_cpus函数会在每个cpu都创建一个watchdog_threads内核线程

static struct smp_hotplug_threadwatchdog_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, 

};  


内核线程的名字为watchdog/%u与每个CPU就是watchdog0watchdog1等,线程函数为watchdog。在创建线程的时候会调用watchdog_enable函数:

static void watchdog_enable(unsigned intcpu) 

{  

    struct hrtimer*hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);                                                        

 

    hrtimer_init(hrtimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); 

    hrtimer->function =  watchdog_timer_fn; 

 

    hrtimer_start(hrtimer,ns_to_ktime(sample_period), HRTIMER_MODE_REL_PINNED); 

 

    watchdog_set_prio(SCHED_FIFO,MAX_RT_PRIO -  1); 

    __touch_watchdog(); 

}  

首先获取当前CPUper cpu变量watchdog_hrtimer,启动一个hrtimerhrtimer的处理函数为watchdog_timer_fn在随后启动此hrtimer

然后调用函数设置进程的调度策略和优先级此内核线程为时的FIFO线程,优先级为MAX_RT_PRIO- 1,优先级最高了这样就能够在进程被唤醒的时候能够强制其它优先级低的线程\进程

最后__touch_watchdog函数中刷新时间戳PER CPU变量watchdog_touch_ts

watchdog/%u线程函数watchdog主要工作就是调用__touch_watchdog函数来刷新时间戳。线程函数是在watchdog_timer_fn中唤醒的。


下面分析下hrtimer处理函数watchdog_timer_fn

static enum hrtimer_restartwatchdog_timer_fn(struct hrtimer *hrtimer) 

{  

    unsigned long touch_ts =__this_cpu_read(watchdog_touch_ts); 

    int softlockup_all_cpu_backtrace =sysctl_softlockup_all_cpu_backtrace; 

 

    wake_up_process(__this_cpu_read(softlockup_watchdog)); 

    hrtimer_forward_now(hrtimer,ns_to_ktime(sample_period)); 

 

    if (touch_ts== 0) { 

        if (unlikely(__this_cpu_read(softlockup_touch_sync))) { 

            __this_cpu_write(softlockup_touch_sync, false);           

            sched_clock_tick(); 

        }  

        __touch_watchdog(); 

        return HRTIMER_RESTART; 

    }  

下面分析下hrtimer处理函数watchdog_timer_fn

首先读取per CPU变量watchdog_touch_ts赋值touch_ts,表示上一次刷新的时间戳。sysctl_softlockup_all_cpu_backtrace变量由用户通过sysctl命令改写或者接口/proc/sys/kernel/softlockup_all_cpu_backtrace来设置。

然后调用wake_up_process函数唤醒cpuwatchdog线程,如果watchdog线程被唤醒就会去刷新时间戳。如果系统关了抢占watchdog线程不会被唤醒,这样时间戳就不会更新。

hrtimer_forward_now函数会将此hrtimer的下次到期时间设置为从现在开始的sample_period纳秒之后

如果touch_ts0,表示第一次hrtimer到期,直接刷新时间戳,并重新启动此定时器。

    duration =is_softlockup(touch_ts); 

    if (unlikely(duration)) {  

        if (__this_cpu_read(soft_watchdog_warn)== true)  

            return HRTIMER_RESTART; 

        if (softlockup_all_cpu_backtrace) {  

            if (test_and_set_bit(0,&soft_lockup_nmi_warn)) {                                                                                         

                __this_cpu_write(soft_watchdog_warn, true); 

                return HRTIMER_RESTART; 

            }  

        } 

is_softlockup函数会判断当前时间与上次刷新时间touch_ts差值如果差值大于设定的阈值,就返回差值即变量duration,否则返回0

如果duration0,则表示内核有超过设定阈值时间没有发生调度。

        printk(KERN_EMERG"BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", smp_processor_id(),duration,             

                                                       current->comm, task_pid_nr(current)); 

        print_modules(); 

        print_irqtrace_events(current); 

        if (regs) 

            show_regs(regs); 

        else  

            dump_stack(); 

        if (softlockup_all_cpu_backtrace) {  

            trigger_allbutself_cpu_backtrace(); 

            clear_bit(0,&soft_lockup_nmi_warn);    

            smp_mb__after_atomic(); 

        }  

 

        if (softlockup_panic) 

            panic("softlockup: hung tasks"); 

        __this_cpu_write(soft_watchdog_warn, true); 

    }  else  

        __this_cpu_write(soft_watchdog_warn, false); 

上面的代码打印softlockup信息,包括模块信息、寄存器信息、堆栈信息等。如果变量softlockup_all_cpu_backtrace有设置,还会其它的CPU发生IPI中断,触发softlockup信息

变量softlockup_panic可以通过sysctlproc接口设置,在使能的情况下,系统会panic




GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐