aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-05-07 19:21:28 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-07 19:21:28 -0400
commit1e38c126c9252b612697e34f43b1b3371c8ee31d (patch)
tree32f4d7635b9acb3c1210d46193ca777021fd52a3 /arch/sparc64/kernel
parent5816339310b2d9623cf413d33e538b45e815da5d (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.c18
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