diff options
| -rw-r--r-- | fs/autofs/waitq.c | 15 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 14 | ||||
| -rw-r--r-- | include/linux/signal.h | 1 | ||||
| -rw-r--r-- | kernel/signal.c | 58 |
4 files changed, 48 insertions, 40 deletions
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c index 6c82dc144b33..d08b648ccae5 100644 --- a/fs/autofs/waitq.c +++ b/fs/autofs/waitq.c @@ -158,21 +158,14 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr *name) 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")); } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 3919e77036e3..369c2ce897f4 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -168,6 +168,7 @@ nfsd(struct svc_rqst *rqstp) 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; @@ -176,6 +177,9 @@ nfsd(struct svc_rqst *rqstp) 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 */ @@ -189,10 +193,7 @@ nfsd(struct svc_rqst *rqstp) */ 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 @@ -210,10 +211,7 @@ nfsd(struct svc_rqst *rqstp) 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); diff --git a/include/linux/signal.h b/include/linux/signal.h index 53d9e4324557..dd2e25e2129f 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -204,6 +204,7 @@ static inline void init_sigpending(struct sigpending *sig) } 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; diff --git a/kernel/signal.c b/kernel/signal.c index 9dc47e8a804a..b1a35f819baa 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1559,6 +1559,7 @@ EXPORT_SYMBOL(kill_sl_info); 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); @@ -1585,6 +1586,41 @@ long do_no_restart_syscall(struct restart_block *param) * 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) { @@ -1601,27 +1637,7 @@ 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) |
