Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull third pile of kernel_execve() patches from Al Viro: "The last bits of infrastructure for kernel_thread() et.al., with alpha/arm/x86 use of those. Plus sanitizing the asm glue and do_notify_resume() on alpha, fixing the "disabled irq while running task_work stuff" breakage there. At that point the rest of kernel_thread/kernel_execve/sys_execve work can be done independently for different architectures. The only pending bits that do depend on having all architectures converted are restrictred to fs/* and kernel/* - that'll obviously have to wait for the next cycle. I thought we'd have to wait for all of them done before we start eliminating the longjump-style insanity in kernel_execve(), but it turned out there's a very simple way to do that without flagday-style changes." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: alpha: switch to saner kernel_execve() semantics arm: switch to saner kernel_execve() semantics x86, um: convert to saner kernel_execve() semantics infrastructure for saner ret_from_kernel_thread semantics make sure that kernel_thread() callbacks call do_exit() themselves make sure that we always have a return path from kernel_execve() ppc: eeh_event should just use kthread_run() don't bother with kernel_thread/kernel_execve for launching linuxrc alpha: get rid of switch_stack argument of do_work_pending() alpha: don't bother passing switch_stack separately from regs alpha: take SIGPENDING/NOTIFY_RESUME loop into signal.c alpha: simplify TIF_NEED_RESCHED handling
This commit is contained in:
@@ -311,7 +311,7 @@ entSys:
|
||||
|
||||
.align 4
|
||||
ret_from_sys_call:
|
||||
cmovne $26, 0, $19 /* $19 = 0 => non-restartable */
|
||||
cmovne $26, 0, $18 /* $18 = 0 => non-restartable */
|
||||
ldq $0, SP_OFF($sp)
|
||||
and $0, 8, $0
|
||||
beq $0, ret_to_kernel
|
||||
@@ -320,8 +320,8 @@ ret_to_user:
|
||||
sampling and the rti. */
|
||||
lda $16, 7
|
||||
call_pal PAL_swpipl
|
||||
ldl $5, TI_FLAGS($8)
|
||||
and $5, _TIF_WORK_MASK, $2
|
||||
ldl $17, TI_FLAGS($8)
|
||||
and $17, _TIF_WORK_MASK, $2
|
||||
bne $2, work_pending
|
||||
restore_all:
|
||||
RESTORE_ALL
|
||||
@@ -341,10 +341,10 @@ $syscall_error:
|
||||
* frame to indicate that a negative return value wasn't an
|
||||
* error number..
|
||||
*/
|
||||
ldq $19, 0($sp) /* old syscall nr (zero if success) */
|
||||
beq $19, $ret_success
|
||||
ldq $18, 0($sp) /* old syscall nr (zero if success) */
|
||||
beq $18, $ret_success
|
||||
|
||||
ldq $20, 72($sp) /* .. and this a3 */
|
||||
ldq $19, 72($sp) /* .. and this a3 */
|
||||
subq $31, $0, $0 /* with error in v0 */
|
||||
addq $31, 1, $1 /* set a3 for errno return */
|
||||
stq $0, 0($sp)
|
||||
@@ -362,51 +362,35 @@ $ret_success:
|
||||
* Do all cleanup when returning from all interrupts and system calls.
|
||||
*
|
||||
* Arguments:
|
||||
* $5: TI_FLAGS.
|
||||
* $8: current.
|
||||
* $19: The old syscall number, or zero if this is not a return
|
||||
* $17: TI_FLAGS.
|
||||
* $18: The old syscall number, or zero if this is not a return
|
||||
* from a syscall that errored and is possibly restartable.
|
||||
* $20: The old a3 value
|
||||
* $19: The old a3 value
|
||||
*/
|
||||
|
||||
.align 4
|
||||
.ent work_pending
|
||||
work_pending:
|
||||
and $5, _TIF_NEED_RESCHED, $2
|
||||
beq $2, $work_notifysig
|
||||
and $17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING, $2
|
||||
bne $2, $work_notifysig
|
||||
|
||||
$work_resched:
|
||||
subq $sp, 16, $sp
|
||||
stq $19, 0($sp) /* save syscall nr */
|
||||
stq $20, 8($sp) /* and error indication (a3) */
|
||||
/*
|
||||
* We can get here only if we returned from syscall without SIGPENDING
|
||||
* or got through work_notifysig already. Either case means no syscall
|
||||
* restarts for us, so let $18 and $19 burn.
|
||||
*/
|
||||
jsr $26, schedule
|
||||
ldq $19, 0($sp)
|
||||
ldq $20, 8($sp)
|
||||
addq $sp, 16, $sp
|
||||
/* Make sure need_resched and sigpending don't change between
|
||||
sampling and the rti. */
|
||||
lda $16, 7
|
||||
call_pal PAL_swpipl
|
||||
ldl $5, TI_FLAGS($8)
|
||||
and $5, _TIF_WORK_MASK, $2
|
||||
beq $2, restore_all
|
||||
and $5, _TIF_NEED_RESCHED, $2
|
||||
bne $2, $work_resched
|
||||
mov 0, $18
|
||||
br ret_to_user
|
||||
|
||||
$work_notifysig:
|
||||
mov $sp, $16
|
||||
bsr $1, do_switch_stack
|
||||
mov $sp, $17
|
||||
mov $5, $18
|
||||
mov $19, $9 /* save old syscall number */
|
||||
mov $20, $10 /* save old a3 */
|
||||
and $5, _TIF_SIGPENDING, $2
|
||||
cmovne $2, 0, $9 /* we don't want double syscall restarts */
|
||||
jsr $26, do_notify_resume
|
||||
mov $9, $19
|
||||
mov $10, $20
|
||||
jsr $26, do_work_pending
|
||||
bsr $1, undo_switch_stack
|
||||
br ret_to_user
|
||||
br restore_all
|
||||
.end work_pending
|
||||
|
||||
/*
|
||||
@@ -454,9 +438,9 @@ $strace_success:
|
||||
|
||||
.align 3
|
||||
$strace_error:
|
||||
ldq $19, 0($sp) /* old syscall nr (zero if success) */
|
||||
beq $19, $strace_success
|
||||
ldq $20, 72($sp) /* .. and this a3 */
|
||||
ldq $18, 0($sp) /* old syscall nr (zero if success) */
|
||||
beq $18, $strace_success
|
||||
ldq $19, 72($sp) /* .. and this a3 */
|
||||
|
||||
subq $31, $0, $0 /* with error in v0 */
|
||||
addq $31, 1, $1 /* set a3 for errno return */
|
||||
@@ -464,11 +448,11 @@ $strace_error:
|
||||
stq $1, 72($sp) /* a3 for return */
|
||||
|
||||
bsr $1, do_switch_stack
|
||||
mov $19, $9 /* save old syscall number */
|
||||
mov $20, $10 /* save old a3 */
|
||||
mov $18, $9 /* save old syscall number */
|
||||
mov $19, $10 /* save old a3 */
|
||||
jsr $26, syscall_trace_leave
|
||||
mov $9, $19
|
||||
mov $10, $20
|
||||
mov $9, $18
|
||||
mov $10, $19
|
||||
bsr $1, undo_switch_stack
|
||||
|
||||
mov $31, $26 /* tell "ret_from_sys_call" we can restart */
|
||||
@@ -619,24 +603,9 @@ ret_from_kernel_thread:
|
||||
mov $9, $27
|
||||
mov $10, $16
|
||||
jsr $26, ($9)
|
||||
ldgp $gp, 0($26)
|
||||
mov $0, $16
|
||||
mov $31, $26
|
||||
jmp $31, sys_exit
|
||||
.end ret_from_kernel_thread
|
||||
|
||||
.globl ret_from_kernel_execve
|
||||
.align 4
|
||||
.ent ret_from_kernel_execve
|
||||
ret_from_kernel_execve:
|
||||
mov $16, $sp
|
||||
/* Avoid the HAE being gratuitously wrong, to avoid restoring it. */
|
||||
ldq $2, alpha_mv+HAE_CACHE
|
||||
stq $2, 152($sp) /* HAE */
|
||||
mov $31, $19 /* to disable syscall restarts */
|
||||
br $31, ret_to_user
|
||||
|
||||
.end ret_from_kernel_execve
|
||||
.end ret_from_kernel_thread
|
||||
|
||||
|
||||
/*
|
||||
|
@@ -298,8 +298,9 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
|
||||
|
||||
static long
|
||||
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
||||
struct switch_stack *sw, unsigned long mask, unsigned long sp)
|
||||
unsigned long mask, unsigned long sp)
|
||||
{
|
||||
struct switch_stack *sw = (struct switch_stack *)regs - 1;
|
||||
long i, err = 0;
|
||||
|
||||
err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
|
||||
@@ -354,7 +355,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
||||
|
||||
static int
|
||||
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
||||
struct pt_regs *regs, struct switch_stack * sw)
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned long oldsp, r26, err = 0;
|
||||
struct sigframe __user *frame;
|
||||
@@ -364,7 +365,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
|
||||
err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp);
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
@@ -401,7 +402,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
||||
|
||||
static int
|
||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
|
||||
sigset_t *set, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long oldsp, r26, err = 0;
|
||||
struct rt_sigframe __user *frame;
|
||||
@@ -420,7 +421,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||
err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags);
|
||||
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw,
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs,
|
||||
set->sig[0], oldsp);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
if (err)
|
||||
@@ -464,15 +465,15 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
*/
|
||||
static inline void
|
||||
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
struct pt_regs * regs, struct switch_stack *sw)
|
||||
struct pt_regs * regs)
|
||||
{
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
int ret;
|
||||
|
||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||
ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
|
||||
ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
||||
else
|
||||
ret = setup_frame(sig, ka, oldset, regs, sw);
|
||||
ret = setup_frame(sig, ka, oldset, regs);
|
||||
|
||||
if (ret) {
|
||||
force_sigsegv(sig, current);
|
||||
@@ -519,8 +520,7 @@ syscall_restart(unsigned long r0, unsigned long r19,
|
||||
* all (if we get here from anything but a syscall return, it will be 0)
|
||||
*/
|
||||
static void
|
||||
do_signal(struct pt_regs * regs, struct switch_stack * sw,
|
||||
unsigned long r0, unsigned long r19)
|
||||
do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
|
||||
{
|
||||
siginfo_t info;
|
||||
int signr;
|
||||
@@ -537,7 +537,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
|
||||
/* Whee! Actually deliver the signal. */
|
||||
if (r0)
|
||||
syscall_restart(r0, r19, regs, &ka);
|
||||
handle_signal(signr, &ka, &info, regs, sw);
|
||||
handle_signal(signr, &ka, &info, regs);
|
||||
if (single_stepping)
|
||||
ptrace_set_bpt(current); /* re-set bpt */
|
||||
return;
|
||||
@@ -568,15 +568,23 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
|
||||
}
|
||||
|
||||
void
|
||||
do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
|
||||
unsigned long thread_info_flags,
|
||||
do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
|
||||
unsigned long r0, unsigned long r19)
|
||||
{
|
||||
if (thread_info_flags & _TIF_SIGPENDING)
|
||||
do_signal(regs, sw, r0, r19);
|
||||
|
||||
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
tracehook_notify_resume(regs);
|
||||
}
|
||||
do {
|
||||
if (thread_flags & _TIF_NEED_RESCHED) {
|
||||
schedule();
|
||||
} else {
|
||||
local_irq_enable();
|
||||
if (thread_flags & _TIF_SIGPENDING) {
|
||||
do_signal(regs, r0, r19);
|
||||
r0 = 0;
|
||||
} else {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
tracehook_notify_resume(regs);
|
||||
}
|
||||
}
|
||||
local_irq_disable();
|
||||
thread_flags = current_thread_info()->flags;
|
||||
} while (thread_flags & _TIF_WORK_MASK);
|
||||
}
|
||||
|
Reference in New Issue
Block a user