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 | |
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
-rw-r--r-- | arch/Kconfig | 3 | ||||
-rw-r--r-- | arch/alpha/Kconfig | 1 | ||||
-rw-r--r-- | arch/alpha/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/alpha/kernel/entry.S | 87 | ||||
-rw-r--r-- | arch/alpha/kernel/signal.c | 48 | ||||
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 29 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_event.c | 5 | ||||
-rw-r--r-- | arch/um/include/asm/processor-generic.h | 2 | ||||
-rw-r--r-- | arch/um/include/shared/os.h | 1 | ||||
-rw-r--r-- | arch/um/kernel/exec.c | 5 | ||||
-rw-r--r-- | arch/um/kernel/process.c | 10 | ||||
-rw-r--r-- | arch/um/os-Linux/process.c | 13 | ||||
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/entry_32.S | 31 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 24 | ||||
-rw-r--r-- | arch/x86/um/Kconfig | 1 | ||||
-rw-r--r-- | include/linux/syscalls.h | 8 | ||||
-rw-r--r-- | init/do_mounts_initrd.c | 41 | ||||
-rw-r--r-- | init/main.c | 33 | ||||
-rw-r--r-- | kernel/kmod.c | 7 | ||||
-rw-r--r-- | kernel/kthread.c | 1 |
25 files changed, 137 insertions, 223 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 26a28419cafc..a79a1ad8bb96 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -274,6 +274,9 @@ config ARCH_WANT_OLD_COMPAT_IPC | |||
274 | config GENERIC_KERNEL_THREAD | 274 | config GENERIC_KERNEL_THREAD |
275 | bool | 275 | bool |
276 | 276 | ||
277 | config GENERIC_KERNEL_EXECVE | ||
278 | bool | ||
279 | |||
277 | config HAVE_ARCH_SECCOMP_FILTER | 280 | config HAVE_ARCH_SECCOMP_FILTER |
278 | bool | 281 | bool |
279 | help | 282 | help |
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 7da91246e279..7a08cfb80ee8 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
@@ -21,6 +21,7 @@ config ALPHA | |||
21 | select GENERIC_STRNCPY_FROM_USER | 21 | select GENERIC_STRNCPY_FROM_USER |
22 | select GENERIC_STRNLEN_USER | 22 | select GENERIC_STRNLEN_USER |
23 | select GENERIC_KERNEL_THREAD | 23 | select GENERIC_KERNEL_THREAD |
24 | select GENERIC_KERNEL_EXECVE | ||
24 | help | 25 | help |
25 | The Alpha is a 64-bit general-purpose processor designed and | 26 | The Alpha is a 64-bit general-purpose processor designed and |
26 | marketed by the Digital Equipment Corporation of blessed memory, | 27 | marketed by the Digital Equipment Corporation of blessed memory, |
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 3cb6c1188984..7826e227e4d0 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h | |||
@@ -482,7 +482,6 @@ | |||
482 | #define __ARCH_WANT_SYS_SIGPENDING | 482 | #define __ARCH_WANT_SYS_SIGPENDING |
483 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 483 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
484 | #define __ARCH_WANT_SYS_EXECVE | 484 | #define __ARCH_WANT_SYS_EXECVE |
485 | #define __ARCH_WANT_KERNEL_EXECVE | ||
486 | 485 | ||
487 | /* "Conditional" syscalls. What we want is | 486 | /* "Conditional" syscalls. What we want is |
488 | 487 | ||
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 | } |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 767aae8277fa..431c3753145a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -53,6 +53,7 @@ config ARM | |||
53 | select GENERIC_STRNLEN_USER | 53 | select GENERIC_STRNLEN_USER |
54 | select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN | 54 | select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN |
55 | select GENERIC_KERNEL_THREAD | 55 | select GENERIC_KERNEL_THREAD |
56 | select GENERIC_KERNEL_EXECVE | ||
56 | help | 57 | help |
57 | The ARM series is a line of low-power-consumption RISC chip designs | 58 | The ARM series is a line of low-power-consumption RISC chip designs |
58 | licensed by ARM Ltd and targeted at embedded applications and | 59 | licensed by ARM Ltd and targeted at embedded applications and |
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index f259921edfe9..91819ad54424 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h | |||
@@ -479,7 +479,6 @@ | |||
479 | #define __ARCH_WANT_SYS_SOCKETCALL | 479 | #define __ARCH_WANT_SYS_SOCKETCALL |
480 | #endif | 480 | #endif |
481 | #define __ARCH_WANT_SYS_EXECVE | 481 | #define __ARCH_WANT_SYS_EXECVE |
482 | #define __ARCH_WANT_KERNEL_EXECVE | ||
483 | 482 | ||
484 | /* | 483 | /* |
485 | * "Conditional" syscalls | 484 | * "Conditional" syscalls |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index e340fa1db203..417bac1846bd 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -86,35 +86,14 @@ ENDPROC(ret_to_user) | |||
86 | */ | 86 | */ |
87 | ENTRY(ret_from_fork) | 87 | ENTRY(ret_from_fork) |
88 | bl schedule_tail | 88 | bl schedule_tail |
89 | cmp r5, #0 | ||
90 | movne r0, r4 | ||
91 | movne lr, pc | ||
92 | movne pc, r5 | ||
89 | get_thread_info tsk | 93 | get_thread_info tsk |
90 | mov why, #1 | ||
91 | b ret_slow_syscall | 94 | b ret_slow_syscall |
92 | ENDPROC(ret_from_fork) | 95 | ENDPROC(ret_from_fork) |
93 | 96 | ||
94 | ENTRY(ret_from_kernel_thread) | ||
95 | UNWIND(.fnstart) | ||
96 | UNWIND(.cantunwind) | ||
97 | bl schedule_tail | ||
98 | mov r0, r4 | ||
99 | adr lr, BSYM(1f) @ kernel threads should not exit | ||
100 | mov pc, r5 | ||
101 | 1: bl do_exit | ||
102 | nop | ||
103 | UNWIND(.fnend) | ||
104 | ENDPROC(ret_from_kernel_thread) | ||
105 | |||
106 | /* | ||
107 | * turn a kernel thread into userland process | ||
108 | * use: ret_from_kernel_execve(struct pt_regs *normal) | ||
109 | */ | ||
110 | ENTRY(ret_from_kernel_execve) | ||
111 | mov why, #0 @ not a syscall | ||
112 | str why, [r0, #S_R0] @ ... and we want 0 in ->ARM_r0 as well | ||
113 | get_thread_info tsk @ thread structure | ||
114 | mov sp, r0 @ stack pointer just under pt_regs | ||
115 | b ret_slow_syscall | ||
116 | ENDPROC(ret_from_kernel_execve) | ||
117 | |||
118 | .equ NR_syscalls,0 | 97 | .equ NR_syscalls,0 |
119 | #define CALL(x) .equ NR_syscalls,NR_syscalls+1 | 98 | #define CALL(x) .equ NR_syscalls,NR_syscalls+1 |
120 | #include "calls.S" | 99 | #include "calls.S" |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index f98c17ff1957..90084a6de35a 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -373,7 +373,6 @@ void release_thread(struct task_struct *dead_task) | |||
373 | } | 373 | } |
374 | 374 | ||
375 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 375 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
376 | asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); | ||
377 | 376 | ||
378 | int | 377 | int |
379 | copy_thread(unsigned long clone_flags, unsigned long stack_start, | 378 | copy_thread(unsigned long clone_flags, unsigned long stack_start, |
@@ -388,13 +387,13 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
388 | *childregs = *regs; | 387 | *childregs = *regs; |
389 | childregs->ARM_r0 = 0; | 388 | childregs->ARM_r0 = 0; |
390 | childregs->ARM_sp = stack_start; | 389 | childregs->ARM_sp = stack_start; |
391 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | ||
392 | } else { | 390 | } else { |
391 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
393 | thread->cpu_context.r4 = stk_sz; | 392 | thread->cpu_context.r4 = stk_sz; |
394 | thread->cpu_context.r5 = stack_start; | 393 | thread->cpu_context.r5 = stack_start; |
395 | thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread; | ||
396 | childregs->ARM_cpsr = SVC_MODE; | 394 | childregs->ARM_cpsr = SVC_MODE; |
397 | } | 395 | } |
396 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | ||
398 | thread->cpu_context.sp = (unsigned long)childregs; | 397 | thread->cpu_context.sp = (unsigned long)childregs; |
399 | 398 | ||
400 | clear_ptrace_hw_breakpoint(p); | 399 | clear_ptrace_hw_breakpoint(p); |
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 51faaac8abe6..185bedd926df 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
26 | #include <linux/kthread.h> | ||
26 | #include <asm/eeh_event.h> | 27 | #include <asm/eeh_event.h> |
27 | #include <asm/ppc-pci.h> | 28 | #include <asm/ppc-pci.h> |
28 | 29 | ||
@@ -59,8 +60,6 @@ static int eeh_event_handler(void * dummy) | |||
59 | struct eeh_event *event; | 60 | struct eeh_event *event; |
60 | struct eeh_pe *pe; | 61 | struct eeh_pe *pe; |
61 | 62 | ||
62 | set_task_comm(current, "eehd"); | ||
63 | |||
64 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 63 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
65 | event = NULL; | 64 | event = NULL; |
66 | 65 | ||
@@ -108,7 +107,7 @@ static int eeh_event_handler(void * dummy) | |||
108 | */ | 107 | */ |
109 | static void eeh_thread_launcher(struct work_struct *dummy) | 108 | static void eeh_thread_launcher(struct work_struct *dummy) |
110 | { | 109 | { |
111 | if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0) | 110 | if (IS_ERR(kthread_run(eeh_event_handler, NULL, "eehd"))) |
112 | printk(KERN_ERR "Failed to start EEH daemon\n"); | 111 | printk(KERN_ERR "Failed to start EEH daemon\n"); |
113 | } | 112 | } |
114 | 113 | ||
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index 1e82e954e978..c03cd5a02364 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h | |||
@@ -26,7 +26,6 @@ struct thread_struct { | |||
26 | jmp_buf *fault_catcher; | 26 | jmp_buf *fault_catcher; |
27 | struct task_struct *prev_sched; | 27 | struct task_struct *prev_sched; |
28 | unsigned long temp_stack; | 28 | unsigned long temp_stack; |
29 | jmp_buf *exec_buf; | ||
30 | struct arch_thread arch; | 29 | struct arch_thread arch; |
31 | jmp_buf switch_buf; | 30 | jmp_buf switch_buf; |
32 | int mm_count; | 31 | int mm_count; |
@@ -54,7 +53,6 @@ struct thread_struct { | |||
54 | .fault_addr = NULL, \ | 53 | .fault_addr = NULL, \ |
55 | .prev_sched = NULL, \ | 54 | .prev_sched = NULL, \ |
56 | .temp_stack = 0, \ | 55 | .temp_stack = 0, \ |
57 | .exec_buf = NULL, \ | ||
58 | .arch = INIT_ARCH_THREAD, \ | 56 | .arch = INIT_ARCH_THREAD, \ |
59 | .request = { 0 } \ | 57 | .request = { 0 } \ |
60 | } | 58 | } |
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 44883049c11d..95feaa47a2fb 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h | |||
@@ -191,7 +191,6 @@ extern int os_getpid(void); | |||
191 | extern int os_getpgrp(void); | 191 | extern int os_getpgrp(void); |
192 | 192 | ||
193 | extern void init_new_thread_signals(void); | 193 | extern void init_new_thread_signals(void); |
194 | extern int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr); | ||
195 | 194 | ||
196 | extern int os_map_memory(void *virt, int fd, unsigned long long off, | 195 | extern int os_map_memory(void *virt, int fd, unsigned long long off, |
197 | unsigned long len, int r, int w, int x); | 196 | unsigned long len, int r, int w, int x); |
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index ab019c7f0b57..3a8ece7d09ca 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c | |||
@@ -47,8 +47,3 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) | |||
47 | #endif | 47 | #endif |
48 | } | 48 | } |
49 | EXPORT_SYMBOL(start_thread); | 49 | EXPORT_SYMBOL(start_thread); |
50 | |||
51 | void __noreturn ret_from_kernel_execve(struct pt_regs *unused) | ||
52 | { | ||
53 | UML_LONGJMP(current->thread.exec_buf, 1); | ||
54 | } | ||
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 30629783b3e0..b6d699cdd557 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
@@ -135,14 +135,10 @@ void new_thread_handler(void) | |||
135 | arg = current->thread.request.u.thread.arg; | 135 | arg = current->thread.request.u.thread.arg; |
136 | 136 | ||
137 | /* | 137 | /* |
138 | * The return value is 1 if the kernel thread execs a process, | 138 | * callback returns only if the kernel thread execs a process |
139 | * 0 if it just exits | ||
140 | */ | 139 | */ |
141 | n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); | 140 | n = fn(arg); |
142 | if (n == 1) | 141 | userspace(¤t->thread.regs.regs); |
143 | userspace(¤t->thread.regs.regs); | ||
144 | else | ||
145 | do_exit(0); | ||
146 | } | 142 | } |
147 | 143 | ||
148 | /* Called magically, see new_thread_handler above */ | 144 | /* Called magically, see new_thread_handler above */ |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 162bea3d91b2..b8f34c9e53ae 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -244,16 +244,3 @@ void init_new_thread_signals(void) | |||
244 | signal(SIGWINCH, SIG_IGN); | 244 | signal(SIGWINCH, SIG_IGN); |
245 | signal(SIGTERM, SIG_DFL); | 245 | signal(SIGTERM, SIG_DFL); |
246 | } | 246 | } |
247 | |||
248 | int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) | ||
249 | { | ||
250 | jmp_buf buf; | ||
251 | int n; | ||
252 | |||
253 | *jmp_ptr = &buf; | ||
254 | n = UML_SETJMP(&buf); | ||
255 | if (n != 0) | ||
256 | return n; | ||
257 | (*fn)(arg); | ||
258 | return 0; | ||
259 | } | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 42d2c35a5bbd..70071b19eb98 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -109,6 +109,7 @@ config X86 | |||
109 | select HAVE_RCU_USER_QS if X86_64 | 109 | select HAVE_RCU_USER_QS if X86_64 |
110 | select HAVE_IRQ_TIME_ACCOUNTING | 110 | select HAVE_IRQ_TIME_ACCOUNTING |
111 | select GENERIC_KERNEL_THREAD | 111 | select GENERIC_KERNEL_THREAD |
112 | select GENERIC_KERNEL_EXECVE | ||
112 | 113 | ||
113 | config INSTRUCTION_DECODER | 114 | config INSTRUCTION_DECODER |
114 | def_bool y | 115 | def_bool y |
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 55d155560fdf..16f3fc6ebf2e 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h | |||
@@ -51,7 +51,6 @@ | |||
51 | # define __ARCH_WANT_SYS_UTIME | 51 | # define __ARCH_WANT_SYS_UTIME |
52 | # define __ARCH_WANT_SYS_WAITPID | 52 | # define __ARCH_WANT_SYS_WAITPID |
53 | # define __ARCH_WANT_SYS_EXECVE | 53 | # define __ARCH_WANT_SYS_EXECVE |
54 | # define __ARCH_WANT_KERNEL_EXECVE | ||
55 | 54 | ||
56 | /* | 55 | /* |
57 | * "Conditional" syscalls | 56 | * "Conditional" syscalls |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 2c6340796fe9..a1193aef6d7d 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -299,12 +299,20 @@ ENTRY(ret_from_fork) | |||
299 | CFI_ENDPROC | 299 | CFI_ENDPROC |
300 | END(ret_from_fork) | 300 | END(ret_from_fork) |
301 | 301 | ||
302 | ENTRY(ret_from_kernel_execve) | 302 | ENTRY(ret_from_kernel_thread) |
303 | movl %eax, %esp | 303 | CFI_STARTPROC |
304 | movl $0,PT_EAX(%esp) | 304 | pushl_cfi %eax |
305 | call schedule_tail | ||
305 | GET_THREAD_INFO(%ebp) | 306 | GET_THREAD_INFO(%ebp) |
307 | popl_cfi %eax | ||
308 | pushl_cfi $0x0202 # Reset kernel eflags | ||
309 | popfl_cfi | ||
310 | movl PT_EBP(%esp),%eax | ||
311 | call *PT_EBX(%esp) | ||
312 | movl $0,PT_EAX(%esp) | ||
306 | jmp syscall_exit | 313 | jmp syscall_exit |
307 | END(ret_from_kernel_execve) | 314 | CFI_ENDPROC |
315 | ENDPROC(ret_from_kernel_thread) | ||
308 | 316 | ||
309 | /* | 317 | /* |
310 | * Interrupt exit functions should be protected against kprobes | 318 | * Interrupt exit functions should be protected against kprobes |
@@ -1015,21 +1023,6 @@ END(spurious_interrupt_bug) | |||
1015 | */ | 1023 | */ |
1016 | .popsection | 1024 | .popsection |
1017 | 1025 | ||
1018 | ENTRY(ret_from_kernel_thread) | ||
1019 | CFI_STARTPROC | ||
1020 | pushl_cfi %eax | ||
1021 | call schedule_tail | ||
1022 | GET_THREAD_INFO(%ebp) | ||
1023 | popl_cfi %eax | ||
1024 | pushl_cfi $0x0202 # Reset kernel eflags | ||
1025 | popfl_cfi | ||
1026 | movl PT_EBP(%esp),%eax | ||
1027 | call *PT_EBX(%esp) | ||
1028 | call do_exit | ||
1029 | ud2 # padding for call trace | ||
1030 | CFI_ENDPROC | ||
1031 | ENDPROC(ret_from_kernel_thread) | ||
1032 | |||
1033 | #ifdef CONFIG_XEN | 1026 | #ifdef CONFIG_XEN |
1034 | /* Xen doesn't set %esp to be precisely what the normal sysenter | 1027 | /* Xen doesn't set %esp to be precisely what the normal sysenter |
1035 | entrypoint expects, so fix it up before using the normal path. */ | 1028 | entrypoint expects, so fix it up before using the normal path. */ |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index cdc790c78f32..0c58952d64e8 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -563,15 +563,13 @@ ENTRY(ret_from_fork) | |||
563 | jmp ret_from_sys_call # go to the SYSRET fastpath | 563 | jmp ret_from_sys_call # go to the SYSRET fastpath |
564 | 564 | ||
565 | 1: | 565 | 1: |
566 | subq $REST_SKIP, %rsp # move the stack pointer back | 566 | subq $REST_SKIP, %rsp # leave space for volatiles |
567 | CFI_ADJUST_CFA_OFFSET REST_SKIP | 567 | CFI_ADJUST_CFA_OFFSET REST_SKIP |
568 | movq %rbp, %rdi | 568 | movq %rbp, %rdi |
569 | call *%rbx | 569 | call *%rbx |
570 | # exit | 570 | movl $0, RAX(%rsp) |
571 | mov %eax, %edi | 571 | RESTORE_REST |
572 | call do_exit | 572 | jmp int_ret_from_sys_call |
573 | ud2 # padding for call trace | ||
574 | |||
575 | CFI_ENDPROC | 573 | CFI_ENDPROC |
576 | END(ret_from_fork) | 574 | END(ret_from_fork) |
577 | 575 | ||
@@ -1326,20 +1324,6 @@ bad_gs: | |||
1326 | jmp 2b | 1324 | jmp 2b |
1327 | .previous | 1325 | .previous |
1328 | 1326 | ||
1329 | ENTRY(ret_from_kernel_execve) | ||
1330 | movq %rdi, %rsp | ||
1331 | movl $0, RAX(%rsp) | ||
1332 | // RESTORE_REST | ||
1333 | movq 0*8(%rsp), %r15 | ||
1334 | movq 1*8(%rsp), %r14 | ||
1335 | movq 2*8(%rsp), %r13 | ||
1336 | movq 3*8(%rsp), %r12 | ||
1337 | movq 4*8(%rsp), %rbp | ||
1338 | movq 5*8(%rsp), %rbx | ||
1339 | addq $(6*8), %rsp | ||
1340 | jmp int_ret_from_sys_call | ||
1341 | END(ret_from_kernel_execve) | ||
1342 | |||
1343 | /* Call softirq on interrupt stack. Interrupts are off. */ | 1327 | /* Call softirq on interrupt stack. Interrupts are off. */ |
1344 | ENTRY(call_softirq) | 1328 | ENTRY(call_softirq) |
1345 | CFI_STARTPROC | 1329 | CFI_STARTPROC |
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index 30c4eec033af..9fa950df80e5 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig | |||
@@ -14,6 +14,7 @@ config UML_X86 | |||
14 | def_bool y | 14 | def_bool y |
15 | select GENERIC_FIND_FIRST_BIT | 15 | select GENERIC_FIND_FIRST_BIT |
16 | select GENERIC_KERNEL_THREAD | 16 | select GENERIC_KERNEL_THREAD |
17 | select GENERIC_KERNEL_EXECVE | ||
17 | 18 | ||
18 | config 64BIT | 19 | config 64BIT |
19 | bool "64-bit kernel" if SUBARCH = "x86" | 20 | bool "64-bit kernel" if SUBARCH = "x86" |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 19439c75c5b2..727f0cd73921 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -827,7 +827,15 @@ asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, | |||
827 | const char __user *pathname); | 827 | const char __user *pathname); |
828 | asmlinkage long sys_syncfs(int fd); | 828 | asmlinkage long sys_syncfs(int fd); |
829 | 829 | ||
830 | #ifndef CONFIG_GENERIC_KERNEL_EXECVE | ||
830 | int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); | 831 | int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); |
832 | #else | ||
833 | #define kernel_execve(filename, argv, envp) \ | ||
834 | do_execve(filename, \ | ||
835 | (const char __user *const __user *)argv, \ | ||
836 | (const char __user *const __user *)envp, \ | ||
837 | current_pt_regs()) | ||
838 | #endif | ||
831 | 839 | ||
832 | 840 | ||
833 | asmlinkage long sys_perf_event_open( | 841 | asmlinkage long sys_perf_event_open( |
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 135959a276be..5e4ded51788e 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c | |||
@@ -16,13 +16,13 @@ | |||
16 | #include <linux/initrd.h> | 16 | #include <linux/initrd.h> |
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/freezer.h> | 18 | #include <linux/freezer.h> |
19 | #include <linux/kmod.h> | ||
19 | 20 | ||
20 | #include "do_mounts.h" | 21 | #include "do_mounts.h" |
21 | 22 | ||
22 | unsigned long initrd_start, initrd_end; | 23 | unsigned long initrd_start, initrd_end; |
23 | int initrd_below_start_ok; | 24 | int initrd_below_start_ok; |
24 | unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ | 25 | unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ |
25 | static int __initdata old_fd, root_fd; | ||
26 | static int __initdata mount_initrd = 1; | 26 | static int __initdata mount_initrd = 1; |
27 | 27 | ||
28 | static int __init no_initrd(char *str) | 28 | static int __init no_initrd(char *str) |
@@ -33,33 +33,29 @@ static int __init no_initrd(char *str) | |||
33 | 33 | ||
34 | __setup("noinitrd", no_initrd); | 34 | __setup("noinitrd", no_initrd); |
35 | 35 | ||
36 | static int __init do_linuxrc(void *_shell) | 36 | static int init_linuxrc(struct subprocess_info *info, struct cred *new) |
37 | { | 37 | { |
38 | static const char *argv[] = { "linuxrc", NULL, }; | 38 | sys_unshare(CLONE_FS | CLONE_FILES); |
39 | extern const char *envp_init[]; | 39 | /* move initrd over / and chdir/chroot in initrd root */ |
40 | const char *shell = _shell; | 40 | sys_chdir("/root"); |
41 | 41 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | |
42 | sys_close(old_fd);sys_close(root_fd); | 42 | sys_chroot("."); |
43 | sys_setsid(); | 43 | sys_setsid(); |
44 | return kernel_execve(shell, argv, envp_init); | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | static void __init handle_initrd(void) | 47 | static void __init handle_initrd(void) |
48 | { | 48 | { |
49 | static char *argv[] = { "linuxrc", NULL, }; | ||
50 | extern char *envp_init[]; | ||
49 | int error; | 51 | int error; |
50 | int pid; | ||
51 | 52 | ||
52 | real_root_dev = new_encode_dev(ROOT_DEV); | 53 | real_root_dev = new_encode_dev(ROOT_DEV); |
53 | create_dev("/dev/root.old", Root_RAM0); | 54 | create_dev("/dev/root.old", Root_RAM0); |
54 | /* mount initrd on rootfs' /root */ | 55 | /* mount initrd on rootfs' /root */ |
55 | mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); | 56 | mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); |
56 | sys_mkdir("/old", 0700); | 57 | sys_mkdir("/old", 0700); |
57 | root_fd = sys_open("/", 0, 0); | 58 | sys_chdir("/old"); |
58 | old_fd = sys_open("/old", 0, 0); | ||
59 | /* move initrd over / and chdir/chroot in initrd root */ | ||
60 | sys_chdir("/root"); | ||
61 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||
62 | sys_chroot("."); | ||
63 | 59 | ||
64 | /* | 60 | /* |
65 | * In case that a resume from disk is carried out by linuxrc or one of | 61 | * In case that a resume from disk is carried out by linuxrc or one of |
@@ -67,27 +63,22 @@ static void __init handle_initrd(void) | |||
67 | */ | 63 | */ |
68 | current->flags |= PF_FREEZER_SKIP; | 64 | current->flags |= PF_FREEZER_SKIP; |
69 | 65 | ||
70 | pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); | 66 | call_usermodehelper_fns("/linuxrc", argv, envp_init, UMH_WAIT_PROC, |
71 | if (pid > 0) | 67 | init_linuxrc, NULL, NULL); |
72 | while (pid != sys_wait4(-1, NULL, 0, NULL)) | ||
73 | yield(); | ||
74 | 68 | ||
75 | current->flags &= ~PF_FREEZER_SKIP; | 69 | current->flags &= ~PF_FREEZER_SKIP; |
76 | 70 | ||
77 | /* move initrd to rootfs' /old */ | 71 | /* move initrd to rootfs' /old */ |
78 | sys_fchdir(old_fd); | 72 | sys_mount("..", ".", NULL, MS_MOVE, NULL); |
79 | sys_mount("/", ".", NULL, MS_MOVE, NULL); | ||
80 | /* switch root and cwd back to / of rootfs */ | 73 | /* switch root and cwd back to / of rootfs */ |
81 | sys_fchdir(root_fd); | 74 | sys_chroot(".."); |
82 | sys_chroot("."); | ||
83 | sys_close(old_fd); | ||
84 | sys_close(root_fd); | ||
85 | 75 | ||
86 | if (new_decode_dev(real_root_dev) == Root_RAM0) { | 76 | if (new_decode_dev(real_root_dev) == Root_RAM0) { |
87 | sys_chdir("/old"); | 77 | sys_chdir("/old"); |
88 | return; | 78 | return; |
89 | } | 79 | } |
90 | 80 | ||
81 | sys_chdir("/"); | ||
91 | ROOT_DEV = new_decode_dev(real_root_dev); | 82 | ROOT_DEV = new_decode_dev(real_root_dev); |
92 | mount_root(); | 83 | mount_root(); |
93 | 84 | ||
diff --git a/init/main.c b/init/main.c index 313360fe1118..9cf77ab138a6 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -69,6 +69,7 @@ | |||
69 | #include <linux/slab.h> | 69 | #include <linux/slab.h> |
70 | #include <linux/perf_event.h> | 70 | #include <linux/perf_event.h> |
71 | #include <linux/file.h> | 71 | #include <linux/file.h> |
72 | #include <linux/ptrace.h> | ||
72 | 73 | ||
73 | #include <asm/io.h> | 74 | #include <asm/io.h> |
74 | #include <asm/bugs.h> | 75 | #include <asm/bugs.h> |
@@ -791,17 +792,17 @@ static void __init do_pre_smp_initcalls(void) | |||
791 | do_one_initcall(*fn); | 792 | do_one_initcall(*fn); |
792 | } | 793 | } |
793 | 794 | ||
794 | static void run_init_process(const char *init_filename) | 795 | static int run_init_process(const char *init_filename) |
795 | { | 796 | { |
796 | argv_init[0] = init_filename; | 797 | argv_init[0] = init_filename; |
797 | kernel_execve(init_filename, argv_init, envp_init); | 798 | return kernel_execve(init_filename, argv_init, envp_init); |
798 | } | 799 | } |
799 | 800 | ||
800 | /* This is a non __init function. Force it to be noinline otherwise gcc | 801 | static void __init kernel_init_freeable(void); |
801 | * makes it inline to init() and it becomes part of init.text section | 802 | |
802 | */ | 803 | static int __ref kernel_init(void *unused) |
803 | static noinline int init_post(void) | ||
804 | { | 804 | { |
805 | kernel_init_freeable(); | ||
805 | /* need to finish all async __init code before freeing the memory */ | 806 | /* need to finish all async __init code before freeing the memory */ |
806 | async_synchronize_full(); | 807 | async_synchronize_full(); |
807 | free_initmem(); | 808 | free_initmem(); |
@@ -813,7 +814,8 @@ static noinline int init_post(void) | |||
813 | flush_delayed_fput(); | 814 | flush_delayed_fput(); |
814 | 815 | ||
815 | if (ramdisk_execute_command) { | 816 | if (ramdisk_execute_command) { |
816 | run_init_process(ramdisk_execute_command); | 817 | if (!run_init_process(ramdisk_execute_command)) |
818 | return 0; | ||
817 | printk(KERN_WARNING "Failed to execute %s\n", | 819 | printk(KERN_WARNING "Failed to execute %s\n", |
818 | ramdisk_execute_command); | 820 | ramdisk_execute_command); |
819 | } | 821 | } |
@@ -825,20 +827,22 @@ static noinline int init_post(void) | |||
825 | * trying to recover a really broken machine. | 827 | * trying to recover a really broken machine. |
826 | */ | 828 | */ |
827 | if (execute_command) { | 829 | if (execute_command) { |
828 | run_init_process(execute_command); | 830 | if (!run_init_process(execute_command)) |
831 | return 0; | ||
829 | printk(KERN_WARNING "Failed to execute %s. Attempting " | 832 | printk(KERN_WARNING "Failed to execute %s. Attempting " |
830 | "defaults...\n", execute_command); | 833 | "defaults...\n", execute_command); |
831 | } | 834 | } |
832 | run_init_process("/sbin/init"); | 835 | if (!run_init_process("/sbin/init") || |
833 | run_init_process("/etc/init"); | 836 | !run_init_process("/etc/init") || |
834 | run_init_process("/bin/init"); | 837 | !run_init_process("/bin/init") || |
835 | run_init_process("/bin/sh"); | 838 | !run_init_process("/bin/sh")) |
839 | return 0; | ||
836 | 840 | ||
837 | panic("No init found. Try passing init= option to kernel. " | 841 | panic("No init found. Try passing init= option to kernel. " |
838 | "See Linux Documentation/init.txt for guidance."); | 842 | "See Linux Documentation/init.txt for guidance."); |
839 | } | 843 | } |
840 | 844 | ||
841 | static int __init kernel_init(void * unused) | 845 | static void __init kernel_init_freeable(void) |
842 | { | 846 | { |
843 | /* | 847 | /* |
844 | * Wait until kthreadd is all set-up. | 848 | * Wait until kthreadd is all set-up. |
@@ -893,7 +897,4 @@ static int __init kernel_init(void * unused) | |||
893 | * we're essentially up and running. Get rid of the | 897 | * we're essentially up and running. Get rid of the |
894 | * initmem segments and start the user-mode stuff.. | 898 | * initmem segments and start the user-mode stuff.. |
895 | */ | 899 | */ |
896 | |||
897 | init_post(); | ||
898 | return 0; | ||
899 | } | 900 | } |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 6f99aead66c6..1c317e386831 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/notifier.h> | 37 | #include <linux/notifier.h> |
38 | #include <linux/suspend.h> | 38 | #include <linux/suspend.h> |
39 | #include <linux/rwsem.h> | 39 | #include <linux/rwsem.h> |
40 | #include <linux/ptrace.h> | ||
40 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
41 | 42 | ||
42 | #include <trace/events/module.h> | 43 | #include <trace/events/module.h> |
@@ -221,11 +222,13 @@ static int ____call_usermodehelper(void *data) | |||
221 | retval = kernel_execve(sub_info->path, | 222 | retval = kernel_execve(sub_info->path, |
222 | (const char *const *)sub_info->argv, | 223 | (const char *const *)sub_info->argv, |
223 | (const char *const *)sub_info->envp); | 224 | (const char *const *)sub_info->envp); |
225 | if (!retval) | ||
226 | return 0; | ||
224 | 227 | ||
225 | /* Exec failed? */ | 228 | /* Exec failed? */ |
226 | fail: | 229 | fail: |
227 | sub_info->retval = retval; | 230 | sub_info->retval = retval; |
228 | return 0; | 231 | do_exit(0); |
229 | } | 232 | } |
230 | 233 | ||
231 | static int call_helper(void *data) | 234 | static int call_helper(void *data) |
@@ -292,7 +295,7 @@ static int wait_for_helper(void *data) | |||
292 | } | 295 | } |
293 | 296 | ||
294 | umh_complete(sub_info); | 297 | umh_complete(sub_info); |
295 | return 0; | 298 | do_exit(0); |
296 | } | 299 | } |
297 | 300 | ||
298 | /* This is run by khelper thread */ | 301 | /* This is run by khelper thread */ |
diff --git a/kernel/kthread.c b/kernel/kthread.c index 146a6fa96825..29fb60caecb5 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/freezer.h> | 18 | #include <linux/freezer.h> |
19 | #include <linux/ptrace.h> | ||
19 | #include <trace/events/sched.h> | 20 | #include <trace/events/sched.h> |
20 | 21 | ||
21 | static DEFINE_SPINLOCK(kthread_create_lock); | 22 | static DEFINE_SPINLOCK(kthread_create_lock); |