Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal

Pull third pile of signal handling patches from Al Viro:
 "This time it's mostly helpers and conversions to them; there's a lot
  of stuff remaining in the tree, but that'll either go in -rc2
  (isolated bug fixes, ideally via arch maintainers' trees) or will sit
  there until the next cycle."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal:
  x86: get rid of calling do_notify_resume() when returning to kernel mode
  blackfin: check __get_user() return value
  whack-a-mole with TIF_FREEZE
  FRV: Optimise the system call exit path in entry.S [ver #2]
  FRV: Shrink TIF_WORK_MASK [ver #2]
  FRV: Prevent syscall exit tracing and notify_resume at end of kernel exceptions
  new helper: signal_delivered()
  powerpc: get rid of restore_sigmask()
  most of set_current_blocked() callers want SIGKILL/SIGSTOP removed from set
  set_restore_sigmask() is never called without SIGPENDING (and never should be)
  TIF_RESTORE_SIGMASK can be set only when TIF_SIGPENDING is set
  don't call try_to_freeze() from do_signal()
  pull clearing RESTORE_SIGMASK into block_sigmask()
  sh64: failure to build sigframe != signal without handler
  openrisc: tracehook_signal_handler() is supposed to be called on success
  new helper: sigmask_to_save()
  new helper: restore_saved_sigmask()
  new helpers: {clear,test,test_and_clear}_restore_sigmask()
  HAVE_RESTORE_SIGMASK is defined on all architectures now
This commit is contained in:
Linus Torvalds 2012-06-01 11:53:44 -07:00
commit 86c47b70f6
68 changed files with 482 additions and 1091 deletions

View file

@ -169,7 +169,7 @@ static inline void set_restore_sigmask(void)
{
struct thread_info *ti = current_thread_info();
ti->status |= TS_RESTORE_SIGMASK;
set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags));
}
#define TI_FLAG_FAULT_CODE_SHIFT 24
@ -189,6 +189,23 @@ static inline unsigned int get_thread_fault_code(void)
struct thread_info *ti = current_thread_info();
return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT;
}
static inline void clear_restore_sigmask(void)
{
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
}
static inline bool test_restore_sigmask(void)
{
return current_thread_info()->status & TS_RESTORE_SIGMASK;
}
static inline bool test_and_clear_restore_sigmask(void)
{
struct thread_info *ti = current_thread_info();
if (!(ti->status & TS_RESTORE_SIGMASK))
return false;
ti->status &= ~TS_RESTORE_SIGMASK;
return true;
}
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */

View file

@ -32,8 +32,6 @@
#include <asm/syscalls.h>
#include <asm/fpu.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
struct fdpic_func_descriptor {
unsigned long text;
unsigned long GOT;
@ -226,7 +224,6 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
sizeof(frame->extramask))))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, &r0))
@ -256,7 +253,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
@ -522,10 +518,11 @@ handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs,
/*
* OK, we're invoking a handler
*/
static int
static void
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0)
struct pt_regs *regs, unsigned int save_r0)
{
sigset_t *oldset = sigmask_to_save();
int ret;
/* Set up the stack frame */
@ -534,10 +531,10 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
else
ret = setup_frame(sig, ka, oldset, regs);
if (ret == 0)
block_sigmask(ka, sig);
return ret;
if (ret)
return;
signal_delivered(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP));
}
/*
@ -554,7 +551,6 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
siginfo_t info;
int signr;
struct k_sigaction ka;
sigset_t *oldset;
/*
* We want the common case to go fast, which
@ -565,30 +561,12 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
if (!user_mode(regs))
return;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
handle_syscall_restart(save_r0, regs, &ka.sa);
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &ka, &info, oldset,
regs, save_r0) == 0) {
/*
* A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
* clear the TS_RESTORE_SIGMASK flag
*/
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
}
handle_signal(signr, &ka, &info, regs, save_r0);
return;
}
@ -610,10 +588,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
* If there's no signal to deliver, we just put the saved sigmask
* back.
*/
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
restore_saved_sigmask();
}
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,

View file

@ -41,11 +41,9 @@
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
static int
static void
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs);
struct pt_regs * regs);
static inline void
handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
@ -88,7 +86,6 @@ static void do_signal(struct pt_regs *regs)
siginfo_t info;
int signr;
struct k_sigaction ka;
sigset_t *oldset;
/*
* We want the common case to go fast, which
@ -99,28 +96,13 @@ static void do_signal(struct pt_regs *regs)
if (!user_mode(regs))
return;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, 0);
if (signr > 0) {
handle_syscall_restart(regs, &ka.sa);
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
/*
* If a signal was successfully delivered, the
* saved sigmask is in its frame, and we can
* clear the TS_RESTORE_SIGMASK flag.
*/
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
return;
}
handle_signal(signr, &info, &ka, regs);
return;
}
/* Did we come from a system call? */
@ -143,12 +125,7 @@ static void do_signal(struct pt_regs *regs)
}
/* No signal to deliver -- put the saved sigmask back */
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
return;
restore_saved_sigmask();
}
/*
@ -351,7 +328,6 @@ asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
sizeof(frame->extramask))))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, &ret))
@ -384,7 +360,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
@ -659,10 +634,11 @@ give_sigsegv:
/*
* OK, we're invoking a handler
*/
static int
static void
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
struct pt_regs * regs)
{
sigset_t *oldset = sigmask_to_save();
int ret;
/* Set up the stack frame */
@ -671,10 +647,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
else
ret = setup_frame(sig, ka, oldset, regs);
if (ret == 0)
block_sigmask(ka, sig);
if (ret)
return;
return ret;
signal_delivered(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP));
}
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)