Commit 73ef4aeb61b53fce464a7e24ef03a26f98b2f617
1 parent
fec9993db0
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 13 additions and 16 deletions Side-by-side Diff
kernel/signal.c
... | ... | @@ -2300,12 +2300,6 @@ |
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 | 2303 | * This is also useful for kernel threads that want to temporarily |
2310 | 2304 | * (or permanently) block certain signals. |
2311 | 2305 | * |
2312 | 2306 | |
2313 | 2307 | |
2314 | 2308 | |
2315 | 2309 | |
2316 | 2310 | |
2317 | 2311 | |
2318 | 2312 | |
2319 | 2313 | |
2320 | 2314 | |
2321 | 2315 | |
... | ... | @@ -2315,30 +2309,33 @@ |
2315 | 2309 | */ |
2316 | 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 | 2316 | if (oldset) |
2322 | - *oldset = current->blocked; | |
2317 | + *oldset = tsk->blocked; | |
2323 | 2318 | |
2324 | - error = 0; | |
2325 | 2319 | switch (how) { |
2326 | 2320 | case SIG_BLOCK: |
2327 | - sigorsets(¤t->blocked, ¤t->blocked, set); | |
2321 | + sigorsets(&newset, &tsk->blocked, set); | |
2328 | 2322 | break; |
2329 | 2323 | case SIG_UNBLOCK: |
2330 | - signandsets(¤t->blocked, ¤t->blocked, set); | |
2324 | + signandsets(&newset, &tsk->blocked, set); | |
2331 | 2325 | break; |
2332 | 2326 | case SIG_SETMASK: |
2333 | - current->blocked = *set; | |
2327 | + newset = *set; | |
2334 | 2328 | break; |
2335 | 2329 | default: |
2336 | - error = -EINVAL; | |
2330 | + return -EINVAL; | |
2337 | 2331 | } |
2332 | + | |
2333 | + spin_lock_irq(&tsk->sighand->siglock); | |
2334 | + tsk->blocked = newset; | |
2338 | 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 | /** |