diff mbox series

[RFC,4/8] signals: Remove sigmask() macro

Message ID 20220103181956.983342-5-walt@drummond.us (mailing list archive)
State New, archived
Headers show
Series signals: Support more than 64 signals | expand

Commit Message

Walt Drummond Jan. 3, 2022, 6:19 p.m. UTC
The sigmask() macro can't support signals numbers larger than 64.

Remove the general usage of sigmask() and bit masks as input into the
functions that manipulate or accept sigset_t, with the exceptions of
compatibility cases. Use a comma-separated list of signal numbers as
input to sigaddset()/sigdelset()/... instead.

Signed-off-by: Walt Drummond <walt@drummond.us>
---
 arch/alpha/kernel/signal.c     |   4 +-
 arch/m68k/include/asm/signal.h |   6 +-
 arch/nios2/kernel/signal.c     |   2 -
 arch/x86/include/asm/signal.h  |   6 +-
 drivers/scsi/dpti.h            |   2 -
 fs/ceph/addr.c                 |   2 +-
 fs/jffs2/background.c          |   2 +-
 fs/lockd/svc.c                 |   1 -
 fs/signalfd.c                  |   2 +-
 include/linux/signal.h         | 254 +++++++++++++++++++++------------
 kernel/compat.c                |   6 +-
 kernel/fork.c                  |   2 +-
 kernel/ptrace.c                |   2 +-
 kernel/signal.c                | 115 +++++++--------
 virt/kvm/kvm_main.c            |   2 +-
 15 files changed, 238 insertions(+), 170 deletions(-)
diff mbox series

Patch

diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index bc077babafab..cae533594248 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -33,7 +33,7 @@ 
 
 #define DEBUG_SIG 0
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+#define _BLOCKABLE (~(compat_sigmask(SIGKILL) | compat_sigmask(SIGSTOP)))
 
 asmlinkage void ret_from_sys_call(void);
 
@@ -47,7 +47,7 @@  SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask)
 	sigset_t mask;
 	unsigned long res;
 
