them do want to temporarily block signals.
Kernel users can also block signals that are normally unblockable
to user space, ie SIGKILL and SIGSTOP.
Make nfsd and autofs use the new interface, as an example to others.
if ( wq->name ) {
/* Block all but "shutdown" signals while waiting */
- sigset_t oldset;
- unsigned long irqflags;
+ sigset_t sigmask;
- spin_lock_irqsave(¤t->sighand->siglock, irqflags);
- oldset = current->blocked;
- siginitsetinv(¤t->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, irqflags);
+ siginitsetinv(&sigmask, SHUTDOWN_SIGS);
+ sigprocmask(SIG_BLOCK, &sigmask, &sigmask);
interruptible_sleep_on(&wq->queue);
- spin_lock_irqsave(¤t->sighand->siglock, irqflags);
- current->blocked = oldset;
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, irqflags);
+ sigprocmask(SIG_SETMASK, &sigmask, NULL);
} else {
DPRINTK(("autofs_wait: skipped sleeping\n"));
}
struct svc_serv *serv = rqstp->rq_server;
int err;
struct nfsd_list me;
+ sigset_t shutdown_mask, allowed_mask;
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
sprintf(current->comm, "nfsd");
current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+ siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS);
+ siginitsetinv(&allowed_mask, ALLOWED_SIGS);
+
nfsdstats.th_cnt++;
lockd_up(); /* start lockd */
*/
for (;;) {
/* Block all but the shutdown signals */
- spin_lock_irq(¤t->sighand->siglock);
- siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ sigprocmask(SIG_SETMASK, &shutdown_mask, NULL);
/*
* Find a socket with data available and call its
exp_readlock();
/* Process request with signals blocked. */
- spin_lock_irq(¤t->sighand->siglock);
- siginitsetinv(¤t->blocked, ALLOWED_SIGS);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
svc_process(serv, rqstp);
}
extern long do_sigpending(void *, unsigned long);
+extern int sigprocmask(int, sigset_t *, sigset_t *);
#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
struct pt_regs;
EXPORT_SYMBOL(notify_parent);
EXPORT_SYMBOL(send_sig);
EXPORT_SYMBOL(send_sig_info);
+EXPORT_SYMBOL(sigprocmask);
EXPORT_SYMBOL(block_all_signals);
EXPORT_SYMBOL(unblock_all_signals);
* used by various programs)
*/
+/*
+ * This is also useful for kernel threads that want to temporarily
+ * (or permanently) block certain signals.
+ *
+ * NOTE! Unlike the user-mode sys_sigprocmask(), the kernel
+ * interface happily blocks "unblockable" signals like SIGKILL
+ * and friends.
+ */
+int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
+{
+ int error;
+ sigset_t old_block;
+
+ spin_lock_irq(¤t->sighand->siglock);
+ old_block = current->blocked;
+ error = 0;
+ switch (how) {
+ case SIG_BLOCK:
+ sigorsets(¤t->blocked, ¤t->blocked, set);
+ break;
+ case SIG_UNBLOCK:
+ signandsets(¤t->blocked, ¤t->blocked, set);
+ break;
+ case SIG_SETMASK:
+ current->blocked = *set;
+ default:
+ error = -EINVAL;
+ }
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+ if (oldset)
+ *oldset = old_block;
+ return error;
+}
+
asmlinkage long
sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize)
{
goto out;
sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
- spin_lock_irq(¤t->sighand->siglock);
- old_set = current->blocked;
-
- error = 0;
- switch (how) {
- default:
- error = -EINVAL;
- break;
- case SIG_BLOCK:
- sigorsets(&new_set, &old_set, &new_set);
- break;
- case SIG_UNBLOCK:
- signandsets(&new_set, &old_set, &new_set);
- break;
- case SIG_SETMASK:
- break;
- }
-
- current->blocked = new_set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ error = sigprocmask(how, &new_set, &old_set);
if (error)
goto out;
if (oset)