cregit-Linux how code gets into the kernel

Release 4.12 kernel/watchdog_hld.c

Directory: kernel
/*
 * Detect hard lockups on a system
 *
 * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
 *
 * Note: Most of this code is borrowed heavily from the original softlockup
 * detector, so thanks to Ingo for the initial implementation.
 * Some chunks also taken from the old x86-specific nmi watchdog code, thanks
 * to those contributors as well.
 */


#define pr_fmt(fmt) "NMI watchdog: " fmt

#include <linux/nmi.h>
#include <linux/module.h>
#include <linux/sched/debug.h>

#include <asm/irq_regs.h>
#include <linux/perf_event.h>

static DEFINE_PER_CPU(bool, hard_watchdog_warn);
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);

/* boot commands */
/*
 * Should we panic when a soft-lockup or hard-lockup occurs:
 */

unsigned int __read_mostly hardlockup_panic =
			CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;

static unsigned long hardlockup_allcpu_dumped;
/*
 * We may not want to enable hard lockup detection by default in all cases,
 * for example when running the kernel as a guest on a hypervisor. In these
 * cases this function can be called to disable hard lockup detection. This
 * function should only be executed once by the boot processor before the
 * kernel command line parameters are parsed, because otherwise it is not
 * possible to override this in hardlockup_panic_setup().
 */

void hardlockup_detector_disable(void) { watchdog_enabled &= ~NMI_WATCHDOG_ENABLED; }

Contributors

PersonTokensPropCommitsCommitProp
Babu Moger12100.00%1100.00%
Total12100.00%1100.00%


static int __init hardlockup_panic_setup(char *str) { if (!strncmp(str, "panic", 5)) hardlockup_panic = 1; else if (!strncmp(str, "nopanic", 7)) hardlockup_panic = 0; else if (!strncmp(str, "0", 1)) watchdog_enabled &= ~NMI_WATCHDOG_ENABLED; else if (!strncmp(str, "1", 1)) watchdog_enabled |= NMI_WATCHDOG_ENABLED; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Babu Moger82100.00%1100.00%
Total82100.00%1100.00%

__setup("nmi_watchdog=", hardlockup_panic_setup);
void touch_nmi_watchdog(void) { /* * Using __raw here because some code paths have * preemption enabled. If preemption is enabled * then interrupts should be enabled too, in which * case we shouldn't have to worry about the watchdog * going off. */ raw_cpu_write(watchdog_nmi_touch, true); touch_softlockup_watchdog(); }

Contributors

PersonTokensPropCommitsCommitProp
Babu Moger18100.00%1100.00%
Total18100.00%1100.00%

EXPORT_SYMBOL(touch_nmi_watchdog); static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, .size = sizeof(struct perf_event_attr), .pinned = 1, .disabled = 1, }; /* Callback function for perf event subsystem */
static void watchdog_overflow_callback(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) { /* Ensure the watchdog never gets throttled */ event->hw.interrupts = 0; if (atomic_read(&watchdog_park_in_progress) != 0) return; if (__this_cpu_read(watchdog_nmi_touch) == true) { __this_cpu_write(watchdog_nmi_touch, false); return; } /* check for a hardlockup * This is done by making sure our timer interrupt * is incrementing. The timer interrupt should have * fired multiple times before we overflow'd. If it hasn't * then this is a good indication the cpu is stuck */ if (is_hardlockup()) { int this_cpu = smp_processor_id(); /* only print hardlockups once */ if (__this_cpu_read(hard_watchdog_warn) == true) return; pr_emerg("Watchdog detected hard LOCKUP on cpu %d", this_cpu); print_modules(); print_irqtrace_events(current); if (regs) show_regs(regs); else dump_stack(); /* * Perform all-CPU dump only once to avoid multiple hardlockups * generating interleaving traces */ if (sysctl_hardlockup_all_cpu_backtrace && !test_and_set_bit(0, &hardlockup_allcpu_dumped)) trigger_allbutself_cpu_backtrace(); if (hardlockup_panic) nmi_panic(regs, "Hard LOCKUP"); __this_cpu_write(hard_watchdog_warn, true); return; } __this_cpu_write(hard_watchdog_warn, false); return; }

