]> git.hungrycats.org Git - linux/commitdiff
Make sigprocmask() available to kernel threads too, since a lot of
authorLinus Torvalds <torvalds@home.transmeta.com>
Sun, 9 Feb 2003 10:17:26 +0000 (02:17 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Sun, 9 Feb 2003 10:17:26 +0000 (02:17 -0800)
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.

fs/autofs/waitq.c
fs/nfsd/nfssvc.c
include/linux/signal.h
kernel/signal.c

index 6c82dc144b3301782105504fd15795481c5fc4aa..d08b648ccae56b4179aa886d9925c84a3eb7c9c0 100644 (file)
@@ -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(&current->sighand->siglock, irqflags);
-               oldset = current->blocked;
-               siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
-               recalc_sigpending();
-               spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
+               siginitsetinv(&sigmask, SHUTDOWN_SIGS);
+               sigprocmask(SIG_BLOCK, &sigmask, &sigmask);
 
                interruptible_sleep_on(&wq->queue);
 
-               spin_lock_irqsave(&current->sighand->siglock, irqflags);
-               current->blocked = oldset;
-               recalc_sigpending();
-               spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
+               sigprocmask(SIG_SETMASK, &sigmask, NULL);
        } else {
                DPRINTK(("autofs_wait: skipped sleeping\n"));
        }
index 3919e77036e3abab70681f8f08c95fcce1d490e4..369c2ce897f4320b43cbb13c9be79ddd35226664 100644 (file)
@@ -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(&current->sighand->siglock);
-               siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
-               recalc_sigpending();
-               spin_unlock_irq(&current->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(&current->sighand->siglock);
-               siginitsetinv(&current->blocked, ALLOWED_SIGS);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
+               sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
 
                svc_process(serv, rqstp);
 
index 53d9e432455709dc2794e5353ccfc23549226ff1..dd2e25e2129f109394dee47256da4926a3922b1d 100644 (file)
@@ -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;
index 9dc47e8a804aeaddc89fdbfb3592a77a38df0f71..b1a35f819baa5390e8bb3e9e99e3163ca442b144 100644 (file)
@@ -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(&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
 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(&current->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(&current->sighand->siglock);
+               error = sigprocmask(how, &new_set, &old_set);
                if (error)
                        goto out;
                if (oset)