aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_shutdown.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2018-03-22 20:47:25 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2018-03-22 20:47:25 +0000
commitc3982007214fa38960660900f06c4c0292fb5326 (patch)
tree17e15916c0d99ff99c4ebc497f5bb52b5dd31c36 /sys/kern/kern_shutdown.c
parent54f30ad961bdd7f1742b58f78211aafe1ec51e37 (diff)
downloadsrc-c3982007214fa38960660900f06c4c0292fb5326.tar.gz
src-c3982007214fa38960660900f06c4c0292fb5326.zip
Do not send signals to init directly from shutdown_nice(9), do it from
the task context. shutdown_nice() is used from the fast interrupt handlers, mostly for console drivers, where we cannot lock blockable locks. Schedule the task in the fast queue to send the signal from the proper context. Reviewed by: imp Discussed with: bde Sponsored by: The FreeBSD Foundation MFC after: 1 week
Notes
Notes: svn path=/head/; revision=331375
Diffstat (limited to 'sys/kern/kern_shutdown.c')
-rw-r--r--sys/kern/kern_shutdown.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c
index e64e1dd39b62..ea16f1fa99d3 100644
--- a/sys/kern/kern_shutdown.c
+++ b/sys/kern/kern_shutdown.c
@@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/sysproto.h>
+#include <sys/taskqueue.h>
#include <sys/vnode.h>
#include <sys/watchdog.h>
@@ -276,6 +277,28 @@ sys_reboot(struct thread *td, struct reboot_args *uap)
return (error);
}
+static void
+shutdown_nice_task_fn(void *arg, int pending __unused)
+{
+ int howto;
+
+ howto = (uintptr_t)arg;
+ /* Send a signal to init(8) and have it shutdown the world. */
+ PROC_LOCK(initproc);
+ if (howto & RB_POWEROFF)
+ kern_psignal(initproc, SIGUSR2);
+ else if (howto & RB_POWERCYCLE)
+ kern_psignal(initproc, SIGWINCH);
+ else if (howto & RB_HALT)
+ kern_psignal(initproc, SIGUSR1);
+ else
+ kern_psignal(initproc, SIGINT);
+ PROC_UNLOCK(initproc);
+}
+
+static struct task shutdown_nice_task = TASK_INITIALIZER(0,
+ &shutdown_nice_task_fn, NULL);
+
/*
* Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC
*/
@@ -283,20 +306,14 @@ void
shutdown_nice(int howto)
{
- if (initproc != NULL) {
- /* Send a signal to init(8) and have it shutdown the world. */
- PROC_LOCK(initproc);
- if (howto & RB_POWEROFF)
- kern_psignal(initproc, SIGUSR2);
- else if (howto & RB_POWERCYCLE)
- kern_psignal(initproc, SIGWINCH);
- else if (howto & RB_HALT)
- kern_psignal(initproc, SIGUSR1);
- else
- kern_psignal(initproc, SIGINT);
- PROC_UNLOCK(initproc);
+ if (initproc != NULL && !SCHEDULER_STOPPED()) {
+ shutdown_nice_task.ta_context = (void *)(uintptr_t)howto;
+ taskqueue_enqueue(taskqueue_fast, &shutdown_nice_task);
} else {
- /* No init(8) running, so simply reboot. */
+ /*
+ * No init(8) running, or scheduler would not allow it
+ * to run, so simply reboot.
+ */
kern_reboot(howto | RB_NOSYNC);
}
}