diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-04-27 15:18:10 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2011-04-28 07:01:38 -0400 |
commit | bb7efee2ca63b08795ffb3cda96fc89d2e641b79 (patch) | |
tree | 05e05d78f815d9fb8f8963860d2287189a17d7b1 /kernel/signal.c | |
parent | e9bd3f0faa90084f188830d77723bafe422e486b (diff) |
signal: cleanup sys_rt_sigprocmask()
sys_rt_sigprocmask() looks unnecessarily complicated, simplify it.
We can just read current->blocked lockless unconditionally before
anything else and then copy-to-user it if needed. At worst we
copy 4 words on mips.
We could copy-to-user the old mask first and simplify the code even
more, but the patch tries to keep the current behaviour: we change
current->block even if copy_to_user(oset) fails.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Matt Fleming <matt.fleming@linux.intel.com>
Acked-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 38 |
1 files changed, 16 insertions, 22 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 8aa3a2e226af..bb9200070ea0 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -2364,40 +2364,34 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) | |||
2364 | * @oset: previous value of signal mask if non-null | 2364 | * @oset: previous value of signal mask if non-null |
2365 | * @sigsetsize: size of sigset_t type | 2365 | * @sigsetsize: size of sigset_t type |
2366 | */ | 2366 | */ |
2367 | SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, set, | 2367 | SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset, |
2368 | sigset_t __user *, oset, size_t, sigsetsize) | 2368 | sigset_t __user *, oset, size_t, sigsetsize) |
2369 | { | 2369 | { |
2370 | int error = -EINVAL; | ||
2371 | sigset_t old_set, new_set; | 2370 | sigset_t old_set, new_set; |
2371 | int error; | ||
2372 | 2372 | ||
2373 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 2373 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
2374 | if (sigsetsize != sizeof(sigset_t)) | 2374 | if (sigsetsize != sizeof(sigset_t)) |
2375 | goto out; | 2375 | return -EINVAL; |
2376 | 2376 | ||
2377 | if (set) { | 2377 | old_set = current->blocked; |
2378 | error = -EFAULT; | 2378 | |
2379 | if (copy_from_user(&new_set, set, sizeof(*set))) | 2379 | if (nset) { |
2380 | goto out; | 2380 | if (copy_from_user(&new_set, nset, sizeof(sigset_t))) |
2381 | return -EFAULT; | ||
2381 | sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); | 2382 | sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); |
2382 | 2383 | ||
2383 | error = sigprocmask(how, &new_set, &old_set); | 2384 | error = sigprocmask(how, &new_set, NULL); |
2384 | if (error) | 2385 | if (error) |
2385 | goto out; | 2386 | return error; |
2386 | if (oset) | 2387 | } |
2387 | goto set_old; | ||
2388 | } else if (oset) { | ||
2389 | spin_lock_irq(¤t->sighand->siglock); | ||
2390 | old_set = current->blocked; | ||
2391 | spin_unlock_irq(¤t->sighand->siglock); | ||
2392 | 2388 | ||
2393 | set_old: | 2389 | if (oset) { |
2394 | error = -EFAULT; | 2390 | if (copy_to_user(oset, &old_set, sizeof(sigset_t))) |
2395 | if (copy_to_user(oset, &old_set, sizeof(*oset))) | 2391 | return -EFAULT; |
2396 | goto out; | ||
2397 | } | 2392 | } |
2398 | error = 0; | 2393 | |
2399 | out: | 2394 | return 0; |
2400 | return error; | ||
2401 | } | 2395 | } |
2402 | 2396 | ||
2403 | long do_sigpending(void __user *set, unsigned long sigsetsize) | 2397 | long do_sigpending(void __user *set, unsigned long sigsetsize) |