The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/softlockup.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Detect Soft Lockups
    3  *
    4  * started by Ingo Molnar, Copyright (C) 2005, 2006 Red Hat, Inc.
    5  *
    6  * this code detects soft lockups: incidents in where on a CPU
    7  * the kernel does not reschedule for 10 seconds or more.
    8  */
    9 #include <linux/mm.h>
   10 #include <linux/cpu.h>
   11 #include <linux/nmi.h>
   12 #include <linux/init.h>
   13 #include <linux/delay.h>
   14 #include <linux/freezer.h>
   15 #include <linux/kthread.h>
   16 #include <linux/lockdep.h>
   17 #include <linux/notifier.h>
   18 #include <linux/module.h>
   19 #include <linux/sysctl.h>
   20 
   21 #include <asm/irq_regs.h>
   22 
   23 static DEFINE_SPINLOCK(print_lock);
   24 
   25 static DEFINE_PER_CPU(unsigned long, touch_timestamp);
   26 static DEFINE_PER_CPU(unsigned long, print_timestamp);
   27 static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
   28 
   29 static int __read_mostly did_panic;
   30 int __read_mostly softlockup_thresh = 60;
   31 
   32 /*
   33  * Should we panic (and reboot, if panic_timeout= is set) when a
   34  * soft-lockup occurs:
   35  */
   36 unsigned int __read_mostly softlockup_panic =
   37                                 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
   38 
   39 static int __init softlockup_panic_setup(char *str)
   40 {
   41         softlockup_panic = simple_strtoul(str, NULL, 0);
   42 
   43         return 1;
   44 }
   45 __setup("softlockup_panic=", softlockup_panic_setup);
   46 
   47 static int
   48 softlock_panic(struct notifier_block *this, unsigned long event, void *ptr)
   49 {
   50         did_panic = 1;
   51 
   52         return NOTIFY_DONE;
   53 }
   54 
   55 static struct notifier_block panic_block = {
   56         .notifier_call = softlock_panic,
   57 };
   58 
   59 /*
   60  * Returns seconds, approximately.  We don't need nanosecond
   61  * resolution, and we don't need to waste time with a big divide when
   62  * 2^30ns == 1.074s.
   63  */
   64 static unsigned long get_timestamp(int this_cpu)
   65 {
   66         return cpu_clock(this_cpu) >> 30LL;  /* 2^30 ~= 10^9 */
   67 }
   68 
   69 static void __touch_softlockup_watchdog(void)
   70 {
   71         int this_cpu = raw_smp_processor_id();
   72 
   73         __raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu);
   74 }
   75 
   76 void touch_softlockup_watchdog(void)
   77 {
   78         __raw_get_cpu_var(touch_timestamp) = 0;
   79 }
   80 EXPORT_SYMBOL(touch_softlockup_watchdog);
   81 
   82 void touch_all_softlockup_watchdogs(void)
   83 {
   84         int cpu;
   85 
   86         /* Cause each CPU to re-update its timestamp rather than complain */
   87         for_each_online_cpu(cpu)
   88                 per_cpu(touch_timestamp, cpu) = 0;
   89 }
   90 EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
   91 
   92 int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
   93                              void __user *buffer,
   94                              size_t *lenp, loff_t *ppos)
   95 {
   96         touch_all_softlockup_watchdogs();
   97         return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
   98 }
   99 
  100 /*
  101  * This callback runs from the timer interrupt, and checks
  102  * whether the watchdog thread has hung or not:
  103  */
  104 void softlockup_tick(void)
  105 {
  106         int this_cpu = smp_processor_id();
  107         unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu);
  108         unsigned long print_timestamp;
  109         struct pt_regs *regs = get_irq_regs();
  110         unsigned long now;
  111 
  112         /* Is detection switched off? */
  113         if (!per_cpu(watchdog_task, this_cpu) || softlockup_thresh <= 0) {
  114                 /* Be sure we don't false trigger if switched back on */
  115                 if (touch_timestamp)
  116                         per_cpu(touch_timestamp, this_cpu) = 0;
  117                 return;
  118         }
  119 
  120         if (touch_timestamp == 0) {
  121                 __touch_softlockup_watchdog();
  122                 return;
  123         }
  124 
  125         print_timestamp = per_cpu(print_timestamp, this_cpu);
  126 
  127         /* report at most once a second */
  128         if (print_timestamp == touch_timestamp || did_panic)
  129                 return;
  130 
  131         /* do not print during early bootup: */
  132         if (unlikely(system_state != SYSTEM_RUNNING)) {
  133                 __touch_softlockup_watchdog();
  134                 return;
  135         }
  136 
  137         now = get_timestamp(this_cpu);
  138 
  139         /*
  140          * Wake up the high-prio watchdog task twice per
  141          * threshold timespan.
  142          */
  143         if (now > touch_timestamp + softlockup_thresh/2)
  144                 wake_up_process(per_cpu(watchdog_task, this_cpu));
  145 
  146         /* Warn about unreasonable delays: */
  147         if (now <= (touch_timestamp + softlockup_thresh))
  148                 return;
  149 
  150         per_cpu(print_timestamp, this_cpu) = touch_timestamp;
  151 
  152         spin_lock(&print_lock);
  153         printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n",
  154                         this_cpu, now - touch_timestamp,
  155                         current->comm, task_pid_nr(current));
  156         print_modules();
  157         print_irqtrace_events(current);
  158         if (regs)
  159                 show_regs(regs);
  160         else
  161                 dump_stack();
  162         spin_unlock(&print_lock);
  163 
  164         if (softlockup_panic)
  165                 panic("softlockup: hung tasks");
  166 }
  167 
  168 /*
  169  * The watchdog thread - runs every second and touches the timestamp.
  170  */
  171 static int watchdog(void *__bind_cpu)
  172 {
  173         struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
  174 
  175         sched_setscheduler(current, SCHED_FIFO, &param);
  176 
  177         /* initialize timestamp */
  178         __touch_softlockup_watchdog();
  179 
  180         set_current_state(TASK_INTERRUPTIBLE);
  181         /*
  182          * Run briefly once per second to reset the softlockup timestamp.
  183          * If this gets delayed for more than 60 seconds then the
  184          * debug-printout triggers in softlockup_tick().
  185          */
  186         while (!kthread_should_stop()) {
  187                 __touch_softlockup_watchdog();
  188                 schedule();
  189 
  190                 if (kthread_should_stop())
  191                         break;
  192 
  193                 set_current_state(TASK_INTERRUPTIBLE);
  194         }
  195         __set_current_state(TASK_RUNNING);
  196 
  197         return 0;
  198 }
  199 
  200 /*
  201  * Create/destroy watchdog threads as CPUs come and go:
  202  */
  203 static int __cpuinit
  204 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
  205 {
  206         int hotcpu = (unsigned long)hcpu;
  207         struct task_struct *p;
  208 
  209         switch (action) {
  210         case CPU_UP_PREPARE:
  211         case CPU_UP_PREPARE_FROZEN:
  212                 BUG_ON(per_cpu(watchdog_task, hotcpu));
  213                 p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
  214                 if (IS_ERR(p)) {
  215                         printk(KERN_ERR "watchdog for %i failed\n", hotcpu);
  216                         return NOTIFY_BAD;
  217                 }
  218                 per_cpu(touch_timestamp, hotcpu) = 0;
  219                 per_cpu(watchdog_task, hotcpu) = p;
  220                 kthread_bind(p, hotcpu);
  221                 break;
  222         case CPU_ONLINE:
  223         case CPU_ONLINE_FROZEN:
  224                 wake_up_process(per_cpu(watchdog_task, hotcpu));
  225                 break;
  226 #ifdef CONFIG_HOTPLUG_CPU
  227         case CPU_UP_CANCELED:
  228         case CPU_UP_CANCELED_FROZEN:
  229                 if (!per_cpu(watchdog_task, hotcpu))
  230                         break;
  231                 /* Unbind so it can run.  Fall thru. */
  232                 kthread_bind(per_cpu(watchdog_task, hotcpu),
  233                              cpumask_any(cpu_online_mask));
  234         case CPU_DEAD:
  235         case CPU_DEAD_FROZEN:
  236                 p = per_cpu(watchdog_task, hotcpu);
  237                 per_cpu(watchdog_task, hotcpu) = NULL;
  238                 kthread_stop(p);
  239                 break;
  240 #endif /* CONFIG_HOTPLUG_CPU */
  241         }
  242         return NOTIFY_OK;
  243 }
  244 
  245 static struct notifier_block __cpuinitdata cpu_nfb = {
  246         .notifier_call = cpu_callback
  247 };
  248 
  249 static int __initdata nosoftlockup;
  250 
  251 static int __init nosoftlockup_setup(char *str)
  252 {
  253         nosoftlockup = 1;
  254         return 1;
  255 }
  256 __setup("nosoftlockup", nosoftlockup_setup);
  257 
  258 static int __init spawn_softlockup_task(void)
  259 {
  260         void *cpu = (void *)(long)smp_processor_id();
  261         int err;
  262 
  263         if (nosoftlockup)
  264                 return 0;
  265 
  266         err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
  267         if (err == NOTIFY_BAD) {
  268                 BUG();
  269                 return 1;
  270         }
  271         cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
  272         register_cpu_notifier(&cpu_nfb);
  273 
  274         atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
  275 
  276         return 0;
  277 }
  278 early_initcall(spawn_softlockup_task);

Cache object: 66cea60d811b95f620a50eb4475f74d7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.