Date: Wed, 23 Jan 2013 02:29:06 +0000 (UTC) From: Alfred Perlstein <alfred@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r245833 - in user/alfred/ewatchdog/sys: dev/watchdog sys Message-ID: <201301230229.r0N2T6LE011843@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: alfred Date: Wed Jan 23 02:29:05 2013 New Revision: 245833 URL: http://svnweb.freebsd.org/changeset/base/245833 Log: Implement part of Linux's watchdog API. ioctls added: WDIOC_GETTIMELEFT - seconds until watchdog goes off WDIOC_SETTIMEOUT - set the timeout (nearly the same as WDIOCPATPAT) WDIOC_GETTIMEOUT - get the timeout/interval This will allow us to craft a utility to bark when the timeout is about to expire and otherwise gather information about pending watchdogs. 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 Wed Jan 23 02:06:20 2013 (r245832) +++ user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c Wed Jan 23 02:29:05 2013 (r245833) @@ -39,8 +39,13 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <machine/bus.h> +#include <sys/syscallsubr.h> /* kern_clock_gettime() */ + static struct cdev *wd_dev; -static volatile u_int wd_last_u; +static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */ + +static int wd_lastpat_valid = 0; +static time_t wd_lastpat = 0; /* when the watchdog was last patted */ static int kern_do_pat(u_int utim) @@ -51,11 +56,20 @@ kern_do_pat(u_int utim) return (EINVAL); if ((utim & WD_LASTVAL) != 0) { + /* + * if WD_LASTVAL is set, fill in the bits for timeout + * from the saved value in wd_last_u. + */ MPASS((wd_last_u & ~WD_INTERVAL) == 0); utim &= ~WD_LASTVAL; utim |= wd_last_u; - } else + } else { + /* + * Otherwise save the new interval. + * This can be zero (to disable the watchdog) + */ wd_last_u = (utim & WD_INTERVAL); + } if ((utim & WD_INTERVAL) == WD_TO_NEVER) { utim = 0; @@ -66,17 +80,28 @@ kern_do_pat(u_int utim) error = EOPNOTSUPP; } EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + /* + * If we were able to arm/strobe the watchdog, then + * update the last time it was strobed for WDIOC_GETTIMELEFT + */ + if (!error) { + struct timespec ts; + + error = kern_clock_gettime(curthread /* XXX */, + CLOCK_MONOTONIC_FAST, &ts); + if (!error) { + wd_lastpat = ts.tv_sec; + wd_lastpat_valid = 1; + } + } return (error); } static int -wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, - int flags __unused, struct thread *td) +wd_ioctl_patpat(caddr_t data) { u_int u; - if (cmd != WDIOCPATPAT) - return (ENOIOCTL); u = *(u_int *)data; if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL)) return (EINVAL); @@ -92,6 +117,57 @@ wd_ioctl(struct cdev *dev __unused, u_lo return (kern_do_pat(u)); } +static int +wd_get_time_left(struct thread *td, time_t *remainp) +{ + struct timespec ts; + int error; + + error = kern_clock_gettime(td, CLOCK_MONOTONIC_FAST, &ts); + if (error) + return (error); + if (!wd_lastpat_valid) + return (ENOENT); + *remainp = ts.tv_sec - wd_lastpat; + return (0); +} + +static int +wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, + int flags __unused, struct thread *td) +{ + u_int u; + time_t timeleft; + int error; + + error = 0; + + switch (cmd) { + case WDIOC_GETTIMELEFT: + error = wd_get_time_left(td, &timeleft); + if (error) + break; + *(int *)data = (int)timeleft; + break; + case WDIOC_SETTIMEOUT: + u = *(u_int *)data; + error = wdog_kern_pat(u); + break; + case WDIOC_GETTIMEOUT: + u = wdog_kern_last_timeout(); + *(u_int *)data = u; + break; + case WDIOCPATPAT: + error = wd_ioctl_patpat(data); + break; + default: + error = ENOIOCTL; + break; + } + return (error); +} + + u_int wdog_kern_last_timeout(void) { Modified: user/alfred/ewatchdog/sys/sys/watchdog.h ============================================================================== --- user/alfred/ewatchdog/sys/sys/watchdog.h Wed Jan 23 02:06:20 2013 (r245832) +++ user/alfred/ewatchdog/sys/sys/watchdog.h Wed Jan 23 02:29:05 2013 (r245833) @@ -33,6 +33,9 @@ #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 WD_ACTIVE 0x8000000 /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201301230229.r0N2T6LE011843>