Created
February 12, 2013 01:19
-
-
Save splbio/4759234 to your computer and use it in GitHub Desktop.
watchdog patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: dev/watchdog/watchdog.c | |
=================================================================== | |
--- dev/watchdog/watchdog.c (revision 246559) | |
+++ dev/watchdog/watchdog.c (working copy) | |
@@ -1,5 +1,8 @@ | |
/*- | |
* Copyright (c) 2004 Poul-Henning Kamp | |
+ * Copyright (c) 2013 iXsystems.com, | |
+ * author: Alfred Perlstein <[email protected]> | |
+ * | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
@@ -29,18 +32,26 @@ | |
__FBSDID("$FreeBSD$"); | |
#include <sys/param.h> | |
+#include <sys/types.h> | |
#include <sys/systm.h> | |
#include <sys/conf.h> | |
#include <sys/uio.h> | |
#include <sys/kernel.h> | |
#include <sys/malloc.h> | |
#include <sys/module.h> | |
+#include <sys/syslog.h> | |
#include <sys/watchdog.h> | |
#include <sys/bus.h> | |
#include <machine/bus.h> | |
#include <sys/syscallsubr.h> /* kern_clock_gettime() */ | |
+static int wd_set_pretimeout(int newtimeout, int disableiftoolong); | |
+ | |
+static struct callout wd_pretimeo_handle; | |
+static int wd_pretimeout; | |
+static int wd_pretimeout_act; | |
+ | |
static struct cdev *wd_dev; | |
static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */ | |
@@ -80,6 +91,7 @@ | |
error = EOPNOTSUPP; | |
} | |
EVENTHANDLER_INVOKE(watchdog_list, utim, &error); | |
+ wd_set_pretimeout(wd_pretimeout, true); | |
/* | |
* If we were able to arm/strobe the watchdog, then | |
* update the last time it was strobed for WDIOC_GETTIMELEFT | |
@@ -132,7 +144,68 @@ | |
return (0); | |
} | |
+static void | |
+wd_pretimeout_cb(void *arg __unused) | |
+{ | |
+ | |
+ switch (wd_pretimeout_act) { | |
+ case WD_PRE_PANIC: | |
+ panic("watchdog pre-timeout, WD_PRE_PANIC set"); | |
+ break; | |
+#ifdef DDB | |
+ case WD_PRE_DDB: | |
+ debugger(); | |
+ break; | |
+#endif | |
+ case WD_PRE_LOG: | |
+ log(LOG_EMERG, "watchdog pre-timeout, WD_PRE_LOG"); | |
+ break; | |
+ default: | |
+ panic("watchdog: unexpected wd_pretimeout_act %d", | |
+ wd_pretimeout_act); | |
+ } | |
+} | |
+ | |
+/* | |
+ * Called to manage timeouts. | |
+ * newtimeout needs to be in the range of 0 to actual watchdog timeout. | |
+ * if 0, we disable the pre-timeout. | |
+ * otherwise we set the pre-timeout provided it's not greater than the | |
+ * current actual watchdog timeout. | |
+ */ | |
static int | |
+wd_set_pretimeout(int newtimeout, int disableiftoolong) | |
+{ | |
+ u_int utime; | |
+ | |
+ utime = wdog_kern_last_timeout(); | |
+ /* do not permit a pre-timeout >= than the timeout. */ | |
+ if (newtimeout >= utime) { | |
+ /* | |
+ * If 'disableiftoolong' then just fall through | |
+ * so as to disable the pre-watchdog | |
+ */ | |
+ if (disableiftoolong) | |
+ newtimeout = 0; | |
+ else | |
+ return EINVAL; | |
+ } | |
+ | |
+ /* disable the pre-timeout */ | |
+ if (newtimeout == 0) { | |
+ wd_pretimeout = 0; | |
+ callout_stop(&wd_pretimeo_handle); | |
+ return 0; | |
+ } | |
+ | |
+ /* We determined the value is sane, so reset the callout */ | |
+ (void) callout_reset(&wd_pretimeo_handle, hz*(utime - newtimeout), | |
+ wd_pretimeout_cb, NULL); | |
+ wd_pretimeout = newtimeout; | |
+ return 0; | |
+} | |
+ | |
+static int | |
wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, | |
int flags __unused, struct thread *td) | |
{ | |
@@ -143,6 +216,27 @@ | |
error = 0; | |
switch (cmd) { | |
+ case WDIOC_SETPRETIMEOUTACT: | |
+ u = *(int *)data; | |
+ switch (u) { | |
+ case WD_PRE_PANIC: | |
+#ifdef DDB | |
+ case WD_PRE_DDB: | |
+#endif | |
+ case WD_PRE_LOG: | |
+ wd_pretimeout_act = u; | |
+ break; | |
+ default: | |
+ error = EINVAL; | |
+ break; | |
+ } | |
+ break; | |
+ case WDIOC_GETPRETIMEOUT: | |
+ *(int *)data = (int)wd_pretimeout; | |
+ break; | |
+ case WDIOC_SETPRETIMEOUT: | |
+ error = wd_set_pretimeout(*(int *)data, false); | |
+ break; | |
case WDIOC_GETTIMELEFT: | |
error = wd_get_time_left(td, &timeleft); | |
if (error) | |
@@ -166,7 +260,6 @@ | |
} | |
return (error); | |
} | |
- | |
u_int | |
wdog_kern_last_timeout(void) | |
@@ -196,10 +289,12 @@ | |
{ | |
switch(type) { | |
case MOD_LOAD: | |
+ callout_init(&wd_pretimeo_handle, true); | |
wd_dev = make_dev(&wd_cdevsw, 0, | |
UID_ROOT, GID_WHEEL, 0600, _PATH_WATCHDOG); | |
return 0; | |
case MOD_UNLOAD: | |
+ callout_drain(&wd_pretimeo_handle); | |
destroy_dev(wd_dev); | |
return 0; | |
case MOD_SHUTDOWN: | |
Index: sys/watchdog.h | |
=================================================================== | |
--- sys/watchdog.h (revision 246559) | |
+++ sys/watchdog.h (working copy) | |
@@ -36,6 +36,9 @@ | |
#define WDIOC_SETTIMEOUT _IOW('W', 43, int) | |
#define WDIOC_GETTIMEOUT _IOR('W', 44, int) | |
#define WDIOC_GETTIMELEFT _IOR('W', 45, int) | |
+#define WDIOC_GETPRETIMEOUT _IOR('W', 46, int) | |
+#define WDIOC_SETPRETIMEOUT _IOW('W', 47, int) | |
+#define WDIOC_SETPRETIMEOUTACT _IOW('W', 48, int) | |
#define WD_ACTIVE 0x8000000 | |
/* | |
@@ -80,6 +83,11 @@ | |
#define WD_TO_16SEC 34 | |
#define WD_TO_32SEC 35 | |
+/* action on pre-timeout trigger */ | |
+#define WD_PRE_PANIC 1 /* panic */ | |
+#define WD_PRE_DDB 2 /* enter debugger */ | |
+#define WD_PRE_LOG 3 /* log(9) */ | |
+ | |
#ifdef _KERNEL | |
#include <sys/eventhandler.h> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment