diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-04-27 13:54:20 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2011-04-28 07:01:36 -0400 |
commit | 73ef4aeb61b53fce464a7e24ef03a26f98b2f617 (patch) | |
tree | 15acc5d7ded643ccd1da1d502033822a2452497c | |
parent | fec9993db093acfc3999a364e31f8adae41fcb28 (diff) |
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: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Matt Fleming <matt.fleming@linux.intel.com>
Acked-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | kernel/signal.c | 29 |
1 files changed, 13 insertions, 16 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 707736e64e0e..e8308e3238c1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -2300,12 +2300,6 @@ long do_no_restart_syscall(struct restart_block *param) | |||
2300 | } | 2300 | } |
2301 | 2301 | ||
2302 | /* | 2302 | /* |
2303 | * We don't need to get the kernel lock - this is all local to this | ||
2304 | * particular thread.. (and that's good, because this is _heavily_ | ||
2305 | * used by various programs) | ||
2306 | */ | ||
2307 | |||
2308 | /* | ||
2309 | * This is also useful for kernel threads that want to temporarily | 2303 | * This is also useful for kernel threads that want to temporarily |
2310 | * (or permanently) block certain signals. | 2304 | * (or permanently) block certain signals. |
2311 | * | 2305 | * |
@@ -2315,30 +2309,33 @@ long do_no_restart_syscall(struct restart_block *param) | |||
2315 | */ | 2309 | */ |
2316 | int sigprocmask(int how, sigset_t *set, sigset_t *oldset) | 2310 | int sigprocmask(int how, sigset_t *set, sigset_t *oldset) |
2317 | { | 2311 | { |
2318 | int error; | 2312 | struct task_struct *tsk = current; |
2313 | sigset_t newset; | ||
2319 | 2314 | ||
2320 | spin_lock_irq(¤t->sighand->siglock); | 2315 | /* Lockless, only current can change ->blocked, never from irq */ |
2321 | if (oldset) | 2316 | if (oldset) |
2322 | *oldset = current->blocked; | 2317 | *oldset = tsk->blocked; |
2323 | 2318 | ||
2324 | error = 0; | ||
2325 | switch (how) { | 2319 | switch (how) { |
2326 | case SIG_BLOCK: | 2320 | case SIG_BLOCK: |
2327 | sigorsets(¤t->blocked, ¤t->blocked, set); | 2321 | sigorsets(&newset, &tsk->blocked, set); |
2328 | break; | 2322 | break; |
2329 | case SIG_UNBLOCK: | 2323 | case SIG_UNBLOCK: |
2330 | signandsets(¤t->blocked, ¤t->blocked, set); | 2324 | signandsets(&newset, &tsk->blocked, set); |
2331 | break; | 2325 | break; |
2332 | case SIG_SETMASK: | 2326 | case SIG_SETMASK: |
2333 | current->blocked = *set; | 2327 | newset = *set; |
2334 | break; | 2328 | break; |
2335 | default: | 2329 | default: |
2336 | error = -EINVAL; | 2330 | return -EINVAL; |
2337 | } | 2331 | } |
2332 | |||
2333 | spin_lock_irq(&tsk->sighand->siglock); | ||
2334 | tsk->blocked = newset; | ||
2338 | recalc_sigpending(); | 2335 | recalc_sigpending(); |
2339 | spin_unlock_irq(¤t->sighand->siglock); | 2336 | spin_unlock_irq(&tsk->sighand->siglock); |
2340 | 2337 | ||
2341 | return error; | 2338 | return 0; |
2342 | } | 2339 | } |
2343 | 2340 | ||
2344 | /** | 2341 | /** |