-	siginitset(&mask, newmask & _BLOCKABLE);
+	compat_siginitset(&mask, newmask & _BLOCKABLE);
 	res = sigprocmask(how, &mask, &oldmask);
 	if (!res) {
 		force_successful_syscall_return();
diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h
index 8af85c38d377..464ff863c958 100644
--- a/arch/m68k/include/asm/signal.h
+++ b/arch/m68k/include/asm/signal.h
@@ -24,7 +24,7 @@  typedef struct {
 #ifndef CONFIG_CPU_HAS_NO_BITFIELDS
 #define __HAVE_ARCH_SIG_BITOPS
 
-static inline void sigaddset(sigset_t *set, int _sig)
+static inline void sigset_add(sigset_t *set, int _sig)
 {
 	asm ("bfset %0{%1,#1}"
 		: "+o" (*set)
@@ -32,7 +32,7 @@  static inline void sigaddset(sigset_t *set, int _sig)
 		: "cc");
 }
 
-static inline void sigdelset(sigset_t *set, int _sig)
+static inline void sigset_del(sigset_t *set, int _sig)
 {
 	asm ("bfclr %0{%1,#1}"
 		: "+o" (*set)
@@ -56,7 +56,7 @@  static inline int __gen_sigismember(sigset_t *set, int _sig)
 	return ret;
 }
 
-#define sigismember(set,sig)			\
+#define sigset_ismember(set, sig)		\
 	(__builtin_constant_p(sig) ?		\
 	 __const_sigismember(set,sig) :		\
 	 __gen_sigismember(set,sig))
diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c
index 2009ae2d3c3b..c9db511a6989 100644
--- a/arch/nios2/kernel/signal.c
+++ b/arch/nios2/kernel/signal.c
@@ -20,8 +20,6 @@ 
 #include <asm/ucontext.h>
 #include <asm/cacheflush.h>
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
 /*
  * Do a signal return; undo the signal stack.
  *
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 2dfb5fea13af..9bac7c6e524c 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -46,7 +46,7 @@  typedef sigset_t compat_sigset_t;
 
 #define __HAVE_ARCH_SIG_BITOPS
 
-#define sigaddset(set,sig)		    \
+#define sigset_add(set, sig)		    \
 	(__builtin_constant_p(sig)	    \
 	 ? __const_sigaddset((set), (sig))  \
 	 : __gen_sigaddset((set), (sig)))
@@ -62,7 +62,7 @@  static inline void __const_sigaddset(sigset_t *set, int _sig)
 	set->sig[sig / _NSIG_BPW] |= 1 << (sig % _NSIG_BPW);
 }
 
-#define sigdelset(set, sig)		    \
+#define sigset_del(set, sig)		    \
 	(__builtin_constant_p(sig)	    \
 	 ? __const_sigdelset((set), (sig))  \
 	 : __gen_sigdelset((set), (sig)))
@@ -93,7 +93,7 @@  static inline int __gen_sigismember(sigset_t *set, int _sig)
 	return ret;
 }
 
-#define sigismember(set, sig)			\
+#define sigset_ismember(set, sig)		\
 	(__builtin_constant_p(sig)		\
 	 ? __const_sigismember((set), (sig))	\
 	 : __gen_sigismember((set), (sig)))
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 8a079e8d7f65..cfcbb7d98fc0 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -96,8 +96,6 @@  static int adpt_device_reset(struct scsi_cmnd* cmd);
 #define PINFO(fmt, args...) printk(KERN_INFO fmt, ##args)
 #define PCRIT(fmt, args...) printk(KERN_CRIT fmt, ##args)
 
-#define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
-
 // Command timeouts
 #define FOREVER			(0)
 #define TMOUT_INQUIRY 		(20)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 99b80b5c7a93..238b5ce5ef64 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1333,7 +1333,7 @@  const struct address_space_operations ceph_aops = {
 static void ceph_block_sigs(sigset_t *oldset)
 {
 	sigset_t mask;
-	siginitsetinv(&mask, sigmask(SIGKILL));
+	siginitsetinv(&mask, SIGKILL);
 	sigprocmask(SIG_BLOCK, &mask, oldset);
 }
 
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 2b4d5013dc5d..bb84a8b2373c 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -77,7 +77,7 @@  static int jffs2_garbage_collect_thread(void *_c)
 	struct jffs2_sb_info *c = _c;
 	sigset_t hupmask;
 
-	siginitset(&hupmask, sigmask(SIGHUP));
+	siginitset(&hupmask, SIGHUP);
 	allow_signal(SIGKILL);
 	allow_signal(SIGSTOP);
 	allow_signal(SIGHUP);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index b632be3ad57b..3c8b56c094d0 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -45,7 +45,6 @@ 
 
 #define NLMDBG_FACILITY		NLMDBG_SVC
 #define LOCKD_BUFSIZE		(1024 + NLMSVC_XDRSIZE)
-#define ALLOWED_SIGS		(sigmask(SIGKILL))
 
 static struct svc_program	nlmsvc_program;
 
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 12fdc282e299..ed024d5aad2a 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -270,7 +270,7 @@  static int do_signalfd4(int ufd, sigset_t *mask, int flags)
 	if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))
 		return -EINVAL;
 
-	sigdelsetmask(mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+	sigdelset(mask, SIGKILL, SIGSTOP);
 	signotset(mask);
 
 	if (ufd == -1) {
diff --git a/include/linux/signal.h b/include/linux/signal.h
index a730f3d4615e..eaf7991fffee 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -53,6 +53,12 @@  enum siginfo_layout {
 
 enum siginfo_layout siginfo_layout(unsigned sig, int si_code);
 
+/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
+static inline int valid_signal(unsigned long sig)
+{
+	return sig <= _NSIG ? 1 : 0;
+}
+
 /* Test if 'sig' is a realtime signal.  Use this instead of testing
  * SIGRTMIN/SIGRTMAX directly.
  */
@@ -62,15 +68,20 @@  static inline int realtime_signal(unsigned long sig)
 }
 
 /*
- * Define some primitives to manipulate sigset_t.
+ * Define some primitives to manipulate individual bits in sigset_t.
+ * Don't use these directly.  Architectures can define their own
+ * versions (see arch/x86/include/signal.h)
  */
 
 #ifndef __HAVE_ARCH_SIG_BITOPS
-#include <linux/bitops.h>
+#define sigset_add(set, sig)       __sigset_add(set, sig)
+#define sigset_del(set, sig)       __sigset_del(set, sig)
+#define sigset_ismember(set, sig)  __sigset_ismember(set, sig)
+#endif
 
 /* We don't use <linux/bitops.h> for these because there is no need to
    be atomic.  */
-static inline void sigaddset(sigset_t *set, int _sig)
+static inline void __sigset_add(sigset_t *set, int _sig)
 {
 	unsigned long sig = _sig - 1;
 	if (_NSIG_WORDS == 1)
@@ -79,7 +90,7 @@  static inline void sigaddset(sigset_t *set, int _sig)
 		set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW);
 }
 
-static inline void sigdelset(sigset_t *set, int _sig)
+static inline void __sigset_del(sigset_t *set, int _sig)
 {
 	unsigned long sig = _sig - 1;
 	if (_NSIG_WORDS == 1)
@@ -88,33 +99,72 @@  static inline void sigdelset(sigset_t *set, int _sig)
 		set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW));
 }
 
