summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/kernel-siginfo.m421
-rw-r--r--config/kernel-signal-stop.m421
-rw-r--r--config/kernel-special-state.m421
-rw-r--r--config/kernel.m46
-rw-r--r--include/os/linux/spl/sys/signal.h18
-rw-r--r--include/os/linux/spl/sys/thread.h13
-rw-r--r--module/os/linux/spl/spl-thread.c51
7 files changed, 134 insertions, 17 deletions
diff --git a/config/kernel-siginfo.m4 b/config/kernel-siginfo.m4
new file mode 100644
index 000000000..6ddb0dcc3
--- /dev/null
+++ b/config/kernel-siginfo.m4
@@ -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)
+ ])
+])
diff --git a/config/kernel-signal-stop.m4 b/config/kernel-signal-stop.m4
new file mode 100644
index 000000000..6cb86e7c4
--- /dev/null
+++ b/config/kernel-signal-stop.m4
@@ -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)
+ ])
+])
diff --git a/config/kernel-special-state.m4 b/config/kernel-special-state.m4
new file mode 100644
index 000000000..aa60aabeb
--- /dev/null
+++ b/config/kernel-special-state.m4
@@ -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)
+ ])
+])
diff --git a/config/kernel.m4 b/config/kernel.m4
index dfb6165d8..7196e66ca 100644
--- a/config/kernel.m4
+++ b/config/kernel.m4
@@ -129,6 +129,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])
@@ -231,6 +234,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 #
diff --git a/include/os/linux/spl/sys/signal.h b/include/os/linux/spl/sys/signal.h
index fd32f08b3..6b538c896 100644
--- a/include/os/linux/spl/sys/signal.h
+++ b/include/os/linux/spl/sys/signal.h
@@ -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 */
diff --git a/include/os/linux/spl/sys/thread.h b/include/os/linux/spl/sys/thread.h
index 99d9c9bf3..220742387 100644
--- a/include/os/linux/spl/sys/thread.h
+++ b/include/os/linux/spl/sys/thread.h
@@ -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 */
diff --git a/module/os/linux/spl/spl-thread.c b/module/os/linux/spl/spl-thread.c
index db23fb64a..834c52711 100644
--- a/module/os/linux/spl/spl-thread.c
+++ b/module/os/linux/spl/spl-thread.c
@@ -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);