aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa/kernel/signal.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 21:11:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 21:11:45 -0400
commitf9369910a6225b8d4892c3f20ae740a711cd5ace (patch)
tree8650ff79d7607bceb35509c028400ecf1c317de0 /arch/xtensa/kernel/signal.c
parent05f144a0d5c2207a0349348127f996e104ad7404 (diff)
parent415d04d08fec74b226c92c1fb54ad117c9c6bac4 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull first series of signal handling cleanups from Al Viro: "This is just the first part of the queue (about a half of it); assorted fixes all over the place in signal handling. This one ends with all sigsuspend() implementations switched to generic one (->saved_sigmask-based). With this, a bunch of assorted old buglets are fixed and most of the missing bits of NOTIFY_RESUME hookup are in place. Two more fixes sit in arm and um trees respectively, and there's a couple of broken ones that need obvious fixes - parisc and avr32 check TIF_NOTIFY_RESUME only on one of two codepaths; fixes for that will happen in the next series" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (55 commits) unicore32: if there's no handler we need to restore sigmask, syscall or no syscall xtensa: add handling of TIF_NOTIFY_RESUME microblaze: drop 'oldset' argument of do_notify_resume() microblaze: handle TIF_NOTIFY_RESUME score: add handling of NOTIFY_RESUME to do_notify_resume() m68k: add TIF_NOTIFY_RESUME and handle it. sparc: kill ancient comment in sparc_sigaction() h8300: missing checks of __get_user()/__put_user() return values frv: missing checks of __get_user()/__put_user() return values cris: missing checks of __get_user()/__put_user() return values powerpc: missing checks of __get_user()/__put_user() return values sh: missing checks of __get_user()/__put_user() return values sparc: missing checks of __get_user()/__put_user() return values avr32: struct old_sigaction is never used m32r: struct old_sigaction is never used xtensa: xtensa_sigaction doesn't exist alpha: tidy signal delivery up score: don't open-code force_sigsegv() cris: don't open-code force_sigsegv() blackfin: don't open-code force_sigsegv() ...
Diffstat (limited to 'arch/xtensa/kernel/signal.c')
-rw-r--r--arch/xtensa/kernel/signal.c73
1 files changed, 32 insertions, 41 deletions
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index d78869a00b11..c5e4ec0598d2 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -20,6 +20,7 @@
20#include <linux/ptrace.h> 20#include <linux/ptrace.h>
21#include <linux/personality.h> 21#include <linux/personality.h>
22#include <linux/freezer.h> 22#include <linux/freezer.h>
23#include <linux/tracehook.h>
23 24
24#include <asm/ucontext.h> 25#include <asm/ucontext.h>
25#include <asm/uaccess.h> 26#include <asm/uaccess.h>
@@ -31,8 +32,6 @@
31 32
32#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 33#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
33 34
34asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
35
36extern struct task_struct *coproc_owners[]; 35extern struct task_struct *coproc_owners[];
37 36
38struct rt_sigframe 37struct rt_sigframe
@@ -248,6 +247,9 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3,
248 sigset_t set; 247 sigset_t set;
249 int ret; 248 int ret;
250 249
250 /* Always make any pending restarted system calls return -EINTR */
251 current_thread_info()->restart_block.fn = do_no_restart_syscall;
252
251 if (regs->depc > 64) 253 if (regs->depc > 64)
252 panic("rt_sigreturn in double exception!\n"); 254 panic("rt_sigreturn in double exception!\n");
253 255
@@ -426,37 +428,6 @@ give_sigsegv:
426 return -EFAULT; 428 return -EFAULT;
427} 429}
428 430
429/*
430 * Atomically swap in the new signal mask, and wait for a signal.
431 */
432
433asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset,
434 size_t sigsetsize,
435 long a2, long a3, long a4, long a5,
436 struct pt_regs *regs)
437{
438 sigset_t saveset, newset;
439
440 /* XXX: Don't preclude handling different sized sigset_t's. */
441 if (sigsetsize != sizeof(sigset_t))
442 return -EINVAL;
443
444 if (copy_from_user(&newset, unewset, sizeof(newset)))
445 return -EFAULT;
446
447 sigdelsetmask(&newset, ~_BLOCKABLE);
448 saveset = current->blocked;
449 set_current_blocked(&newset);
450
451 regs->areg[2] = -EINTR;
452 while (1) {
453 current->state = TASK_INTERRUPTIBLE;
454 schedule();
455 if (do_signal(regs, &saveset))
456 return -EINTR;
457 }
458}
459
460asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, 431asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
461 stack_t __user *uoss, 432 stack_t __user *uoss,
462 long a2, long a3, long a4, long a5, 433 long a2, long a3, long a4, long a5,
@@ -476,19 +447,19 @@ asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
476 * the kernel can handle, and then we build all the user-level signal handling 447 * the kernel can handle, and then we build all the user-level signal handling
477 * stack-frames in one go after that. 448 * stack-frames in one go after that.
478 */ 449 */
479int do_signal(struct pt_regs *regs, sigset_t *oldset) 450static void do_signal(struct pt_regs *regs)
480{ 451{
481 siginfo_t info; 452 siginfo_t info;
482 int signr; 453 int signr;
483 struct k_sigaction ka; 454 struct k_sigaction ka;
484 455 sigset_t oldset;
485 if (!user_mode(regs))
486 return 0;
487 456
488 if (try_to_freeze()) 457 if (try_to_freeze())
489 goto no_signal; 458 goto no_signal;
490 459
491 if (!oldset) 460 if (test_thread_flag(TIF_RESTORE_SIGMASK))
461 oldset = &current->saved_sigmask;
462 else
492 oldset = &current->blocked; 463 oldset = &current->blocked;
493 464
494 task_pt_regs(current)->icountlevel = 0; 465 task_pt_regs(current)->icountlevel = 0;
@@ -532,13 +503,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
532 /* Set up the stack frame */ 503 /* Set up the stack frame */
533 ret = setup_frame(signr, &ka, &info, oldset, regs); 504 ret = setup_frame(signr, &ka, &info, oldset, regs);
534 if (ret) 505 if (ret)
535 return ret; 506 return;
536 507
508 clear_thread_flag(TIF_RESTORE_SIGMASK);
537 block_sigmask(&ka, signr); 509 block_sigmask(&ka, signr);
538 if (current->ptrace & PT_SINGLESTEP) 510 if (current->ptrace & PT_SINGLESTEP)
539 task_pt_regs(current)->icountlevel = 1; 511 task_pt_regs(current)->icountlevel = 1;
540 512
541 return 1; 513 return;
542 } 514 }
543 515
544no_signal: 516no_signal:
@@ -558,8 +530,27 @@ no_signal:
558 break; 530 break;
559 } 531 }
560 } 532 }
533
534 /* If there's no signal to deliver, we just restore the saved mask. */
535 if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
536 set_current_blocked(&current->saved_sigmask);
537
561 if (current->ptrace & PT_SINGLESTEP) 538 if (current->ptrace & PT_SINGLESTEP)
562 task_pt_regs(current)->icountlevel = 1; 539 task_pt_regs(current)->icountlevel = 1;
563 return 0; 540 return;
564} 541}
565 542
543void do_notify_resume(struct pt_regs *regs)
544{
545 if (!user_mode(regs))
546 return;
547
548 if (test_thread_flag(TIF_SIGPENDING))
549 do_signal(regs);
550
551 if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
552 tracehook_notify_resume(regs);
553 if (current->replacement_session_keyring)
554 key_replace_session_keyring();
555 }
556}