-static inline int sigismember(sigset_t *set, int _sig)
+static inline int __sigset_ismember(sigset_t *set, int _sig)
 {
 	unsigned long sig = _sig - 1;
 	if (_NSIG_WORDS == 1)
-		return 1 & (set->sig[0] >> sig);
+		return 1UL & (set->sig[0] >> sig);
 	else
-		return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
+		return 1UL & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
 }
 
-#endif /* __HAVE_ARCH_SIG_BITOPS */
+/* Some primitives for setting/deleting signals from sigset_t.  Use these. */
 
-static inline int sigisemptyset(sigset_t *set)
+#define NUM_INTARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+
+#define sigdelset(x, ...) __sigdelset((x), NUM_INTARGS(__VA_ARGS__),	\
+				      __VA_ARGS__)
+static inline void __sigdelset(sigset_t *set, int count, ...)
 {
-	switch (_NSIG_WORDS) {
-	case 4:
-		return (set->sig[3] | set->sig[2] |
-			set->sig[1] | set->sig[0]) == 0;
-	case 2:
-		return (set->sig[1] | set->sig[0]) == 0;
-	case 1:
-		return set->sig[0] == 0;
-	default:
-		BUILD_BUG();
-		return 0;
+	va_list ap;
+	int sig;
+
+	va_start(ap, count);
+	while (count > 0) {
+		sig = va_arg(ap, int);
+		if (valid_signal(sig) && sig != 0)
+			sigset_del(set, sig);
+		count--;
 	}
+	va_end(ap);
+}
+
+#define sigaddset(x, ...) __sigaddset((x), NUM_INTARGS(__VA_ARGS__),	\
+				      __VA_ARGS__)
+static inline void __sigaddset(sigset_t *set, int count, ...)
+{
+	va_list ap;
+	int sig;
+
+	va_start(ap, count);
+	while (count > 0) {
+		sig = va_arg(ap, int);
+		if (valid_signal(sig) && sig != 0)
+			sigset_add(set, sig);
+		count--;
+	}
+	va_end(ap);
+}
+
+static inline int sigismember(sigset_t *set, int sig)
+{
+	if (!valid_signal(sig) || sig == 0)
+		return 0;
+	return sigset_ismember(set, sig);
 }
 
+#define siginitset(set, ...)			\
+do {						\
+	sigemptyset((set));			\
+	sigaddset((set), __VA_ARGS__);		\
+} while (0)
+
+#define siginitsetinv(set, ...)			\
+do {					        \
+	sigfillset((set));			\
+	sigdelset((set), __VA_ARGS__);		\
+} while (0)
+
 static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2)
 {
 	switch (_NSIG_WORDS) {
@@ -128,11 +178,18 @@  static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2)
 			(set1->sig[0] == set2->sig[0]);
 	case 1:
 		return	set1->sig[0] == set2->sig[0];
+	default:
+		return memcmp(set1, set2, sizeof(sigset_t)) == 0;
 	}
 	return 0;
 }
 