Contributors

PersonTokensPropCommitsCommitProp
Babu Moger14692.99%150.00%
Don Zickus117.01%150.00%
Total157100.00%2100.00%

/* * People like the simple clean cpu node info on boot. * Reduce the watchdog noise by only printing messages * that are different from what cpu0 displayed. */ static unsigned long firstcpu_err; static atomic_t watchdog_cpus;
int watchdog_nmi_enable(unsigned int cpu) { struct perf_event_attr *wd_attr; struct perf_event *event = per_cpu(watchdog_ev, cpu); int firstcpu = 0; /* nothing to do if the hard lockup detector is disabled */ if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) goto out; /* is it already setup and enabled? */ if (event && event->state > PERF_EVENT_STATE_OFF) goto out; /* it is setup but not enabled */ if (event != NULL) goto out_enable; if (atomic_inc_return(&watchdog_cpus) == 1) firstcpu = 1; wd_attr = &wd_hw_attr; wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); /* Try to register using hardware perf events */ event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); /* save the first cpu's error for future comparision */ if (firstcpu && IS_ERR(event)) firstcpu_err = PTR_ERR(event); if (!IS_ERR(event)) { /* only print for the first cpu initialized */ if (firstcpu || firstcpu_err) pr_info("enabled on all CPUs, permanently consumes one hw-PMU counter.\n"); goto out_save; } /* * Disable the hard lockup detector if _any_ CPU fails to set up * set up the hardware perf event. The watchdog() function checks * the NMI_WATCHDOG_ENABLED bit periodically. * * The barriers are for syncing up watchdog_enabled across all the * cpus, as clear_bit() does not use barriers. */ smp_mb__before_atomic(); clear_bit(NMI_WATCHDOG_ENABLED_BIT, &watchdog_enabled); smp_mb__after_atomic(); /* skip displaying the same error again */ if (!firstcpu && (PTR_ERR(event) == firstcpu_err)) return PTR_ERR(event); /* vary the KERN level based on the returned errno */ if (PTR_ERR(event) == -EOPNOTSUPP) pr_info("disabled (cpu%i): not supported (no LAPIC?)\n", cpu); else if (PTR_ERR(event) == -ENOENT) pr_warn("disabled (cpu%i): hardware events not enabled\n", cpu); else pr_err("disabled (cpu%i): unable to create perf event: %ld\n", cpu, PTR_ERR(event)); pr_info("Shutting down hard lockup detector on all cpus\n"); return PTR_ERR(event); /* success path */ out_save: per_cpu(watchdog_ev, cpu) = event; out_enable: perf_event_enable(per_cpu(watchdog_ev, cpu)); out: return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Babu Moger25189.96%150.00%
Prarit Bhargava2810.04%150.00%
Total279100.00%2100.00%


void watchdog_nmi_disable(unsigned int cpu) { struct perf_event *event = per_cpu(watchdog_ev, cpu); if (event) { perf_event_disable(event); per_cpu(watchdog_ev, cpu) = NULL; /* should be in cleanup, but blocks oprofile */ perf_event_release_kernel(event); /* watchdog_nmi_enable() expects this to be zero initially. */ if (atomic_dec_and_test(&watchdog_cpus)) firstcpu_err = 0; } }

Contributors

PersonTokensPropCommitsCommitProp
Babu Moger5388.33%150.00%
Prarit Bhargava711.67%150.00%
Total60100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Babu Moger67792.61%125.00%
Prarit Bhargava405.47%125.00%
Don Zickus111.50%125.00%
Ingo Molnar30.41%125.00%
Total731100.00%4100.00%
Directory: kernel
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.