Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Feb 2013 04:22:01 +0000 (UTC)
From:      Alfred Perlstein <alfred@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r246704 - in user/alfred/ewatchdog/sys: dev/watchdog sys
Message-ID:  <201302120422.r1C4M1Ok078780@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: alfred
Date: Tue Feb 12 04:22:00 2013
New Revision: 246704
URL: http://svnweb.freebsd.org/changeset/base/246704

Log:
  Add a new software watchdog that has a configurable action.
  
  While here refactor the "action" code.

Modified:
  user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c
  user/alfred/ewatchdog/sys/sys/watchdog.h

Modified: user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c
==============================================================================
--- user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c	Tue Feb 12 03:19:39 2013	(r246703)
+++ user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c	Tue Feb 12 04:22:00 2013	(r246704)
@@ -47,11 +47,17 @@ __FBSDID("$FreeBSD$");
 #include <sys/syscallsubr.h> /* kern_clock_gettime() */
 
 static int wd_set_pretimeout(int newtimeout, int disableiftoolong);
+static void wd_timeout_cb(void *arg);
 
 static struct callout wd_pretimeo_handle;
 static int wd_pretimeout;
 static int wd_pretimeout_act;
 
+static struct callout wd_softtimeo_handle;
+static int wd_softtimer;	/* true = use softtimer instead of hardware
+				   watchdog */
+static int wd_softtimeout_act;	/* action for the software timeout */
+
 static struct cdev *wd_dev;
 static volatile u_int wd_last_u;    /* last timeout value set by kern_do_pat */
 
@@ -90,7 +96,16 @@ kern_do_pat(u_int utim)
 		/* Assume no watchdog available; watchdog flags success */
 		error = EOPNOTSUPP;
 	}
-	EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
+	if (wd_softtimer) {
+		if (utim == 0) {
+			callout_stop(&wd_softtimeo_handle);
+		} else {
+			(void) callout_reset(&wd_softtimeo_handle,
+			    hz*utim, wd_timeout_cb, "soft");
+		}
+	} else {
+		EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
+	}
 	wd_set_pretimeout(wd_pretimeout, true);
 	/*
 	 * If we were able to arm/strobe the watchdog, then
@@ -110,6 +125,21 @@ kern_do_pat(u_int utim)
 }
 
 static int
+wd_valid_act(int act)
+{
+
+	switch (act) {
+	case WD_SOFT_PANIC:
+#ifdef DDB
+	case WD_SOFT_DDB:
+#endif
+	case WD_SOFT_LOG:
+		return true;
+	}
+	return false;
+}
+
+static int
 wd_ioctl_patpat(caddr_t data)
 {
 	u_int u;
@@ -145,20 +175,26 @@ wd_get_time_left(struct thread *td, time
 }
 
 static void
-wd_pretimeout_cb(void *arg __unused)
+wd_timeout_cb(void *arg)
 {
+	const char *type = arg;
+#ifdef DDB
+	char kdb_why[80];
+#endif
 
 	switch (wd_pretimeout_act) {
-	case WD_PRE_PANIC:
-		panic("watchdog pre-timeout, WD_PRE_PANIC set");
+	case WD_SOFT_PANIC:
+		panic("watchdog %s-timeout, WD_SOFT_PANIC set", type);
 		break;
 #ifdef DDB
-	case WD_PRE_DDB:
-		debugger();
+	case WD_SOFT_DDB:
+		snprintf(kdb_why, sizeof(buf), "watchdog %s timeout", type);
+		kdb_backtrace();
+		kdb_enter(KDB_WHY_WATCHDOG, kdb_why);
 		break;
 #endif
-	case WD_PRE_LOG:
-		log(LOG_EMERG, "watchdog pre-timeout, WD_PRE_LOG");
+	case WD_SOFT_LOG:
+		log(LOG_EMERG, "watchdog %s-timeout, WD_SOFT_LOG", type);
 		break;
 	default:
 		panic("watchdog: unexpected wd_pretimeout_act %d",
@@ -200,7 +236,7 @@ wd_set_pretimeout(int newtimeout, int di
 
 	/* We determined the value is sane, so reset the callout */
 	(void) callout_reset(&wd_pretimeo_handle, hz*(utime - newtimeout),
-	    wd_pretimeout_cb, NULL);
+	    wd_timeout_cb, "pre-timeout");
 	wd_pretimeout = newtimeout;
 	return 0;
 }