-#define sigmask(sig)	(1UL << ((sig) - 1))
+static inline int sigisemptyset(sigset_t *set)
+{
+	sigset_t empty = {0};
+
+	return sigequalsets(set, &empty);
+}
 
 #ifndef __HAVE_ARCH_SIG_SETOPS
 #include <linux/string.h>
@@ -141,6 +198,7 @@  static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2)
 static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \
 {									\
 	unsigned long a0, a1, a2, a3, b0, b1, b2, b3;			\
+	int i;								\
 									\
 	switch (_NSIG_WORDS) {						\
 	case 4:								\
@@ -158,7 +216,9 @@  static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \
 		r->sig[0] = op(a0, b0);					\
 		break;							\
 	default:							\
-		BUILD_BUG();						\
+		for (i = 0; i < _NSIG_WORDS; i++)			\
+			r->sig[i] = op(a->sig[i], b->sig[i]);		\
+		break;							\
 	}								\
 }
 
@@ -179,6 +239,8 @@  _SIG_SET_BINOP(sigandnsets, _sig_andn)
 #define _SIG_SET_OP(name, op)						\
 static inline void name(sigset_t *set)					\
 {									\
+	int i;								\
+									\
 	switch (_NSIG_WORDS) {						\
 	case 4:	set->sig[3] = op(set->sig[3]);				\
 		set->sig[2] = op(set->sig[2]);				\
@@ -188,7 +250,9 @@  static inline void name(sigset_t *set)					\
 	case 1:	set->sig[0] = op(set->sig[0]);				\
 		    break;						\
 	default:							\
-		BUILD_BUG();						\
+		for (i = 0; i < _NSIG_WORDS; i++)			\
+			set->sig[i] = op(set->sig[i]);			\
+		break;							\
 	}								\
 }
 
@@ -224,24 +288,13 @@  static inline void sigfillset(sigset_t *set)
 	}
 }
 
-/* Some extensions for manipulating the low 32 signals in particular.  */
+#endif /* __HAVE_ARCH_SIG_SETOPS */
 
-static inline void sigaddsetmask(sigset_t *set, unsigned long mask)
-{
-	set->sig[0] |= mask;
-}
+/* Primitives for handing the compat (first long) sigset_t */
 
-static inline void sigdelsetmask(sigset_t *set, unsigned long mask)
-{
-	set->sig[0] &= ~mask;
-}
+#define compat_sigmask(sig)       (1UL << ((sig) - 1))
 
-static inline int sigtestsetmask(sigset_t *set, unsigned long mask)
-{
-	return (set->sig[0] & mask) != 0;
-}
-
-static inline void siginitset(sigset_t *set, unsigned long mask)
+static inline void compat_siginitset(sigset_t *set, unsigned long mask)
 {
 	set->sig[0] = mask;
 	switch (_NSIG_WORDS) {
@@ -254,7 +307,7 @@  static inline void siginitset(sigset_t *set, unsigned long mask)
 	}
 }
 
-static inline void siginitsetinv(sigset_t *set, unsigned long mask)
+static inline void compat_siginitsetinv(sigset_t *set, unsigned long mask)
 {
 	set->sig[0] = ~mask;
 	switch (_NSIG_WORDS) {
@@ -267,7 +320,21 @@  static inline void siginitsetinv(sigset_t *set, unsigned long mask)
 	}
 }
 
-#endif /* __HAVE_ARCH_SIG_SETOPS */
+static inline void compat_sigaddsetmask(sigset_t *set, unsigned long mask)
+{
+	set->sig[0] |= mask;
+}
+
+static inline void compat_sigdelsetmask(sigset_t *set, unsigned long mask)
+{
+	set->sig[0] &= ~mask;
+}
+
+static inline int compat_sigtestsetmask(sigset_t *set, unsigned long mask)
+{
+	return (set->sig[0] & mask) != 0;
+}
+
 
 /* Safely copy a sigset_t from user space handling any differences in
  * size between user space and kernel sigset_t.  We don't use
@@ -338,12 +405,6 @@  static inline void init_sigpending(struct sigpending *sig)
 
 extern void flush_sigqueue(struct sigpending *queue);
 
-/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
-static inline int valid_signal(unsigned long sig)
-{
-	return sig <= _NSIG ? 1 : 0;
-}
-
 struct timespec;
 struct pt_regs;
 enum pid_type;
@@ -470,55 +531,72 @@  extern bool unhandled_signal(struct task_struct *tsk, int sig);
  * default action of stopping the process may happen later or never.
  */
 
