Skip to content

Commit

Permalink
Add SIGSTOP and SIGTSTP handling to issig
Browse files Browse the repository at this point in the history
This change adds SIGSTOP and SIGTSTP handling to the issig function;
this mirrors its behavior on Solaris. This way, long running kernel
tasks can be stopped with the appropriate signals. Note that doing
so with ctrl-z on the command line doesn't return control of the tty
to the shell, because tty handling is done separately from stopping
the process. That can be future work, if people feel that it is a
necessary addition.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Signed-off-by: Paul Dagnelie <pcd@delphix.com>
Issue openzfs#810
Issue openzfs#10843
Closes openzfs#11801
  • Loading branch information
pcd1193182 authored and Ryan Moeller committed Oct 7, 2021
1 parent d9374e5 commit 9b80856
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 17 deletions.
21 changes: 21 additions & 0 deletions config/kernel-siginfo.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dnl #
dnl # 4.20 API change
dnl # Added kernel_siginfo_t
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_SIGINFO], [
ZFS_LINUX_TEST_SRC([siginfo], [
#include <linux/signal_types.h>
],[
kernel_siginfo_t info __attribute__ ((unused));
])
])

AC_DEFUN([ZFS_AC_KERNEL_SIGINFO], [
AC_MSG_CHECKING([whether kernel_siginfo_t tyepedef exists])
ZFS_LINUX_TEST_RESULT([siginfo], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SIGINFO, 1, [kernel_siginfo_t exists])
],[
AC_MSG_RESULT(no)
])
])
21 changes: 21 additions & 0 deletions config/kernel-signal-stop.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dnl #
dnl # 4.4 API change
dnl # Added kernel_signal_stop
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_SIGNAL_STOP], [
ZFS_LINUX_TEST_SRC([signal_stop], [
#include <linux/sched/signal.h>
],[
kernel_signal_stop();
])
])

AC_DEFUN([ZFS_AC_KERNEL_SIGNAL_STOP], [
AC_MSG_CHECKING([whether signal_stop() exists])
ZFS_LINUX_TEST_RESULT([signal_stop], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SIGNAL_STOP, 1, [signal_stop() exists])
],[
AC_MSG_RESULT(no)
])
])
21 changes: 21 additions & 0 deletions config/kernel-special-state.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dnl #
dnl # 4.17 API change
dnl # Added set_special_state() function
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE], [
ZFS_LINUX_TEST_SRC([set_special_state], [
#include <linux/sched.h>
],[
set_special_state(TASK_STOPPED);
])
])

AC_DEFUN([ZFS_AC_KERNEL_SET_SPECIAL_STATE], [
AC_MSG_CHECKING([whether set_special_state() exists])
ZFS_LINUX_TEST_RESULT([set_special_state], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SET_SPECIAL_STATE, 1, [set_special_state() exists])
],[
AC_MSG_RESULT(no)
])
])
6 changes: 6 additions & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_MKNOD
ZFS_AC_KERNEL_SRC_SYMLINK
ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS
ZFS_AC_KERNEL_SRC_SIGNAL_STOP
ZFS_AC_KERNEL_SRC_SIGINFO
ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE
AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
Expand Down Expand Up @@ -229,6 +232,9 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_MKNOD
ZFS_AC_KERNEL_SYMLINK
ZFS_AC_KERNEL_BIO_MAX_SEGS
ZFS_AC_KERNEL_SIGNAL_STOP
ZFS_AC_KERNEL_SIGINFO
ZFS_AC_KERNEL_SET_SPECIAL_STATE
])

dnl #
Expand Down
18 changes: 1 addition & 17 deletions include/os/linux/spl/sys/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,6 @@
#define FORREAL 0 /* Usual side-effects */
#define JUSTLOOKING 1 /* Don't stop the process */

/*
* The "why" argument indicates the allowable side-effects of the call:
*
* FORREAL: Extract the next pending signal from p_sig into p_cursig;
* stop the process if a stop has been requested or if a traced signal
* is pending.
*
* JUSTLOOKING: Don't stop the process, just indicate whether or not
* a signal might be pending (FORREAL is needed to tell for sure).
*/
static __inline__ int
issig(int why)
{
ASSERT(why == FORREAL || why == JUSTLOOKING);

return (signal_pending(current));
}
extern int issig(int why);

#endif /* SPL_SIGNAL_H */
13 changes: 13 additions & 0 deletions include/os/linux/spl/sys/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,17 @@ extern struct task_struct *spl_kthread_create(int (*func)(void *),

extern proc_t p0;

#ifdef HAVE_SIGINFO
typedef kernel_siginfo_t spl_kernel_siginfo_t;
#else
typedef siginfo_t spl_kernel_siginfo_t;
#endif

#ifdef HAVE_SET_SPECIAL_STATE
#define spl_set_special_state(x) set_special_state((x))
#else
#define spl_set_special_state(x) __set_current_state((x))
#endif


#endif /* _SPL_THREAD_H */
51 changes: 51 additions & 0 deletions module/os/linux/spl/spl-thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,54 @@ spl_kthread_create(int (*func)(void *), void *data, const char namefmt[], ...)
} while (1);
}
EXPORT_SYMBOL(spl_kthread_create);

/*
* The "why" argument indicates the allowable side-effects of the call:
*
* FORREAL: Extract the next pending signal from p_sig into p_cursig;
* stop the process if a stop has been requested or if a traced signal
* is pending.
*
* JUSTLOOKING: Don't stop the process, just indicate whether or not
* a signal might be pending (FORREAL is needed to tell for sure).
*/
int
issig(int why)
{
ASSERT(why == FORREAL || why == JUSTLOOKING);

if (!signal_pending(current))
return (0);

if (why != FORREAL)
return (1);

struct task_struct *task = current;
spl_kernel_siginfo_t __info;
sigset_t set;
siginitsetinv(&set, 1ULL << (SIGSTOP - 1) | 1ULL << (SIGTSTP - 1));
sigorsets(&set, &task->blocked, &set);

spin_lock_irq(&task->sighand->siglock);
int ret;
if ((ret = dequeue_signal(task, &set, &__info)) != 0) {
#ifdef HAVE_SIGNAL_STOP
spin_unlock_irq(&task->sighand->siglock);
kernel_signal_stop();
#else
if (current->jobctl & JOBCTL_STOP_DEQUEUED)
spl_set_special_state(TASK_STOPPED);

spin_unlock_irq(&current->sighand->siglock);

schedule();
#endif
return (0);
}

spin_unlock_irq(&task->sighand->siglock);

return (1);
}

EXPORT_SYMBOL(issig);

0 comments on commit 9b80856

Please sign in to comment.