Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e21fc13 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 8418263e 5522be6a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -274,6 +274,9 @@ config ARCH_WANT_OLD_COMPAT_IPC
config GENERIC_KERNEL_THREAD
	bool

config GENERIC_KERNEL_EXECVE
	bool

config HAVE_ARCH_SECCOMP_FILTER
	bool
	help
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ config ALPHA
	select GENERIC_STRNCPY_FROM_USER
	select GENERIC_STRNLEN_USER
	select GENERIC_KERNEL_THREAD
	select GENERIC_KERNEL_EXECVE
	help
	  The Alpha is a 64-bit general-purpose processor designed and
	  marketed by the Digital Equipment Corporation of blessed memory,
+0 −1
Original line number Diff line number Diff line
@@ -482,7 +482,6 @@
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_EXECVE
#define __ARCH_WANT_KERNEL_EXECVE

/* "Conditional" syscalls.  What we want is

+28 −59
Original line number Diff line number Diff line
@@ -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


/*
+28 −20
Original line number Diff line number Diff line
@@ -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) {
	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);
}
Loading