Skip to content

Commit 36a8947

Browse files
holio0Wim Van Sebroeck
authored andcommitted
watchdog: softdog: Add options 'soft_reboot_cmd' and 'soft_active_on_boot'
Add module parameters 'soft_reboot_cmd' and 'soft_active_on_boot' for customizing softdog configuration; config reboot command by assigning soft_reboot_cmd, and set soft_active_on_boot to start up softdog timer at module initialization stage. Signed-off-by: Woody Lin <[email protected]> Reviewed-by: Guenter Roeck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Guenter Roeck <[email protected]> Signed-off-by: Wim Van Sebroeck <[email protected]>
1 parent f1889c9 commit 36a8947

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

drivers/watchdog/softdog.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
#include <linux/hrtimer.h>
2121
#include <linux/init.h>
2222
#include <linux/kernel.h>
23+
#include <linux/kthread.h>
2324
#include <linux/module.h>
2425
#include <linux/moduleparam.h>
2526
#include <linux/reboot.h>
2627
#include <linux/types.h>
2728
#include <linux/watchdog.h>
29+
#include <linux/workqueue.h>
2830

2931
#define TIMER_MARGIN 60 /* Default is 60 seconds */
3032
static unsigned int soft_margin = TIMER_MARGIN; /* in seconds */
@@ -49,11 +51,34 @@ module_param(soft_panic, int, 0);
4951
MODULE_PARM_DESC(soft_panic,
5052
"Softdog action, set to 1 to panic, 0 to reboot (default=0)");
5153

54+
static char *soft_reboot_cmd;
55+
module_param(soft_reboot_cmd, charp, 0000);
56+
MODULE_PARM_DESC(soft_reboot_cmd,
57+
"Set reboot command. Emergency reboot takes place if unset");
58+
59+
static bool soft_active_on_boot;
60+
module_param(soft_active_on_boot, bool, 0000);
61+
MODULE_PARM_DESC(soft_active_on_boot,
62+
"Set to true to active Softdog on boot (default=false)");
63+
5264
static struct hrtimer softdog_ticktock;
5365
static struct hrtimer softdog_preticktock;
5466

67+
static int reboot_kthread_fn(void *data)
68+
{
69+
kernel_restart(soft_reboot_cmd);
70+
return -EPERM; /* Should not reach here */
71+
}
72+
73+
static void reboot_work_fn(struct work_struct *unused)
74+
{
75+
kthread_run(reboot_kthread_fn, NULL, "softdog_reboot");
76+
}
77+
5578
static enum hrtimer_restart softdog_fire(struct hrtimer *timer)
5679
{
80+
static bool soft_reboot_fired;
81+
5782
module_put(THIS_MODULE);
5883
if (soft_noboot) {
5984
pr_crit("Triggered - Reboot ignored\n");
@@ -62,6 +87,33 @@ static enum hrtimer_restart softdog_fire(struct hrtimer *timer)
6287
panic("Software Watchdog Timer expired");
6388
} else {
6489
pr_crit("Initiating system reboot\n");
90+
if (!soft_reboot_fired && soft_reboot_cmd != NULL) {
91+
static DECLARE_WORK(reboot_work, reboot_work_fn);
92+
/*
93+
* The 'kernel_restart' is a 'might-sleep' operation.
94+
* Also, executing it in system-wide workqueues blocks
95+
* any driver from using the same workqueue in its
96+
* shutdown callback function. Thus, we should execute
97+
* the 'kernel_restart' in a standalone kernel thread.
98+
* But since starting a kernel thread is also a
99+
* 'might-sleep' operation, so the 'reboot_work' is
100+
* required as a launcher of the kernel thread.
101+
*
102+
* After request the reboot, restart the timer to
103+
* schedule an 'emergency_restart' reboot after
104+
* 'TIMER_MARGIN' seconds. It's because if the softdog
105+
* hangs, it might be because of scheduling issues. And
106+
* if that is the case, both 'schedule_work' and
107+
* 'kernel_restart' may possibly be malfunctional at the
108+
* same time.
109+
*/
110+
soft_reboot_fired = true;
111+
schedule_work(&reboot_work);
112+
hrtimer_add_expires_ns(timer,
113+
(u64)TIMER_MARGIN * NSEC_PER_SEC);
114+
115+
return HRTIMER_RESTART;
116+
}
65117
emergency_restart();
66118
pr_crit("Reboot didn't ?????\n");
67119
}
@@ -145,12 +197,17 @@ static int __init softdog_init(void)
145197
softdog_preticktock.function = softdog_pretimeout;
146198
}
147199

200+
if (soft_active_on_boot)
201+
softdog_ping(&softdog_dev);
202+
148203
ret = watchdog_register_device(&softdog_dev);
149204
if (ret)
150205
return ret;
151206

152207
pr_info("initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
153208
soft_noboot, softdog_dev.timeout, soft_panic, nowayout);
209+
pr_info(" soft_reboot_cmd=%s soft_active_on_boot=%d\n",
210+
soft_reboot_cmd ?: "<not set>", soft_active_on_boot);
154211

155212
return 0;
156213
}

0 commit comments

Comments
 (0)