|
@@ -703,6 +703,71 @@ static int proc_watchdog_update(void)
|
|
|
|
|
|
static DEFINE_MUTEX(watchdog_proc_mutex);
|
|
static DEFINE_MUTEX(watchdog_proc_mutex);
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * 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
|
|
|
|
+ */
|
|
|
|
+static int proc_watchdog_common(int which, struct ctl_table *table, int write,
|
|
|
|
+ void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ int err, old, new;
|
|
|
|
+ int *watchdog_param = (int *)table->data;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&watchdog_proc_mutex);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the parameter is being read return the state of the corresponding
|
|
|
|
+ * bit(s) in 'watchdog_enabled', else update 'watchdog_enabled' and the
|
|
|
|
+ * run state of the lockup detectors.
|
|
|
|
+ */
|
|
|
|
+ if (!write) {
|
|
|
|
+ *watchdog_param = (watchdog_enabled & which) != 0;
|
|
|
|
+ err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
|
|
|
+ } else {
|
|
|
|
+ err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * There is a race window between fetching the current value
|
|
|
|
+ * from 'watchdog_enabled' and storing the new value. During
|
|
|
|
+ * this race window, watchdog_nmi_enable() can sneak in and
|
|
|
|
+ * clear the NMI_WATCHDOG_ENABLED bit in 'watchdog_enabled'.
|
|
|
|
+ * The 'cmpxchg' detects this race and the loop retries.
|
|
|
|
+ */
|
|
|
|
+ do {
|
|
|
|
+ old = watchdog_enabled;
|
|
|
|
+ /*
|
|
|
|
+ * If the parameter value is not zero set the
|
|
|
|
+ * corresponding bit(s), else clear it(them).
|
|
|
|
+ */
|
|
|
|
+ if (*watchdog_param)
|
|
|
|
+ new = old | which;
|
|
|
|
+ else
|
|
|
|
+ new = old & ~which;
|
|
|
|
+ } while (cmpxchg(&watchdog_enabled, old, new) != old);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Update the run state of the lockup detectors.
|
|
|
|
+ * Restore 'watchdog_enabled' on failure.
|
|
|
|
+ */
|
|
|
|
+ err = proc_watchdog_update();
|
|
|
|
+ if (err)
|
|
|
|
+ watchdog_enabled = old;
|
|
|
|
+ }
|
|
|
|
+out:
|
|
|
|
+ mutex_unlock(&watchdog_proc_mutex);
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* proc handler for /proc/sys/kernel/nmi_watchdog,watchdog_thresh
|
|
* proc handler for /proc/sys/kernel/nmi_watchdog,watchdog_thresh
|
|
*/
|
|
*/
|