]> git.neil.brown.name Git - history.git/commitdiff
[ALPHA] Fix SETTLS -- read TLS value to install before clobbering it.
authorRichard Henderson <rth@kanga.twiddle.net>
Mon, 30 Jun 2003 08:39:11 +0000 (01:39 -0700)
committerRichard Henderson <rth@kanga.twiddle.net>
Mon, 30 Jun 2003 08:39:11 +0000 (01:39 -0700)
arch/alpha/kernel/process.c

index 473a4adf767f108acf2d3e6e7cb4ddabd5bfd4b8..497d9057be51063ab81463df93941c110cf29467 100644 (file)
@@ -270,7 +270,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        struct thread_info *childti = p->thread_info;
        struct pt_regs * childregs;
        struct switch_stack * childstack, *stack;
-       unsigned long stack_offset;
+       unsigned long stack_offset, settls;
 
        stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
        if (!(regs->ps & 8))
@@ -279,6 +279,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
          (stack_offset + PAGE_SIZE + (long) childti);
                
        *childregs = *regs;
+       settls = regs->r20;
        childregs->r0 = 0;
        childregs->r19 = 0;
        childregs->r20 = 1;     /* OSF/1 has some strange fork() semantics.  */
@@ -292,14 +293,16 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        childti->pcb.flags = 1; /* set FEN, clear everything else */
 
        /* Set a new TLS for the child thread?  Peek back into the
-          syscall arguments that we saved on syscall entry.  */
+          syscall arguments that we saved on syscall entry.  Oops,
+          except we'd have clobbered it with the parent/child set
+          of r20.  Read the saved copy.  */
        /* Note: if CLONE_SETTLS is not set, then we must inherit the
           value from the parent, which will have been set by the block
           copy in dup_task_struct.  This is non-intuitive, but is
           required for proper operation in the case of a threaded
           application calling fork.  */
        if (clone_flags & CLONE_SETTLS)
-               childti->pcb.unique = regs->r20;
+               childti->pcb.unique = settls;
 
        return 0;
 }