+static inline int sig_kernel_stop(unsigned long sig)
+{
+	return	sig == SIGSTOP ||
+		sig == SIGTSTP ||
+		sig == SIGTTIN ||
+		sig == SIGTTOU;
+}
+
+static inline int sig_kernel_ignore(unsigned long sig)
+{
+	return	sig == SIGCONT	||
+		sig == SIGCHLD	||
+		sig == SIGWINCH ||
+		sig == SIGURG;
+}
+
+static inline int sig_kernel_only(unsigned long sig)
+{
+	return	sig == SIGKILL ||
+		sig == SIGSTOP;
+}
+
+static inline int sig_kernel_coredump(unsigned long sig)
+{
+	return	sig == SIGQUIT ||
+		sig == SIGILL  ||
+		sig == SIGTRAP ||
+		sig == SIGABRT ||
+		sig == SIGFPE  ||
+		sig == SIGSEGV ||
+		sig == SIGBUS  ||
+		sig == SIGSYS  ||
+		sig == SIGXCPU ||
 #ifdef SIGEMT
-#define SIGEMT_MASK	rt_sigmask(SIGEMT)
-#else
-#define SIGEMT_MASK	0
+		sig == SIGEMT  ||
 #endif
+		sig == SIGXFSZ;
+}
 
-#if SIGRTMIN > BITS_PER_LONG
-#define rt_sigmask(sig)	(1ULL << ((sig)-1))
-#else
-#define rt_sigmask(sig)	sigmask(sig)
+static inline int sig_specific_sicodes(unsigned long sig)
+{
+	return	sig == SIGILL  ||
+		sig == SIGFPE  ||
+		sig == SIGSEGV ||
+		sig == SIGBUS  ||
+		sig == SIGTRAP ||
+		sig == SIGCHLD ||
+		sig == SIGPOLL ||
+#ifdef SIGEMT
+		sig == SIGEMT  ||
 #endif
+		sig == SIGSYS;
+}
 
-#define siginmask(sig, mask) \
-	((sig) > 0 && (sig) < SIGRTMIN && (rt_sigmask(sig) & (mask)))
-
-#define SIG_KERNEL_ONLY_MASK (\
-	rt_sigmask(SIGKILL)   |  rt_sigmask(SIGSTOP))
-
-#define SIG_KERNEL_STOP_MASK (\
-	rt_sigmask(SIGSTOP)   |  rt_sigmask(SIGTSTP)   | \
-	rt_sigmask(SIGTTIN)   |  rt_sigmask(SIGTTOU)   )
-
-#define SIG_KERNEL_COREDUMP_MASK (\
-        rt_sigmask(SIGQUIT)   |  rt_sigmask(SIGILL)    | \
-	rt_sigmask(SIGTRAP)   |  rt_sigmask(SIGABRT)   | \
-        rt_sigmask(SIGFPE)    |  rt_sigmask(SIGSEGV)   | \
-	rt_sigmask(SIGBUS)    |  rt_sigmask(SIGSYS)    | \
-        rt_sigmask(SIGXCPU)   |  rt_sigmask(SIGXFSZ)   | \
-	SIGEMT_MASK				       )
-
-#define SIG_KERNEL_IGNORE_MASK (\
-        rt_sigmask(SIGCONT)   |  rt_sigmask(SIGCHLD)   | \
-	rt_sigmask(SIGWINCH)  |  rt_sigmask(SIGURG)    )
-
-#define SIG_SPECIFIC_SICODES_MASK (\
-	rt_sigmask(SIGILL)    |  rt_sigmask(SIGFPE)    | \
-	rt_sigmask(SIGSEGV)   |  rt_sigmask(SIGBUS)    | \
-	rt_sigmask(SIGTRAP)   |  rt_sigmask(SIGCHLD)   | \
-	rt_sigmask(SIGPOLL)   |  rt_sigmask(SIGSYS)    | \
-	SIGEMT_MASK                                    )
-
-#define sig_kernel_only(sig)		siginmask(sig, SIG_KERNEL_ONLY_MASK)
-#define sig_kernel_coredump(sig)	siginmask(sig, SIG_KERNEL_COREDUMP_MASK)
-#define sig_kernel_ignore(sig)		siginmask(sig, SIG_KERNEL_IGNORE_MASK)
-#define sig_kernel_stop(sig)		siginmask(sig, SIG_KERNEL_STOP_MASK)
-#define sig_specific_sicodes(sig)	siginmask(sig, SIG_SPECIFIC_SICODES_MASK)
+static inline int synchronous_signal(unsigned long sig)
+{
+	return	sig == SIGSEGV ||
+		sig == SIGBUS  ||
+		sig == SIGILL  ||
+		sig == SIGTRAP ||
+		sig == SIGFPE  ||
+		sig == SIGSYS;
+}
 
 #define sig_fatal(t, signr) \
