make SW_WATCHDOG dynamic
Enable the hardclock-based watchdog previously conditional on the SW_WATCHDOG option whenever hardware watchdogs are not found, and watchdogd attempts to enable the watchdog. The SW_WATCHDOG option still causes the sofware watchdog to be enabled even if there is a hardware watchdog. This does not change the other software-based watchdog enabled by the --softtimeout option to watchdogd. Note that the code to reprime the watchdog during kernel core dumps is no longer conditional on SW_WATCHDOG. I think this was previously a bug. Reviewed by: imp alfred bjk MFC after: 1 week Relnotes: yes Differential Revision: https://reviews.freebsd.org/D13713
This commit is contained in:
parent
c79875bc4c
commit
95cd76bc3b
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 21, 2009
|
||||
.Dd January 2, 2018
|
||||
.Dt WATCHDOG 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -40,8 +40,11 @@ facility is used for controlling hardware and software watchdogs.
|
||||
.Pp
|
||||
The device
|
||||
.Pa /dev/fido
|
||||
responds to a single
|
||||
supports several optional
|
||||
.Xr ioctl 2
|
||||
calls for configuration, and
|
||||
responds to a single operational
|
||||
.Xr ioctl
|
||||
call,
|
||||
.Dv WDIOCPATPAT .
|
||||
It takes a single argument which represents a timeout value specified as a
|
||||
@ -60,12 +63,16 @@ indicates that the
|
||||
will be kept from timing out from the kernel.
|
||||
.Pp
|
||||
The
|
||||
.Dv WDIOCPATPAT
|
||||
.Xr ioctl 2
|
||||
call will return success if just one of the available
|
||||
.Xr watchdog 9
|
||||
implementations supports setting the timeout to the specified timeout.
|
||||
This
|
||||
means that at least one watchdog is armed.
|
||||
By default, this will be a hardware watchdog if one is present, but if
|
||||
no hardware watchdog is able to process the request, a default software
|
||||
watchdog is enabled.
|
||||
If the call fails, for instance if
|
||||
none of
|
||||
.Xr watchdog 9
|
||||
@ -77,8 +84,53 @@ To disable the watchdogs pass
|
||||
If disarming the watchdog(s) failed an error is returned.
|
||||
The watchdog might
|
||||
still be armed!
|
||||
.Pp
|
||||
The optional configuration
|
||||
.Xr ioctl
|
||||
commands are listed here, along with the type of the parameter used.
|
||||
Examples of their use can be found in
|
||||
.Xr watchdogd 8 .
|
||||
.Bl -tag -width "WDIOC_SETSOFTTIMEOUTACT int "
|
||||
.It Dv WDIOC_SETTIMEOUT Fa int
|
||||
set/reset the timer
|
||||
.It Dv WDIOC_GETTIMEOUT Fa int
|
||||
get total timeout
|
||||
.It Dv WDIOC_GETTIMELEFT Fa int
|
||||
get time left
|
||||
.It Dv WDIOC_GETPRETIMEOUT Fa int
|
||||
get the pre-timeout
|
||||
.It Dv WDIOC_SETPRETIMEOUT Fa int
|
||||
set the pre-timeout
|
||||
.It Dv WDIOC_SETPRETIMEOUTACT Fa int
|
||||
Set the action when a pre-timeout occurs (see
|
||||
.Li WD_SOFT_*
|
||||
below).
|
||||
.It Dv WDIOC_SETSOFT Fa int
|
||||
Use an internal software watchdog instead of hardware.
|
||||
There is also an external software watchdog, which is used by default
|
||||
if no hardware watchdog was attached.
|
||||
.It Dv WDIOC_SETSOFTTIMEOUTACT Fa int
|
||||
Set the action whan a soft timeout occurs.
|
||||
.El
|
||||
.Pp
|
||||
The actions that may be specified for the pre-timeout or the internal software
|
||||
watchdog are listed here.
|
||||
Multiple actions can be specified by ORing values together.
|
||||
.Bl -tag -width WD_SOFT_PRINT
|
||||
.It Dv WD_SOFT_PANIC
|
||||
panic
|
||||
.It Dv WD_SOFT_DDB
|
||||
enter debugger
|
||||
.It Dv WD_SOFT_LOG
|
||||
log(9)
|
||||
.It Dv WD_SOFT_PRINT
|
||||
printf(9)
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
The ioctl returns zero on success and non-zero on failure.
|
||||
The
|
||||
.Dv WDIOCPATPAT
|
||||
.Xr ioctl
|
||||
returns zero on success and non-zero on failure.
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EOPNOTSUPP
|
||||
No watchdog present in the kernel or
|
||||
@ -89,6 +141,10 @@ Watchdog could not be disabled (timeout value of 0).
|
||||
.It Bq Er EINVAL
|
||||
Invalid flag combination passed.
|
||||
.El
|
||||
.Pp
|
||||
The configuration
|
||||
.Xr ioctl
|
||||
operations return zero on success and non-zero on failure.
|
||||
.Sh EXAMPLES
|
||||
.Bd -literal -offset indent
|
||||
#include <paths.h>
|
||||
@ -122,8 +178,10 @@ Enables a watchdog to recover from a potentially freezing piece of code.
|
||||
.Pp
|
||||
.Dl "options SW_WATCHDOG"
|
||||
.Pp
|
||||
in your kernel config adds a software watchdog in the kernel, dropping to KDB
|
||||
or panic-ing when firing.
|
||||
in your kernel config forces a software watchdog in the kernel
|
||||
to be configured even if a hardware watchdog is configured,
|
||||
dropping to KDB or panicking when firing, depending
|
||||
on the KDB and KDB_UNATTENDED kernel configuration options.
|
||||
.Sh SEE ALSO
|
||||
.Xr watchdogd 8 ,
|
||||
.Xr watchdog 9
|
||||
|
@ -2609,7 +2609,9 @@ options BOOTP_WIRED_TO=fxp0 # Use interface fxp0 for BOOTP
|
||||
options BOOTP_BLOCKSIZE=8192 # Override NFS block size
|
||||
|
||||
#
|
||||
# Add software watchdog routines.
|
||||
# Enable software watchdog routines, even if hardware watchdog is present.
|
||||
# By default, software watchdog timer is enabled only if no hardware watchdog
|
||||
# is present.
|
||||
#
|
||||
options SW_WATCHDOG
|
||||
|
||||
|
@ -78,6 +78,9 @@ SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u_secs, CTLFLAG_RD,
|
||||
static int wd_lastpat_valid = 0;
|
||||
static time_t wd_lastpat = 0; /* when the watchdog was last patted */
|
||||
|
||||
/* Hook for external software watchdog to register for use if needed */
|
||||
void (*wdog_software_attach)(void);
|
||||
|
||||
static void
|
||||
pow2ns_to_ts(int pow2ns, struct timespec *ts)
|
||||
{
|
||||
@ -120,6 +123,7 @@ int
|
||||
wdog_kern_pat(u_int utim)
|
||||
{
|
||||
int error;
|
||||
static int first = 1;
|
||||
|
||||
if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0)
|
||||
return (EINVAL);
|
||||
@ -161,6 +165,17 @@ wdog_kern_pat(u_int utim)
|
||||
} else {
|
||||
EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
|
||||
}
|
||||
/*
|
||||
* If we no hardware watchdog responded, we have not tried to
|
||||
* attach an external software watchdog, and one is available,
|
||||
* attach it now and retry.
|
||||
*/
|
||||
if (error == EOPNOTSUPP && first && *wdog_software_attach != NULL) {
|
||||
(*wdog_software_attach)();
|
||||
EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
|
||||
}
|
||||
first = 0;
|
||||
|
||||
wd_set_pretimeout(wd_pretimeout, true);
|
||||
/*
|
||||
* If we were able to arm/strobe the watchdog, then
|
||||
|
@ -335,14 +335,18 @@ read_cpu_time(long *cp_time)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SW_WATCHDOG
|
||||
#include <sys/watchdog.h>
|
||||
|
||||
static int watchdog_ticks;
|
||||
static int watchdog_enabled;
|
||||
static void watchdog_fire(void);
|
||||
static void watchdog_config(void *, u_int, int *);
|
||||
#endif /* SW_WATCHDOG */
|
||||
|
||||
static void
|
||||
watchdog_attach(void)
|
||||
{
|
||||
EVENTHANDLER_REGISTER(watchdog_list, watchdog_config, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clock handling routines.
|
||||
@ -410,8 +414,14 @@ initclocks(void *dummy)
|
||||
if (profhz == 0)
|
||||
profhz = i;
|
||||
psratio = profhz / i;
|
||||
|
||||
#ifdef SW_WATCHDOG
|
||||
EVENTHANDLER_REGISTER(watchdog_list, watchdog_config, NULL, 0);
|
||||
/* Enable hardclock watchdog now, even if a hardware watchdog exists. */
|
||||
watchdog_attach();
|
||||
#else
|
||||
/* Volunteer to run a software watchdog. */
|
||||
if (wdog_software_attach == NULL)
|
||||
wdog_software_attach = watchdog_attach;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -482,10 +492,8 @@ hardclock(int usermode, uintfptr_t pc)
|
||||
#ifdef DEVICE_POLLING
|
||||
hardclock_device_poll(); /* this is very short and quick */
|
||||
#endif /* DEVICE_POLLING */
|
||||
#ifdef SW_WATCHDOG
|
||||
if (watchdog_enabled > 0 && --watchdog_ticks <= 0)
|
||||
watchdog_fire();
|
||||
#endif /* SW_WATCHDOG */
|
||||
}
|
||||
|
||||
void
|
||||
@ -496,9 +504,7 @@ hardclock_cnt(int cnt, int usermode)
|
||||
struct proc *p = td->td_proc;
|
||||
int *t = DPCPU_PTR(pcputicks);
|
||||
int flags, global, newticks;
|
||||
#ifdef SW_WATCHDOG
|
||||
int i;
|
||||
#endif /* SW_WATCHDOG */
|
||||
|
||||
/*
|
||||
* Update per-CPU and possibly global ticks values.
|
||||
@ -558,13 +564,11 @@ hardclock_cnt(int cnt, int usermode)
|
||||
atomic_store_rel_int(&devpoll_run, 0);
|
||||
}
|
||||
#endif /* DEVICE_POLLING */
|
||||
#ifdef SW_WATCHDOG
|
||||
if (watchdog_enabled > 0) {
|
||||
i = atomic_fetchadd_int(&watchdog_ticks, -newticks);
|
||||
if (i > 0 && i <= newticks)
|
||||
watchdog_fire();
|
||||
}
|
||||
#endif /* SW_WATCHDOG */
|
||||
}
|
||||
if (curcpu == CPU_FIRST())
|
||||
cpu_tick_calibration();
|
||||
@ -841,8 +845,6 @@ SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate,
|
||||
0, 0, sysctl_kern_clockrate, "S,clockinfo",
|
||||
"Rate and period of various kernel clocks");
|
||||
|
||||
#ifdef SW_WATCHDOG
|
||||
|
||||
static void
|
||||
watchdog_config(void *unused __unused, u_int cmd, int *error)
|
||||
{
|
||||
@ -891,5 +893,3 @@ watchdog_fire(void)
|
||||
panic("watchdog timeout");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SW_WATCHDOG */
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_watchdog.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
@ -36,9 +34,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/kerneldump.h>
|
||||
#ifdef SW_WATCHDOG
|
||||
#include <sys/watchdog.h>
|
||||
#endif
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
@ -205,9 +201,7 @@ dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg)
|
||||
}
|
||||
|
||||
dumpsys_map_chunk(pa, chunk, &va);
|
||||
#ifdef SW_WATCHDOG
|
||||
wdog_kern_pat(WD_LASTVAL);
|
||||
#endif
|
||||
|
||||
error = dump_append(di, va, 0, sz);
|
||||
dumpsys_unmap_chunk(pa, chunk, va);
|
||||
|
@ -112,6 +112,14 @@ EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn);
|
||||
|
||||
u_int wdog_kern_last_timeout(void);
|
||||
int wdog_kern_pat(u_int utim);
|
||||
|
||||
/*
|
||||
* The following function pointer is used to attach a software watchdog
|
||||
* if no hardware watchdog has been attached, and if the software module
|
||||
* has initialized the function pointer.
|
||||
*/
|
||||
|
||||
extern void (*wdog_software_attach)(void);
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_WATCHDOG_H */
|
||||
|
Loading…
Reference in New Issue
Block a user