diff options
Diffstat (limited to 'arch/frv/kernel/signal.c')
-rw-r--r-- | arch/frv/kernel/signal.c | 111 |
1 files changed, 90 insertions, 21 deletions
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 535810a3217..bab01298b58 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/ptrace.h> | 20 | #include <linux/ptrace.h> |
21 | #include <linux/unistd.h> | 21 | #include <linux/unistd.h> |
22 | #include <linux/personality.h> | 22 | #include <linux/personality.h> |
23 | #include <linux/freezer.h> | ||
23 | #include <linux/tracehook.h> | 24 | #include <linux/tracehook.h> |
24 | #include <asm/ucontext.h> | 25 | #include <asm/ucontext.h> |
25 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
@@ -27,6 +28,8 @@ | |||
27 | 28 | ||
28 | #define DEBUG_SIG 0 | 29 | #define DEBUG_SIG 0 |
29 | 30 | ||
31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
32 | |||
30 | struct fdpic_func_descriptor { | 33 | struct fdpic_func_descriptor { |
31 | unsigned long text; | 34 | unsigned long text; |
32 | unsigned long GOT; | 35 | unsigned long GOT; |
@@ -37,9 +40,17 @@ struct fdpic_func_descriptor { | |||
37 | */ | 40 | */ |
38 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 41 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) |
39 | { | 42 | { |
40 | sigset_t blocked; | 43 | mask &= _BLOCKABLE; |
41 | siginitset(&blocked, mask); | 44 | spin_lock_irq(¤t->sighand->siglock); |
42 | return sigsuspend(&blocked); | 45 | current->saved_sigmask = current->blocked; |
46 | siginitset(¤t->blocked, mask); | ||
47 | recalc_sigpending(); | ||
48 | spin_unlock_irq(¤t->sighand->siglock); | ||
49 | |||
50 | current->state = TASK_INTERRUPTIBLE; | ||
51 | schedule(); | ||
52 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
53 | return -ERESTARTNOHAND; | ||
43 | } | 54 | } |
44 | 55 | ||
45 | asmlinkage int sys_sigaction(int sig, | 56 | asmlinkage int sys_sigaction(int sig, |
@@ -53,10 +64,10 @@ asmlinkage int sys_sigaction(int sig, | |||
53 | old_sigset_t mask; | 64 | old_sigset_t mask; |
54 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 65 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
55 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 66 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
56 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || | 67 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
57 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
58 | __get_user(mask, &act->sa_mask)) | ||
59 | return -EFAULT; | 68 | return -EFAULT; |
69 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
70 | __get_user(mask, &act->sa_mask); | ||
60 | siginitset(&new_ka.sa.sa_mask, mask); | 71 | siginitset(&new_ka.sa.sa_mask, mask); |
61 | } | 72 | } |
62 | 73 | ||
@@ -65,10 +76,10 @@ asmlinkage int sys_sigaction(int sig, | |||
65 | if (!ret && oact) { | 76 | if (!ret && oact) { |
66 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 77 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
67 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 78 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
68 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || | 79 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
69 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
70 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
71 | return -EFAULT; | 80 | return -EFAULT; |
81 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
82 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
72 | } | 83 | } |
73 | 84 | ||
74 | return ret; | 85 | return ret; |
@@ -146,7 +157,11 @@ asmlinkage int sys_sigreturn(void) | |||
146 | __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) | 157 | __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) |
147 | goto badframe; | 158 | goto badframe; |
148 | 159 | ||
149 | set_current_blocked(&set); | 160 | sigdelsetmask(&set, ~_BLOCKABLE); |
161 | spin_lock_irq(¤t->sighand->siglock); | ||
162 | current->blocked = set; | ||
163 | recalc_sigpending(); | ||
164 | spin_unlock_irq(¤t->sighand->siglock); | ||
150 | 165 | ||
151 | if (restore_sigcontext(&frame->sc, &gr8)) | 166 | if (restore_sigcontext(&frame->sc, &gr8)) |
152 | goto badframe; | 167 | goto badframe; |
@@ -168,7 +183,11 @@ asmlinkage int sys_rt_sigreturn(void) | |||
168 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 183 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
169 | goto badframe; | 184 | goto badframe; |
170 | 185 | ||
171 | set_current_blocked(&set); | 186 | sigdelsetmask(&set, ~_BLOCKABLE); |
187 | spin_lock_irq(¤t->sighand->siglock); | ||
188 | current->blocked = set; | ||
189 | recalc_sigpending(); | ||
190 | spin_unlock_irq(¤t->sighand->siglock); | ||
172 | 191 | ||
173 | if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) | 192 | if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) |
174 | goto badframe; | 193 | goto badframe; |
@@ -297,6 +316,10 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) | |||
297 | __frame->lr = (unsigned long) &frame->retcode; | 316 | __frame->lr = (unsigned long) &frame->retcode; |
298 | __frame->gr8 = sig; | 317 | __frame->gr8 = sig; |
299 | 318 | ||
319 | /* the tracer may want to single-step inside the handler */ | ||
320 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
321 | ptrace_notify(SIGTRAP); | ||
322 | |||
300 | #if DEBUG_SIG | 323 | #if DEBUG_SIG |
301 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | 324 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", |
302 | sig, current->comm, current->pid, frame, __frame->pc, | 325 | sig, current->comm, current->pid, frame, __frame->pc, |
@@ -395,6 +418,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
395 | __frame->gr8 = sig; | 418 | __frame->gr8 = sig; |
396 | __frame->gr9 = (unsigned long) &frame->info; | 419 | __frame->gr9 = (unsigned long) &frame->info; |
397 | 420 | ||
421 | /* the tracer may want to single-step inside the handler */ | ||
422 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
423 | ptrace_notify(SIGTRAP); | ||
424 | |||
398 | #if DEBUG_SIG | 425 | #if DEBUG_SIG |
399 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | 426 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", |
400 | sig, current->comm, current->pid, frame, __frame->pc, | 427 | sig, current->comm, current->pid, frame, __frame->pc, |
@@ -413,10 +440,9 @@ give_sigsegv: | |||
413 | /* | 440 | /* |
414 | * OK, we're invoking a handler | 441 | * OK, we're invoking a handler |
415 | */ | 442 | */ |
416 | static void handle_signal(unsigned long sig, siginfo_t *info, | 443 | static int handle_signal(unsigned long sig, siginfo_t *info, |
417 | struct k_sigaction *ka) | 444 | struct k_sigaction *ka, sigset_t *oldset) |
418 | { | 445 | { |
419 | sigset_t *oldset = sigmask_to_save(); | ||
420 | int ret; | 446 | int ret; |
421 | 447 | ||
422 | /* Are we from a system call? */ | 448 | /* Are we from a system call? */ |
@@ -448,11 +474,18 @@ static void handle_signal(unsigned long sig, siginfo_t *info, | |||
448 | else | 474 | else |
449 | ret = setup_frame(sig, ka, oldset); | 475 | ret = setup_frame(sig, ka, oldset); |
450 | 476 | ||
451 | if (ret) | 477 | if (ret == 0) { |
452 | return; | 478 | spin_lock_irq(¤t->sighand->siglock); |
479 | sigorsets(¤t->blocked, ¤t->blocked, | ||
480 | &ka->sa.sa_mask); | ||
481 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
482 | sigaddset(¤t->blocked, sig); | ||
483 | recalc_sigpending(); | ||
484 | spin_unlock_irq(¤t->sighand->siglock); | ||
485 | } | ||
486 | |||
487 | return ret; | ||
453 | 488 | ||
454 | signal_delivered(sig, info, ka, __frame, | ||
455 | test_thread_flag(TIF_SINGLESTEP)); | ||
456 | } /* end handle_signal() */ | 489 | } /* end handle_signal() */ |
457 | 490 | ||
458 | /*****************************************************************************/ | 491 | /*****************************************************************************/ |
@@ -465,14 +498,44 @@ static void do_signal(void) | |||
465 | { | 498 | { |
466 | struct k_sigaction ka; | 499 | struct k_sigaction ka; |
467 | siginfo_t info; | 500 | siginfo_t info; |
501 | sigset_t *oldset; | ||
468 | int signr; | 502 | int signr; |
469 | 503 | ||
504 | /* | ||
505 | * We want the common case to go fast, which | ||
506 | * is why we may in certain cases get here from | ||
507 | * kernel mode. Just return without doing anything | ||
508 | * if so. | ||
509 | */ | ||
510 | if (!user_mode(__frame)) | ||
511 | return; | ||
512 | |||
513 | if (try_to_freeze()) | ||
514 | goto no_signal; | ||
515 | |||
516 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
517 | oldset = ¤t->saved_sigmask; | ||
518 | else | ||
519 | oldset = ¤t->blocked; | ||
520 | |||
470 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); | 521 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); |
471 | if (signr > 0) { | 522 | if (signr > 0) { |
472 | handle_signal(signr, &info, &ka); | 523 | if (handle_signal(signr, &info, &ka, oldset) == 0) { |
524 | /* a signal was successfully delivered; the saved | ||
525 | * sigmask will have been stored in the signal frame, | ||
526 | * and will be restored by sigreturn, so we can simply | ||
527 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
528 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
529 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
530 | |||
531 | tracehook_signal_handler(signr, &info, &ka, __frame, | ||
532 | test_thread_flag(TIF_SINGLESTEP)); | ||
533 | } | ||
534 | |||
473 | return; | 535 | return; |
474 | } | 536 | } |
475 | 537 | ||
538 | no_signal: | ||
476 | /* Did we come from a system call? */ | 539 | /* Did we come from a system call? */ |
477 | if (__frame->syscallno != -1) { | 540 | if (__frame->syscallno != -1) { |
478 | /* Restart the system call - no handlers present */ | 541 | /* Restart the system call - no handlers present */ |
@@ -494,7 +557,11 @@ static void do_signal(void) | |||
494 | 557 | ||
495 | /* if there's no signal to deliver, we just put the saved sigmask | 558 | /* if there's no signal to deliver, we just put the saved sigmask |
496 | * back */ | 559 | * back */ |
497 | restore_saved_sigmask(); | 560 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
561 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
562 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
563 | } | ||
564 | |||
498 | } /* end do_signal() */ | 565 | } /* end do_signal() */ |
499 | 566 | ||
500 | /*****************************************************************************/ | 567 | /*****************************************************************************/ |
@@ -509,13 +576,15 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) | |||
509 | clear_thread_flag(TIF_SINGLESTEP); | 576 | clear_thread_flag(TIF_SINGLESTEP); |
510 | 577 | ||
511 | /* deal with pending signal delivery */ | 578 | /* deal with pending signal delivery */ |
512 | if (thread_info_flags & _TIF_SIGPENDING) | 579 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
513 | do_signal(); | 580 | do_signal(); |
514 | 581 | ||
515 | /* deal with notification on about to resume userspace execution */ | 582 | /* deal with notification on about to resume userspace execution */ |
516 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 583 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
517 | clear_thread_flag(TIF_NOTIFY_RESUME); | 584 | clear_thread_flag(TIF_NOTIFY_RESUME); |
518 | tracehook_notify_resume(__frame); | 585 | tracehook_notify_resume(__frame); |
586 | if (current->replacement_session_keyring) | ||
587 | key_replace_session_keyring(); | ||
519 | } | 588 | } |
520 | 589 | ||
521 | } /* end do_notify_resume() */ | 590 | } /* end do_notify_resume() */ |