Commit 73ef4aeb authored by Oleg Nesterov's avatar Oleg Nesterov

signal: sigprocmask: narrow the scope of ->siglock

No functional changes, preparation to simplify the review of the next change.

1. We can read current->block lockless, nobody else can ever change this mask.

2. Calculate the resulting sigset_t outside of ->siglock into the temporary
   variable, then take ->siglock and change ->blocked.

Also, kill the stale comment about BKL.
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Reviewed-by: default avatarMatt Fleming <matt.fleming@linux.intel.com>
Acked-by: default avatarTejun Heo <tj@kernel.org>
parent fec9993d
...@@ -2299,12 +2299,6 @@ long do_no_restart_syscall(struct restart_block *param) ...@@ -2299,12 +2299,6 @@ long do_no_restart_syscall(struct restart_block *param)
return -EINTR; return -EINTR;
} }
/*
* We don't need to get the kernel lock - this is all local to this
* particular thread.. (and that's good, because this is _heavily_
* used by various programs)
*/
/* /*
* This is also useful for kernel threads that want to temporarily * This is also useful for kernel threads that want to temporarily
* (or permanently) block certain signals. * (or permanently) block certain signals.
...@@ -2315,30 +2309,33 @@ long do_no_restart_syscall(struct restart_block *param) ...@@ -2315,30 +2309,33 @@ long do_no_restart_syscall(struct restart_block *param)
*/ */
int sigprocmask(int how, sigset_t *set, sigset_t *oldset) int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
{ {
int error; struct task_struct *tsk = current;
sigset_t newset;
spin_lock_irq(&current->sighand->siglock); /* Lockless, only current can change ->blocked, never from irq */
if (oldset) if (oldset)
*oldset = current->blocked; *oldset = tsk->blocked;
error = 0;
switch (how) { switch (how) {
case SIG_BLOCK: case SIG_BLOCK:
sigorsets(&current->blocked, &current->blocked, set); sigorsets(&newset, &tsk->blocked, set);
break; break;
case SIG_UNBLOCK: case SIG_UNBLOCK:
signandsets(&current->blocked, &current->blocked, set); signandsets(&newset, &tsk->blocked, set);
break; break;
case SIG_SETMASK: case SIG_SETMASK:
current->blocked = *set; newset = *set;
break; break;
default: default:
error = -EINVAL; return -EINVAL;
} }
spin_lock_irq(&tsk->sighand->siglock);
tsk->blocked = newset;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&tsk->sighand->siglock);
return error; return 0;
} }
/** /**
......
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