@@ -216,20 +252,33 @@ wd_ioctl(struct cdev *dev __unused, u_lo
 	error = 0;
 
 	switch (cmd) {
-	case WDIOC_SETPRETIMEOUTACT:
+	case WDIOC_SETSOFT:
 		u = *(int *)data;
-		switch (u) {
-		case WD_PRE_PANIC:
-#ifdef DDB
-		case WD_PRE_DDB:
-#endif
-		case WD_PRE_LOG:
-			wd_pretimeout_act = u;
+		/* do nothing? */
+		if (u == wd_softtimer)
 			break;
-		default:
+		/* If there is a pending timeout disallow this ioctl */
+		if (wd_last_u != 0) {
 			error = EINVAL;
 			break;
 		}
+		wd_softtimer = u;
+		break;
+	case WDIOC_SETSOFTTIMEOUTACT:
+		u = *(int *)data;
+		if (wd_valid_act(u)) {
+			wd_softtimeout_act = u;
+		} else {
+			error = EINVAL;
+		}
+		break;
+	case WDIOC_SETPRETIMEOUTACT:
+		u = *(int *)data;
+		if (wd_valid_act(u)) {
+			wd_pretimeout_act = u;
+		} else {
+			error = EINVAL;
+		}
 		break;
 	case WDIOC_GETPRETIMEOUT:
 		*(int *)data = (int)wd_pretimeout;
@@ -290,11 +339,15 @@ watchdog_modevent(module_t mod __unused,
 	switch(type) {
 	case MOD_LOAD:
 		callout_init(&wd_pretimeo_handle, true);
+		callout_init(&wd_softtimeo_handle, true);
 		wd_dev = make_dev(&wd_cdevsw, 0,
 		    UID_ROOT, GID_WHEEL, 0600, _PATH_WATCHDOG);
 		return 0;
 	case MOD_UNLOAD:
+		callout_stop(&wd_pretimeo_handle);
+		callout_stop(&wd_softtimeo_handle);
 		callout_drain(&wd_pretimeo_handle);
+		callout_drain(&wd_softtimeo_handle);
 		destroy_dev(wd_dev);
 		return 0;
 	case MOD_SHUTDOWN:

Modified: user/alfred/ewatchdog/sys/sys/watchdog.h
==============================================================================
--- user/alfred/ewatchdog/sys/sys/watchdog.h	Tue Feb 12 03:19:39 2013	(r246703)
+++ user/alfred/ewatchdog/sys/sys/watchdog.h	Tue Feb 12 04:22:00 2013	(r246704)
@@ -32,14 +32,19 @@
 
 #define	_PATH_WATCHDOG	"fido"
 
-#define WDIOCPATPAT	_IOW('W', 42, u_int)
-#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 WDIOCPATPAT	_IOW('W', 42, u_int)	/* pat the watchdog */
+#define WDIOC_SETTIMEOUT    _IOW('W', 43, int)	/* set/reset the timer */
+#define WDIOC_GETTIMEOUT    _IOR('W', 44, int)	/* get total timeout */
+#define WDIOC_GETTIMELEFT   _IOR('W', 45, int)	/* get time left */
+#define WDIOC_GETPRETIMEOUT _IOR('W', 46, int)	/* get the pre-timeout */
+#define WDIOC_SETPRETIMEOUT _IOW('W', 47, int)	/* set the pre-timeout */
+/* set the action when a pre-timeout occurs see: WD_SOFT_* */
 #define WDIOC_SETPRETIMEOUTACT _IOW('W', 48, int)
 
+/* use software watchdog instead of hardware */
+#define WDIOC_SETSOFT	_IOW('W', 49, int)
+#define WDIOC_SETSOFTTIMEOUTACT	_IOW('W', 50, int)
+
 #define WD_ACTIVE	0x8000000
 	/* 
 	 * Watchdog reset, timeout set to value in WD_INTERVAL field.
@@ -84,9 +89,9 @@
 #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) */
+#define	WD_SOFT_PANIC	1	/* panic */
+#define	WD_SOFT_DDB	2	/* enter debugger */
+#define	WD_SOFT_LOG	3	/* log(9) */
 
 #ifdef _KERNEL
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302120422.r1C4M1Ok078780>