add ability to set watchdog timeout for a shutdown

This change allows to specify a watchdog(9) timeout for a system
shutdown.  The timeout is activated when the watchdogd daemon is
stopped.  The idea is to a prevent any indefinite hang during late
stages of the shutdown.  The feature is implemented in rc.d/watchdogd,
it builds upon watchdogd -x option.

Note that the shutdown timeout is not actiavted when the watchdogd
service is individually stopped by an operator.  It is also not
activated for the 'shutdown' to the single-user mode.  In those cases it
is assumed that the operator knows what they are doing and they have
means to recover the system should it hang.

Significant subchanges and implementation details:
- the argument to rc.shutdown, completely unused before, is assigned to
  rc_shutdown variable that can be inspected by rc scripts
- init(8) passes "single" or "reboot" as the argument, this is not
  changed
- the argument is not mandatory and if it is not set then rc_shutdown is
  set to "unspecified"
- however, the default jail management scripts and jail configuration
  examples have been updated to pass "jail" to rc.shutdown, just in case
- the new timeout can be set via watchdogd_shutdown_timeout rc option
- for consistency, the regular timeout can now be set via
  watchdogd_timeout rc option
- watchdogd_shutdown_timeout and watchdogd_timeout override timeout
  specifications in watchdogd_flags
- existing configurations, where the new rc options are not set, should
  keep working as before

I am not particularly wed to any of the implementation specifics.
I am open to changing or removing any of them as long as the provided
functionality is the same (or very close) to the proposed one.
For example, I think it can be implemented without using watchdogd -x,
by means of watchdog(1) alone.  In that case there would be a small
window between stopping watchdogd and running watchdog, but I think that
that is acceptable.

Reviewed by:	bcr (man page changes)
MFC after:	5 weeks
Relnotes:	yes
Differential Revision: https://reviews.freebsd.org/D21221
This commit is contained in:
avg 2019-10-03 11:23:10 +00:00
parent a757da83a4
commit e96b4170d0
12 changed files with 118 additions and 14 deletions

View File

@ -679,6 +679,10 @@ harvest_mask="511" # Entropy device harvests all but the very invasive sources.
dmesg_enable="YES" # Save dmesg(8) to /var/run/dmesg.boot
watchdogd_enable="NO" # Start the software watchdog daemon
watchdogd_flags="" # Flags to watchdogd (if enabled)
watchdogd_timeout="" # watchdogd timeout, overrides -t in watchdogd_flags
watchdogd_shutdown_timeout="" # Timeout to use after watchdogd is stopped.
# Has effect only for system shutdown.
# Overrides -x in watchdogd_flags.
devfs_rulesets="/etc/defaults/devfs.rules /etc/devfs.rules" # Files containing
# devfs(8) rules.
devfs_system_ruleset="" # The name (NOT number) of a ruleset to apply to /dev

View File

@ -168,7 +168,7 @@ parse_options()
if [ -z "${_exec_start}" ]; then
_exec_start="/bin/sh /etc/rc"
if [ -z "${_exec_stop}" ]; then
_exec_stop="/bin/sh /etc/rc.shutdown"
_exec_stop="/bin/sh /etc/rc.shutdown jail"
fi
fi
fi

View File

@ -38,9 +38,55 @@ desc="Watchdog daemon"
rcvar="watchdogd_enable"
command="/usr/sbin/${name}"
pidfile="/var/run/${name}.pid"
start_precmd="watchdogd_prestart"
stop_precmd="watchdogd_prestop"
stop_postcmd="watchdogd_poststop"
watchdog_command="/usr/sbin/watchdog"
watchdogd_prestart()
{
if [ -n "${watchdogd_timeout}" ] ; then
rc_flags="${rc_flags} -t ${watchdogd_timeout}"
fi
if [ -n "$watchdogd_shutdown_timeout" ] ; then
rc_flags="${rc_flags} -x ${watchdogd_shutdown_timeout}"
fi
return 0
}
watchdogd_prestop()
{
sig_stop="${watchdogd_sig_stop:-TERM}"
}
watchdogd_poststop()
{
if [ ${watchdogd_shutdown_timeout:-0} -gt 0 ] ; then
case "${rc_shutdown}" in
"reboot")
info "watchdog timer is set to" \
${watchdogd_shutdown_timeout} "before shutdown"
return 0
;;
"single")
info "watchdog timer is disabled before going to" \
"single user mode"
${watchdog_command} -t 0
;;
"")
info "watchdog timer is disabled after administrative" \
"${name} stop"
${watchdog_command} -t 0
;;
*)
warn "unknown shutdown mode '${rc_shutdown}'"
warn "watchdog timer is set to ${watchdogd_shutdown_timeout}"
return 0
;;
esac
fi
return 0
}
load_rc_config $name
sig_stop="${watchdogd_sig_stop:-TERM}"
run_rc_command "$1"

