- Add the possibility to reuse the already last used timeout when patting
the watchdog, via the watchdog(9) interface. For that, the WD_LASTVAL bitwise operation is used. It is mutually exclusive with any explicit timout passing to the watchdogs. The last timeout can be returned via the wdog_kern_last_timeout() KPI. - Add the possibility to pat the watchdogs installed via the watchdog(9) interface from the kernel. In order to do that the new KPI wdog_kern_pat() is offered and it does accept normalized nanoseconds or WD_LASTVAL. - Avoid to pass WD_ACTIVE down in the watchdog handlers. All the control bit processing should over to the upper layer functions and not passed down to the handlers at all. These changes are intended to be used in order to fix up the watchdog tripping in situation when the userland is busted, but protection is still wanted (examples: shutdown syncing / disk dumping). Sponsored by: Sandvine Incorporated Reviewed by: emaste, des, cognet MFC after: 2 weeks
This commit is contained in:
parent
0e24a634ce
commit
7126ba42f6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221121
@ -724,14 +724,6 @@ db_watchdog(dummy1, dummy2, dummy3, dummy4)
|
||||
} else if ((tout & WD_INTERVAL) == WD_TO_NEVER) {
|
||||
db_error("Out of range watchdog interval\n");
|
||||
return;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* XXX: Right now we only support WD_ACTIVE, in the future we
|
||||
* may be possibly needing a more convoluted function for
|
||||
* dealing with different cases.
|
||||
*/
|
||||
tout |= WD_ACTIVE;
|
||||
}
|
||||
EVENTHANDLER_INVOKE(watchdog_list, tout, &i);
|
||||
}
|
||||
|
@ -40,37 +40,75 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/bus.h>
|
||||
|
||||
static struct cdev *wd_dev;
|
||||
static volatile u_int wd_last_u;
|
||||
|
||||
static int
|
||||
wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
int flags __unused, struct thread *td)
|
||||
kern_do_pat(u_int utim)
|
||||
{
|
||||
int error;
|
||||
u_int u;
|
||||
|
||||
if (cmd != WDIOCPATPAT)
|
||||
return (ENOIOCTL);
|
||||
u = *(u_int *)data;
|
||||
if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_INTERVAL))
|
||||
if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0)
|
||||
return (EINVAL);
|
||||
if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE))
|
||||
return (EINVAL);
|
||||
if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && (u & WD_INTERVAL) > 0)
|
||||
return (EINVAL);
|
||||
if (u & WD_PASSIVE)
|
||||
return (ENOSYS); /* XXX Not implemented yet */
|
||||
if ((u & WD_INTERVAL) == WD_TO_NEVER) {
|
||||
u = 0;
|
||||
|
||||
if ((utim & WD_LASTVAL) != 0) {
|
||||
MPASS((wd_last_u & ~WD_INTERVAL) == 0);
|
||||
utim &= ~WD_LASTVAL;
|
||||
utim |= wd_last_u;
|
||||
} else
|
||||
wd_last_u = (utim & WD_INTERVAL);
|
||||
if ((utim & WD_INTERVAL) == WD_TO_NEVER) {
|
||||
utim = 0;
|
||||
|
||||
/* Assume all is well; watchdog signals failure. */
|
||||
error = 0;
|
||||
} else {
|
||||
/* Assume no watchdog available; watchdog flags success */
|
||||
error = EOPNOTSUPP;
|
||||
}
|
||||
EVENTHANDLER_INVOKE(watchdog_list, u, &error);
|
||||
EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
int flags __unused, struct thread *td)
|
||||
{
|
||||
u_int u;
|
||||
|
||||
if (cmd != WDIOCPATPAT)
|
||||
return (ENOIOCTL);
|
||||
u = *(u_int *)data;
|
||||
if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL))
|
||||
return (EINVAL);
|
||||
if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE))
|
||||
return (EINVAL);
|
||||
if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && ((u & WD_INTERVAL) > 0 ||
|
||||
(u & WD_LASTVAL) != 0))
|
||||
return (EINVAL);
|
||||
if (u & WD_PASSIVE)
|
||||
return (ENOSYS); /* XXX Not implemented yet */
|
||||
u &= ~(WD_ACTIVE | WD_PASSIVE);
|
||||
|
||||
return (kern_do_pat(u));
|
||||
}
|
||||
|
||||
u_int
|
||||
wdog_kern_last_timeout(void)
|
||||
{
|
||||
|
||||
return (wd_last_u);
|
||||
}
|
||||
|
||||
int
|
||||
wdog_kern_pat(u_int utim)
|
||||
{
|
||||
|
||||
if (utim & ~(WD_LASTVAL | WD_INTERVAL))
|
||||
return (EINVAL);
|
||||
|
||||
return (kern_do_pat(utim));
|
||||
}
|
||||
|
||||
static struct cdevsw wd_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_ioctl = wd_ioctl,
|
||||
|
@ -50,6 +50,12 @@
|
||||
* right to the kernel.
|
||||
*/
|
||||
|
||||
#define WD_LASTVAL 0x0200000
|
||||
/*
|
||||
* Use the already last used timeout value.
|
||||
* The kernel will use as timeout the last valid timeout provided.
|
||||
*/
|
||||
|
||||
#define WD_INTERVAL 0x00000ff
|
||||
/*
|
||||
* Mask for duration bits.
|
||||
@ -78,6 +84,9 @@
|
||||
typedef void (*watchdog_fn)(void *, u_int, int *);
|
||||
|
||||
EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn);
|
||||
|
||||
u_int wdog_kern_last_timeout(void);
|
||||
int wdog_kern_pat(u_int utim);
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_WATCHDOG_H */
|
||||
|
Loading…
Reference in New Issue
Block a user