Commit f3cee469 authored by Linus Torvalds's avatar Linus Torvalds

Make sigprocmask() available to kernel threads too, since a lot of

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. 
parent 01f5c53c
...@@ -158,21 +158,14 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr *name) ...@@ -158,21 +158,14 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr *name)
if ( wq->name ) { if ( wq->name ) {
/* Block all but "shutdown" signals while waiting */ /* Block all but "shutdown" signals while waiting */
sigset_t oldset; sigset_t sigmask;
unsigned long irqflags;
spin_lock_irqsave(&current->sighand->siglock, irqflags); siginitsetinv(&sigmask, SHUTDOWN_SIGS);
oldset = current->blocked; sigprocmask(SIG_BLOCK, &sigmask, &sigmask);
siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
interruptible_sleep_on(&wq->queue); interruptible_sleep_on(&wq->queue);
spin_lock_irqsave(&current->sighand->siglock, irqflags); sigprocmask(SIG_SETMASK, &sigmask, NULL);
current->blocked = oldset;
recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
} else { } else {
DPRINTK(("autofs_wait: skipped sleeping\n")); DPRINTK(("autofs_wait: skipped sleeping\n"));
} }
......
...@@ -168,6 +168,7 @@ nfsd(struct svc_rqst *rqstp) ...@@ -168,6 +168,7 @@ nfsd(struct svc_rqst *rqstp)
struct svc_serv *serv = rqstp->rq_server; struct svc_serv *serv = rqstp->rq_server;
int err; int err;
struct nfsd_list me; struct nfsd_list me;
sigset_t shutdown_mask, allowed_mask;
/* Lock module and set up kernel thread */ /* Lock module and set up kernel thread */
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -176,6 +177,9 @@ nfsd(struct svc_rqst *rqstp) ...@@ -176,6 +177,9 @@ nfsd(struct svc_rqst *rqstp)
sprintf(current->comm, "nfsd"); sprintf(current->comm, "nfsd");
current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS);
siginitsetinv(&allowed_mask, ALLOWED_SIGS);
nfsdstats.th_cnt++; nfsdstats.th_cnt++;
lockd_up(); /* start lockd */ lockd_up(); /* start lockd */
...@@ -189,10 +193,7 @@ nfsd(struct svc_rqst *rqstp) ...@@ -189,10 +193,7 @@ nfsd(struct svc_rqst *rqstp)
*/ */
for (;;) { for (;;) {
/* Block all but the shutdown signals */ /* Block all but the shutdown signals */
spin_lock_irq(&current->sighand->siglock); sigprocmask(SIG_SETMASK, &shutdown_mask, NULL);
siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
/* /*
* Find a socket with data available and call its * Find a socket with data available and call its
...@@ -210,10 +211,7 @@ nfsd(struct svc_rqst *rqstp) ...@@ -210,10 +211,7 @@ nfsd(struct svc_rqst *rqstp)
exp_readlock(); exp_readlock();
/* Process request with signals blocked. */ /* Process request with signals blocked. */
spin_lock_irq(&current->sighand->siglock); sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
siginitsetinv(&current->blocked, ALLOWED_SIGS);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
svc_process(serv, rqstp); svc_process(serv, rqstp);
......
...@@ -204,6 +204,7 @@ static inline void init_sigpending(struct sigpending *sig) ...@@ -204,6 +204,7 @@ static inline void init_sigpending(struct sigpending *sig)
} }
extern long do_sigpending(void *, unsigned long); extern long do_sigpending(void *, unsigned long);
extern int sigprocmask(int, sigset_t *, sigset_t *);
#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
struct pt_regs; struct pt_regs;
......
...@@ -1559,6 +1559,7 @@ EXPORT_SYMBOL(kill_sl_info); ...@@ -1559,6 +1559,7 @@ EXPORT_SYMBOL(kill_sl_info);
EXPORT_SYMBOL(notify_parent); EXPORT_SYMBOL(notify_parent);
EXPORT_SYMBOL(send_sig); EXPORT_SYMBOL(send_sig);
EXPORT_SYMBOL(send_sig_info); EXPORT_SYMBOL(send_sig_info);
EXPORT_SYMBOL(sigprocmask);
EXPORT_SYMBOL(block_all_signals); EXPORT_SYMBOL(block_all_signals);
EXPORT_SYMBOL(unblock_all_signals); EXPORT_SYMBOL(unblock_all_signals);
...@@ -1585,6 +1586,41 @@ long do_no_restart_syscall(struct restart_block *param) ...@@ -1585,6 +1586,41 @@ long do_no_restart_syscall(struct restart_block *param)
* used by various programs) * 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(&current->sighand->siglock);
old_block = current->blocked;
error = 0;
switch (how) {
case SIG_BLOCK:
sigorsets(&current->blocked, &current->blocked, set);
break;
case SIG_UNBLOCK:
signandsets(&current->blocked, &current->blocked, set);
break;
case SIG_SETMASK:
current->blocked = *set;
default:
error = -EINVAL;
}
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (oldset)
*oldset = old_block;
return error;
}
asmlinkage long asmlinkage long
sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize) 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) ...@@ -1601,27 +1637,7 @@ sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize)
goto out; goto out;
sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
spin_lock_irq(&current->sighand->siglock); error = sigprocmask(how, &new_set, &old_set);
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(&current->sighand->siglock);
if (error) if (error)
goto out; goto out;
if (oset) if (oset)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment