diff options
author | David S. Miller <davem@davemloft.net> | 2008-05-07 19:21:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-05-07 19:21:28 -0400 |
commit | 1e38c126c9252b612697e34f43b1b3371c8ee31d (patch) | |
tree | 32f4d7635b9acb3c1210d46193ca777021fd52a3 /arch/sparc64/kernel | |
parent | 5816339310b2d9623cf413d33e538b45e815da5d (diff) |
sparc: Fix fork/clone/vfork system call restart.
We clobber %i1 as well as %i0 for these system calls,
because they give two return values.
Therefore, on error, we have to restore %i1 properly
or else the restart explodes since it uses the wrong
arguments.
This fixes glibc's nptl/tst-eintr1.c testcase.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r-- | arch/sparc64/kernel/process.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 500ac6d483a0..4129c0449856 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
@@ -503,6 +503,8 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags, | |||
503 | unsigned long stack_size) | 503 | unsigned long stack_size) |
504 | { | 504 | { |
505 | int __user *parent_tid_ptr, *child_tid_ptr; | 505 | int __user *parent_tid_ptr, *child_tid_ptr; |
506 | unsigned long orig_i1 = regs->u_regs[UREG_I1]; | ||
507 | long ret; | ||
506 | 508 | ||
507 | #ifdef CONFIG_COMPAT | 509 | #ifdef CONFIG_COMPAT |
508 | if (test_thread_flag(TIF_32BIT)) { | 510 | if (test_thread_flag(TIF_32BIT)) { |
@@ -515,9 +517,19 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags, | |||
515 | child_tid_ptr = (int __user *) regs->u_regs[UREG_I4]; | 517 | child_tid_ptr = (int __user *) regs->u_regs[UREG_I4]; |
516 | } | 518 | } |
517 | 519 | ||
518 | return do_fork(clone_flags, stack_start, | 520 | ret = do_fork(clone_flags, stack_start, |
519 | regs, stack_size, | 521 | regs, stack_size, |
520 | parent_tid_ptr, child_tid_ptr); | 522 | parent_tid_ptr, child_tid_ptr); |
523 | |||
524 | /* If we get an error and potentially restart the system | ||
525 | * call, we're screwed because copy_thread() clobbered | ||
526 | * the parent's %o1. So detect that case and restore it | ||
527 | * here. | ||
528 | */ | ||
529 | if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) | ||
530 | regs->u_regs[UREG_I1] = orig_i1; | ||
531 | |||
532 | return ret; | ||
521 | } | 533 | } |
522 | 534 | ||
523 | /* Copy a Sparc thread. The fork() return value conventions | 535 | /* Copy a Sparc thread. The fork() return value conventions |