-	(!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
+	(!(sig_kernel_ignore(signr) ||	sig_kernel_stop(signr)) &&	\
 	 (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
 void signals_init(void);
diff --git a/kernel/compat.c b/kernel/compat.c
index cc2438f4070c..26ffd271444c 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -49,16 +49,16 @@  COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
 	if (nset) {
 		if (get_user(new_set, nset))
 			return -EFAULT;
-		new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
+		new_set &= ~(compat_sigmask(SIGKILL) | compat_sigmask(SIGSTOP));
 
 		new_blocked = current->blocked;
 
 		switch (how) {
 		case SIG_BLOCK:
-			sigaddsetmask(&new_blocked, new_set);
+			compat_sigaddsetmask(&new_blocked, new_set);
 			break;
 		case SIG_UNBLOCK:
-			sigdelsetmask(&new_blocked, new_set);
+			compat_sigdelsetmask(&new_blocked, new_set);
 			break;
 		case SIG_SETMASK:
 			compat_sig_setmask(&new_blocked, new_set);
diff --git a/kernel/fork.c b/kernel/fork.c
index 38681ad44c76..8b07f0090b82 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2032,7 +2032,7 @@  static __latent_entropy struct task_struct *copy_process(
 		 * fatal or STOP
 		 */
 		p->flags |= PF_IO_WORKER;
-		siginitsetinv(&p->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		siginitsetinv(&p->blocked, SIGKILL, SIGSTOP);
 	}
 
 	/*
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 2f7ee345a629..200b99d39878 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -1102,7 +1102,7 @@  int ptrace_request(struct task_struct *child, long request,
 		if (ret)
 			break;
 
-		sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigdelset(&new_set, SIGKILL, SIGSTOP);
 
 		/*
 		 * Every thread does recalc_sigpending() after resume, so
diff --git a/kernel/signal.c b/kernel/signal.c
index a2f0e38ba934..9421f1112b20 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -64,6 +64,9 @@  static struct kmem_cache *sigqueue_cachep;
 
 int print_fatal_signals __read_mostly;
 
+sigset_t signal_stop_mask;
+sigset_t signal_synchronous_mask;
+
 static void __user *sig_handler(struct task_struct *t, int sig)
 {
 	return t->sighand->action[sig - 1].sa.sa_handler;
@@ -199,55 +202,26 @@  void calculate_sigpending(void)
 }
 
 /* Given the mask, find the first available signal that should be serviced. */
-
-#define SYNCHRONOUS_MASK \
-	(sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \
-	 sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS))
-
 int next_signal(struct sigpending *pending, sigset_t *mask)
 {
-	unsigned long i, *s, *m, x;
-	int sig = 0;
+	int i, sig;
+	sigset_t pend, s;
 
-	s = pending->signal.sig;
-	m = mask->sig;
+	sigandnsets(&pend, &pending->signal, mask);
 
-	/*
-	 * Handle the first word specially: it contains the
-	 * synchronous signals that need to be dequeued first.
-	 */
-	x = *s &~ *m;
-	if (x) {
-		if (x & SYNCHRONOUS_MASK)
-			x &= SYNCHRONOUS_MASK;
-		sig = ffz(~x) + 1;
-		return sig;
-	}
+	/* Handle synchronous signals first */
+	sigandsets(&s, &pend, &signal_synchronous_mask);
+	if (!sigisemptyset(&s))
+		pend = s;
 
-	switch (_NSIG_WORDS) {
-	default:
-		for (i = 1; i < _NSIG_WORDS; ++i) {
-			x = *++s &~ *++m;
-			if (!x)
-				continue;
-			sig = ffz(~x) + i*_NSIG_BPW + 1;
-			break;
+	for (i = 0; i < _NSIG_WORDS; i++) {
+		if (pend.sig[i] != 0) {
+			sig = ffz(~pend.sig[i]) + i*_NSIG_BPW + 1;
+			return sig;
 		}
-		break;
-
-	case 2:
-		x = s[1] &~ m[1];
-		if (!x)
-			break;
-		sig = ffz(~x) + _NSIG_BPW + 1;
-		break;
-
-	case 1:
-		/* Nothing to do */
-		break;
 	}
 
-	return sig;
+	return 0;
 }
 
 static inline void print_dropped_signal(int sig)
@@ -709,11 +683,14 @@  static int dequeue_synchronous_signal(kernel_siginfo_t *info)
 	struct task_struct *tsk = current;
 	struct sigpending *pending = &tsk->pending;
 	struct sigqueue *q, *sync = NULL;
+	sigset_t s;
 
 	/*
 	 * Might a synchronous signal be in the queue?
 	 */
-	if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK))
+	sigandnsets(&s, &pending->signal, &tsk->blocked);
+	sigandsets(&s, &s, &signal_synchronous_mask);
+	if (sigisemptyset(&s))
 		return 0;
 
 	/*
@@ -722,7 +699,7 @@  static int dequeue_synchronous_signal(kernel_siginfo_t *info)
 	list_for_each_entry(q, &pending->list, list) {
 		/* Synchronous signals have a positive si_code */
 		if ((q->info.si_code > SI_USER) &&
-		    (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) {
+		    synchronous_signal(q->info.si_signo)) {
 			sync = q;
 			goto next;
 		}
@@ -795,6 +772,25 @@  static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
 	}
 }
 
+#define flush_sigqueue_sig(x, ...) __flush_sigqueue_sig((x),		\
+					NUM_INTARGS(__VA_ARGS__), __VA_ARGS__)
+static void __flush_sigqueue_sig(struct sigpending *s, int count, ...)
+{
+	va_list ap;
+	sigset_t mask;
+	int sig;
+
+	sigemptyset(&mask);
+	va_start(ap, count);
+	while (count > 0) {
+		sig = va_arg(ap, int);
+		if (valid_signal(sig) && sig != 0)
+			sigset_add(&mask, sig);
+		count--;
+	}
+	flush_sigqueue_mask(&mask, s);
+}
+
 static inline int is_si_special(const struct kernel_siginfo *info)
 {
 	return info <= SEND_SIG_PRIV;
@@ -913,8 +909,7 @@  static bool prepare_signal(int sig, struct task_struct *p, bool force)
 		/*
 		 * This is a stop signal.  Remove SIGCONT from all queues.
 		 */
-		siginitset(&flush, sigmask(SIGCONT));
-		flush_sigqueue_mask(&flush, &signal->shared_pending);
+		flush_sigqueue_sig(&signal->shared_pending, SIGCONT);
 		for_each_thread(p, t)
 			flush_sigqueue_mask(&flush, &t->pending);
 	} else if (sig == SIGCONT) {
@@ -922,10 +917,9 @@  static bool prepare_signal(int sig, struct task_struct *p, bool force)
 		/*
 		 * Remove all stop signals from all queues, wake all threads.
 		 */
-		siginitset(&flush, SIG_KERNEL_STOP_MASK);
-		flush_sigqueue_mask(&flush, &signal->shared_pending);
+		flush_sigqueue_mask(&signal_stop_mask, &signal->shared_pending);
 		for_each_thread(p, t) {
-			flush_sigqueue_mask(&flush, &t->pending);
+			flush_sigqueue_mask(&signal_stop_mask, &t->pending);
 			task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING);
 			if (likely(!(t->ptrace & PT_SEIZED)))
 				wake_up_state(t, __TASK_STOPPED);
@@ -1172,7 +1166,7 @@  static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc
 			sigset_t *signal = &delayed->signal;
 			/* Can't queue both a stop and a continue signal */
 			if (sig == SIGCONT)
-				sigdelsetmask(signal, SIG_KERNEL_STOP_MASK);
+				sigandnsets(signal, signal, &signal_stop_mask);
 			else if (sig_kernel_stop(sig))
 				sigdelset(signal, SIGCONT);
 			sigaddset(signal, sig);
@@ -3023,7 +3017,7 @@  static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset)
  */
 void set_current_blocked(sigset_t *newset)
 {
-	sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP));
+	sigdelset(newset, SIGKILL, SIGSTOP);
 	__set_current_blocked(newset);
 }
 
@@ -3150,7 +3144,7 @@  SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset,
 	if (nset) {
 		if (copy_sigset_from_user(&new_set, nset, sigsetsize))
 			return -EFAULT;
-		sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigdelset(&new_set, SIGKILL, SIGSTOP);
 
 		error = sigprocmask(how, &new_set, NULL);
 		if (error)
@@ -3180,7 +3174,7 @@  COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset,
 	if (nset) {
 		if (copy_compat_sigset_from_user(&new_set, nset, sigsetsize))
 			return -EFAULT;
-		sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigdelset(&new_set, SIGKILL, SIGSTOP);
 
 		error = sigprocmask(how, &new_set, NULL);
 		if (error)
@@ -3586,7 +3580,7 @@  static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info,
 	/*
 	 * Invert the set of allowed signals to get those we want to block.
 	 */
-	sigdelsetmask(&mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+	sigdelset(&mask, SIGKILL, SIGSTOP);
 	signotset(&mask);
 
 	spin_lock_irq(&tsk->sighand->siglock);
@@ -4111,8 +4105,7 @@  int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 	sigaction_compat_abi(act, oact);
 
 	if (act) {
-		sigdelsetmask(&act->sa.sa_mask,
-			      sigmask(SIGKILL) | sigmask(SIGSTOP));
+		sigdelset(&act->sa.sa_mask, SIGKILL, SIGSTOP);
 		*k = *act;
 		/*
 		 * POSIX 3.3.1.3:
@@ -4126,9 +4119,7 @@  int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 		 *   be discarded, whether or not it is blocked"
 		 */
 		if (sig_handler_ignored(sig_handler(p, sig), sig)) {
-			sigemptyset(&mask);
-			sigaddset(&mask, sig);
-			flush_sigqueue_mask(&mask, &p->signal->shared_pending);
+			flush_sigqueue_sig(&p->signal->shared_pending, sig);
 			for_each_thread(p, t)
 				flush_sigqueue_mask(&mask, &t->pending);
 		}
@@ -4332,10 +4323,10 @@  SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset,
 
 		switch (how) {
 		case SIG_BLOCK:
-			sigaddsetmask(&new_blocked, new_set);
+			compat_sigaddsetmask(&new_blocked, new_set);
 			break;
 		case SIG_UNBLOCK:
-			sigdelsetmask(&new_blocked, new_set);
+			compat_sigdelsetmask(&new_blocked, new_set);
 			break;
 		case SIG_SETMASK:
 			new_blocked.sig[0] = new_set;
@@ -4724,6 +4715,10 @@  void __init signals_init(void)
 {
 	siginfo_buildtime_checks();
 
+	sigaddset(&signal_stop_mask, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU);
+	sigaddset(&signal_synchronous_mask, SIGSEGV, SIGBUS, SIGILL, SIGTRAP,
+		 SIGFPE, SIGSYS);
+
 	sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC | SLAB_ACCOUNT);
 }
 
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index c8b3645c9a7d..ab6ba4ec661b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3684,7 +3684,7 @@  static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
 static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
 {
 	if (sigset) {
-		sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		sigdelset(sigset, SIGKILL, SIGSTOP);
 		vcpu->sigset_active = 1;
 		vcpu->sigset = *sigset;
 	} else