diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-12 21:05:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-12 21:05:52 -0400 |
commit | 4e21fc138bfd7fe625ff5dc81541399aaf9d429b (patch) | |
tree | 43bedf14d2eee7711b8241dcfd6bd7b8737d9bd5 /arch/alpha/kernel | |
parent | 8418263e3547ed3816475e4c55a77004f0426ee6 (diff) | |
parent | 5522be6a4624a5f505555569e4d9cee946630686 (diff) |
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
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r-- | arch/alpha/kernel/entry.S | 87 | ||||
-rw-r--r-- | arch/alpha/kernel/signal.c | 48 |
2 files changed, 56 insertions, 79 deletions
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 2a359c9ee3cd..a7607832dd4f 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S | |||
@@ -311,7 +311,7 @@ entSys: | |||
311 | 311 | ||
312 | .align 4 | 312 | .align 4 |
313 | ret_from_sys_call: | 313 | ret_from_sys_call: |
314 | cmovne $26, 0, $19 /* $19 = 0 => non-restartable */ | 314 | cmovne $26, 0, $18 /* $18 = 0 => non-restartable */ |
315 | ldq $0, SP_OFF($sp) | 315 | ldq $0, SP_OFF($sp) |
316 | and $0, 8, $0 | 316 | and $0, 8, $0 |
317 | beq $0, ret_to_kernel | 317 | beq $0, ret_to_kernel |
@@ -320,8 +320,8 @@ ret_to_user: | |||
320 | sampling and the rti. */ | 320 | sampling and the rti. */ |
321 | lda $16, 7 | 321 | lda $16, 7 |
322 | call_pal PAL_swpipl | 322 | call_pal PAL_swpipl |
323 | ldl $5, TI_FLAGS($8) | 323 | ldl $17, TI_FLAGS($8) |
324 | and $5, _TIF_WORK_MASK, $2 | 324 | and $17, _TIF_WORK_MASK, $2 |
325 | bne $2, work_pending | 325 | bne $2, work_pending |
326 | restore_all: | 326 | restore_all: |
327 | RESTORE_ALL | 327 | RESTORE_ALL |
@@ -341,10 +341,10 @@ $syscall_error: | |||
341 | * frame to indicate that a negative return value wasn't an | 341 | * frame to indicate that a negative return value wasn't an |
342 | * error number.. | 342 | * error number.. |
343 | */ | 343 | */ |
344 | ldq $19, 0($sp) /* old syscall nr (zero if success) */ | 344 | ldq $18, 0($sp) /* old syscall nr (zero if success) */ |
345 | beq $19, $ret_success | 345 | beq $18, $ret_success |
346 | 346 | ||
347 | ldq $20, 72($sp) /* .. and this a3 */ | 347 | ldq $19, 72($sp) /* .. and this a3 */ |
348 | subq $31, $0, $0 /* with error in v0 */ | 348 | subq $31, $0, $0 /* with error in v0 */ |
349 | addq $31, 1, $1 /* set a3 for errno return */ | 349 | addq $31, 1, $1 /* set a3 for errno return */ |
350 | stq $0, 0($sp) | 350 | stq $0, 0($sp) |
@@ -362,51 +362,35 @@ $ret_success: | |||
362 | * Do all cleanup when returning from all interrupts and system calls. | 362 | * Do all cleanup when returning from all interrupts and system calls. |
363 | * | 363 | * |
364 | * Arguments: | 364 | * Arguments: |
365 | * $5: TI_FLAGS. | ||
366 | * $8: current. | 365 | * $8: current. |
367 | * $19: The old syscall number, or zero if this is not a return | 366 | * $17: TI_FLAGS. |
367 | * $18: The old syscall number, or zero if this is not a return | ||
368 | * from a syscall that errored and is possibly restartable. | 368 | * from a syscall that errored and is possibly restartable. |
369 | * $20: The old a3 value | 369 | * $19: The old a3 value |
370 | */ | 370 | */ |
371 | 371 | ||
372 | .align 4 | 372 | .align 4 |
373 | .ent work_pending | 373 | .ent work_pending |
374 | work_pending: | 374 | work_pending: |
375 | and $5, _TIF_NEED_RESCHED, $2 | 375 | and $17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING, $2 |
376 | beq $2, $work_notifysig | 376 | bne $2, $work_notifysig |
377 | 377 | ||
378 | $work_resched: | 378 | $work_resched: |
379 | subq $sp, 16, $sp | 379 | /* |
380 | stq $19, 0($sp) /* save syscall nr */ | 380 | * We can get here only if we returned from syscall without SIGPENDING |
381 | stq $20, 8($sp) /* and error indication (a3) */ | 381 | * or got through work_notifysig already. Either case means no syscall |
382 | * restarts for us, so let $18 and $19 burn. | ||
383 | */ | ||
382 | jsr $26, schedule | 384 | jsr $26, schedule |
383 | ldq $19, 0($sp) | 385 | mov 0, $18 |
384 | ldq $20, 8($sp) | 386 | br ret_to_user |
385 | addq $sp, 16, $sp | ||
386 | /* Make sure need_resched and sigpending don't change between | ||
387 | sampling and the rti. */ | ||
388 | lda $16, 7 | ||
389 | call_pal PAL_swpipl | ||
390 | ldl $5, TI_FLAGS($8) | ||
391 | and $5, _TIF_WORK_MASK, $2 | ||
392 | beq $2, restore_all | ||
393 | and $5, _TIF_NEED_RESCHED, $2 | ||
394 | bne $2, $work_resched | ||
395 | 387 | ||
396 | $work_notifysig: | 388 | $work_notifysig: |
397 | mov $sp, $16 | 389 | mov $sp, $16 |
398 | bsr $1, do_switch_stack | 390 | bsr $1, do_switch_stack |
399 | mov $sp, $17 | 391 | jsr $26, do_work_pending |
400 | mov $5, $18 | ||
401 | mov $19, $9 /* save old syscall number */ | ||
402 | mov $20, $10 /* save old a3 */ | ||
403 | and $5, _TIF_SIGPENDING, $2 | ||
404 | cmovne $2, 0, $9 /* we don't want double syscall restarts */ | ||
405 | jsr $26, do_notify_resume | ||
406 | mov $9, $19 | ||
407 | mov $10, $20 | ||
408 | bsr $1, undo_switch_stack | 392 | bsr $1, undo_switch_stack |
409 | br ret_to_user | 393 | br restore_all |
410 | .end work_pending | 394 | .end work_pending |
411 | 395 | ||
412 | /* | 396 | /* |
@@ -454,9 +438,9 @@ $strace_success: | |||
454 | 438 | ||
455 | .align 3 | 439 | .align 3 |
456 | $strace_error: | 440 | $strace_error: |
457 | ldq $19, 0($sp) /* old syscall nr (zero if success) */ | 441 | ldq $18, 0($sp) /* old syscall nr (zero if success) */ |
458 | beq $19, $strace_success | 442 | beq $18, $strace_success |
459 | ldq $20, 72($sp) /* .. and this a3 */ | 443 | ldq $19, 72($sp) /* .. and this a3 */ |
460 | 444 | ||
461 | subq $31, $0, $0 /* with error in v0 */ | 445 | subq $31, $0, $0 /* with error in v0 */ |
462 | addq $31, 1, $1 /* set a3 for errno return */ | 446 | addq $31, 1, $1 /* set a3 for errno return */ |
@@ -464,11 +448,11 @@ $strace_error: | |||
464 | stq $1, 72($sp) /* a3 for return */ | 448 | stq $1, 72($sp) /* a3 for return */ |
465 | 449 | ||
466 | bsr $1, do_switch_stack | 450 | bsr $1, do_switch_stack |
467 | mov $19, $9 /* save old syscall number */ | 451 | mov $18, $9 /* save old syscall number */ |
468 | mov $20, $10 /* save old a3 */ | 452 | mov $19, $10 /* save old a3 */ |
469 | jsr $26, syscall_trace_leave | 453 | jsr $26, syscall_trace_leave |
470 | mov $9, $19 | 454 | mov $9, $18 |
471 | mov $10, $20 | 455 | mov $10, $19 |
472 | bsr $1, undo_switch_stack | 456 | bsr $1, undo_switch_stack |
473 | 457 | ||
474 | mov $31, $26 /* tell "ret_from_sys_call" we can restart */ | 458 | mov $31, $26 /* tell "ret_from_sys_call" we can restart */ |
@@ -619,24 +603,9 @@ ret_from_kernel_thread: | |||
619 | mov $9, $27 | 603 | mov $9, $27 |
620 | mov $10, $16 | 604 | mov $10, $16 |
621 | jsr $26, ($9) | 605 | jsr $26, ($9) |
622 | ldgp $gp, 0($26) | ||
623 | mov $0, $16 | ||
624 | mov $31, $26 | ||
625 | jmp $31, sys_exit | ||
626 | .end ret_from_kernel_thread | ||
627 | |||
628 | .globl ret_from_kernel_execve | ||
629 | .align 4 | ||
630 | .ent ret_from_kernel_execve | ||
631 | ret_from_kernel_execve: | ||
632 | mov $16, $sp | ||
633 | /* Avoid the HAE being gratuitously wrong, to avoid restoring it. */ | ||
634 | ldq $2, alpha_mv+HAE_CACHE | ||
635 | stq $2, 152($sp) /* HAE */ | ||
636 | mov $31, $19 /* to disable syscall restarts */ | 606 | mov $31, $19 /* to disable syscall restarts */ |
637 | br $31, ret_to_user | 607 | br $31, ret_to_user |
638 | 608 | .end ret_from_kernel_thread | |
639 | .end ret_from_kernel_execve | ||
640 | 609 | ||
641 | 610 | ||
642 | /* | 611 | /* |
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index a8c97d42ec8e..32575f85507d 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
@@ -298,8 +298,9 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
298 | 298 | ||
299 | static long | 299 | static long |
300 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 300 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
301 | struct switch_stack *sw, unsigned long mask, unsigned long sp) | 301 | unsigned long mask, unsigned long sp) |
302 | { | 302 | { |
303 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
303 | long i, err = 0; | 304 | long i, err = 0; |
304 | 305 | ||
305 | err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); | 306 | 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, | |||
354 | 355 | ||
355 | static int | 356 | static int |
356 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 357 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
357 | struct pt_regs *regs, struct switch_stack * sw) | 358 | struct pt_regs *regs) |
358 | { | 359 | { |
359 | unsigned long oldsp, r26, err = 0; | 360 | unsigned long oldsp, r26, err = 0; |
360 | struct sigframe __user *frame; | 361 | struct sigframe __user *frame; |
@@ -364,7 +365,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
364 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 365 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
365 | return -EFAULT; | 366 | return -EFAULT; |
366 | 367 | ||
367 | err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); | 368 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp); |
368 | if (err) | 369 | if (err) |
369 | return -EFAULT; | 370 | return -EFAULT; |
370 | 371 | ||
@@ -401,7 +402,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
401 | 402 | ||
402 | static int | 403 | static int |
403 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 404 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
404 | sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) | 405 | sigset_t *set, struct pt_regs *regs) |
405 | { | 406 | { |
406 | unsigned long oldsp, r26, err = 0; | 407 | unsigned long oldsp, r26, err = 0; |
407 | struct rt_sigframe __user *frame; | 408 | struct rt_sigframe __user *frame; |
@@ -420,7 +421,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
420 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 421 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
421 | err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); | 422 | err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); |
422 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 423 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
423 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, | 424 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, |
424 | set->sig[0], oldsp); | 425 | set->sig[0], oldsp); |
425 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 426 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
426 | if (err) | 427 | if (err) |
@@ -464,15 +465,15 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
464 | */ | 465 | */ |
465 | static inline void | 466 | static inline void |
466 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 467 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
467 | struct pt_regs * regs, struct switch_stack *sw) | 468 | struct pt_regs * regs) |
468 | { | 469 | { |
469 | sigset_t *oldset = sigmask_to_save(); | 470 | sigset_t *oldset = sigmask_to_save(); |
470 | int ret; | 471 | int ret; |
471 | 472 | ||
472 | if (ka->sa.sa_flags & SA_SIGINFO) | 473 | if (ka->sa.sa_flags & SA_SIGINFO) |
473 | ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); | 474 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
474 | else | 475 | else |
475 | ret = setup_frame(sig, ka, oldset, regs, sw); | 476 | ret = setup_frame(sig, ka, oldset, regs); |
476 | 477 | ||
477 | if (ret) { | 478 | if (ret) { |
478 | force_sigsegv(sig, current); | 479 | force_sigsegv(sig, current); |
@@ -519,8 +520,7 @@ syscall_restart(unsigned long r0, unsigned long r19, | |||
519 | * all (if we get here from anything but a syscall return, it will be 0) | 520 | * all (if we get here from anything but a syscall return, it will be 0) |
520 | */ | 521 | */ |
521 | static void | 522 | static void |
522 | do_signal(struct pt_regs * regs, struct switch_stack * sw, | 523 | do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) |
523 | unsigned long r0, unsigned long r19) | ||
524 | { | 524 | { |
525 | siginfo_t info; | 525 | siginfo_t info; |
526 | int signr; | 526 | int signr; |
@@ -537,7 +537,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
537 | /* Whee! Actually deliver the signal. */ | 537 | /* Whee! Actually deliver the signal. */ |
538 | if (r0) | 538 | if (r0) |
539 | syscall_restart(r0, r19, regs, &ka); | 539 | syscall_restart(r0, r19, regs, &ka); |
540 | handle_signal(signr, &ka, &info, regs, sw); | 540 | handle_signal(signr, &ka, &info, regs); |
541 | if (single_stepping) | 541 | if (single_stepping) |
542 | ptrace_set_bpt(current); /* re-set bpt */ | 542 | ptrace_set_bpt(current); /* re-set bpt */ |
543 | return; | 543 | return; |
@@ -568,15 +568,23 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
568 | } | 568 | } |
569 | 569 | ||
570 | void | 570 | void |
571 | do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, | 571 | do_work_pending(struct pt_regs *regs, unsigned long thread_flags, |
572 | unsigned long thread_info_flags, | ||
573 | unsigned long r0, unsigned long r19) | 572 | unsigned long r0, unsigned long r19) |
574 | { | 573 | { |
575 | if (thread_info_flags & _TIF_SIGPENDING) | 574 | do { |
576 | do_signal(regs, sw, r0, r19); | 575 | if (thread_flags & _TIF_NEED_RESCHED) { |
577 | 576 | schedule(); | |
578 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 577 | } else { |
579 | clear_thread_flag(TIF_NOTIFY_RESUME); | 578 | local_irq_enable(); |
580 | tracehook_notify_resume(regs); | 579 | if (thread_flags & _TIF_SIGPENDING) { |
581 | } | 580 | do_signal(regs, r0, r19); |
581 | r0 = 0; | ||
582 | } else { | ||
583 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
584 | tracehook_notify_resume(regs); | ||
585 | } | ||
586 | } | ||
587 | local_irq_disable(); | ||
588 | thread_flags = current_thread_info()->flags; | ||
589 | } while (thread_flags & _TIF_WORK_MASK); | ||
582 | } | 590 | } |