View File

@ -43,6 +43,8 @@ HOME=/
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin
export HOME PATH
rc_shutdown=${1:-"unspecified"}
. /etc/rc.subr
load_rc_config

View File

@ -31,7 +31,7 @@
.\" @(#)init.8 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd August 15, 2018
.Dd August 6, 2019
.Dt INIT 8
.Os
.Sh NAME
@ -270,6 +270,15 @@ The timeout can be configured via the
variable
.Va kern.init_shutdown_timeout .
.Pp
.Nm init
passes
.Dq Li single
as the argument to the shutdown script if return to single-user mode
is requested.
Otherwise,
.Dq Li reboot
argument is used.
.Pp
The role of
.Nm
is so critical that if it dies, the system will reboot itself

View File

@ -23,7 +23,7 @@ xxx {
# Standard recipe
exec.start += "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.stop = "/bin/sh /etc/rc.shutdown jail";
exec.consolelog = "/var/log/jail_xxx_console.log";
mount.devfs; # mount devfs

View File

@ -67,7 +67,7 @@
#
# # Standard recipe
# exec.start += "/bin/sh /etc/rc";
# exec.stop = "/bin/sh /etc/rc.shutdown";
# exec.stop = "/bin/sh /etc/rc.shutdown jail";
# exec.consolelog = "/var/log/jail_xxx_console.log";
# mount.devfs;
#

View File

@ -67,7 +67,7 @@
#
# # Standard recipe
# exec.start += "/bin/sh /etc/rc";
# exec.stop = "/bin/sh /etc/rc.shutdown";
# exec.stop = "/bin/sh /etc/rc.shutdown jail";
# exec.consolelog = "/var/log/jail_xxx_console.log";
# mount.devfs;
#

View File

@ -3738,6 +3738,41 @@ is set to
these are the flags passed to the
.Xr watchdogd 8
daemon.
.It Va watchdogd_timeout
.Pq Vt int
If
.Va watchdogd_enable
is set to
.Dq Li YES ,
this is a timeout that will be used by the
.Xr watchdogd 8
daemon.
If this option is set, it overrides
.Fl t
in
.Va watchdogd_flags .
.It Va watchdogd_shutdown_timeout
.Pq Vt int
If
.Va watchdogd_enable
is set to
.Dq Li YES ,
this is a timeout that will be set by the
.Xr watchdogd 8
daemon when it exits during the system shutdown.
This timeout will not be set when returning to the single-user mode
or when the watchdogd service is stopped individually using the
.Xr service 8
command or the rc.d script.
Note that the timeout will be applied if
.Xr watchdogd 8
is stopped outside of
.Xr rc 8
framework.
If this option is set, it overrides
.Fl x
in
.Va watchdogd_flags .
.It Va devfs_rulesets
.Pq Vt str
List of files containing sets of rules for

View File

@ -189,6 +189,14 @@ also exists (because it was created by a script), then delete it and reboot.
.Ss Operation of Nm rc.shutdown
.Bl -enum
.It
Set
.Va rc_shutdown
to the value of the first argument passed to
.Nm rc.shutdown
or to
.Dq Li unspecified
if no argument was passed.
.It
Source
.Pa /etc/rc.subr
to load various

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 18, 2019
.Dd August 6, 2019
.Dt JAIL 8
.Os
.Sh NAME
@ -681,7 +681,7 @@ A value of
.Dq inherit
will keep the same environment, and
.Dq new
will give the jail it's own environment (still originally inherited when
will give the jail its own environment (still originally inherited when
the jail is created).
.It Va linux.osname , linux.osrelease , linux.oss_version
The Linux OS name, OS release, and OSS version associated with this jail.
@ -754,7 +754,7 @@ and after any
.Va exec.prestop
commands have completed.
A typical command to run is
.Dq sh /etc/rc.shutdown .
.Dq sh /etc/rc.shutdown jail .
.It Va exec.poststop
Command(s) to run in the system environment after a jail is removed.
.It Va exec.clean
@ -1103,7 +1103,7 @@ testjail {
ip4.addr = 192.0.2.100;
interface = em0;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.stop = "/bin/sh /etc/rc.shutdown jail";
}
.Ed
.Pp

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 13, 2014
.Dd August 6, 2019
.Dt JAIL.CONF 5
.Os
.Sh NAME
@ -182,7 +182,7 @@ in the middle of a string or a token.
# Typical static defaults:
# Use the rc scripts to start and stop jails. Mount jail's /dev.
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.stop = "/bin/sh /etc/rc.shutdown jail";
exec.clean;
mount.devfs;