patch-2.1.127 linux/arch/sparc64/kernel/ptrace.c

Next file: linux/arch/sparc64/kernel/rtrap.S
Previous file: linux/arch/sparc64/kernel/psycho.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
@@ -43,6 +43,12 @@
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
+
+	/* Seems non-intuitive but the page copy/clear routines always
+	 * check current's value.
+	 */
+	current->mm->segments = (void *) (addr & PAGE_SIZE);
+
 	if (pgd_none(*pgdir)) {
 		handle_mm_fault(tsk, vma, addr, write);
 		goto repeat;
@@ -574,7 +580,11 @@
 		goto out;
 	}
 #endif
-	if(!(child = find_task_by_pid(pid))) {
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);
+
+	if(!child) {
 		pt_error_return(regs, ESRCH);
 		goto out;
 	}
@@ -604,9 +614,13 @@
 		}
 		child->flags |= PF_PTRACED;
 		if(child->p_pptr != current) {
+			unsigned long flags;
+
+			write_lock_irqsave(&tasklist_lock, flags);
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
+			write_unlock_irqrestore(&tasklist_lock, flags);
 		}
 		send_sig(SIGSTOP, child, 1);
 		pt_succ_return(regs, 0);
@@ -781,11 +795,12 @@
 			cregs->tnpc = npc;
 		}
 		cregs->y = y;
-		for(i = 1; i < 16; i++)
+		for(i = 1; i < 16; i++) {
 			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
 				pt_error_return(regs, EFAULT);
 				goto out;
 			}
+		}
 		pt_succ_return(regs, 0);
 		goto out;
 	}
@@ -814,11 +829,12 @@
 			cregs->tnpc = tnpc;
 		}
 		cregs->y = y;
-		for(i = 1; i < 16; i++)
+		for(i = 1; i < 16; i++) {
 			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
 				pt_error_return(regs, EFAULT);
 				goto out;
 			}
+		}
 		pt_succ_return(regs, 0);
 		goto out;
 	}
@@ -1055,23 +1071,29 @@
 			pt_succ_return(regs, 0);
 			goto out;
 		}
-		wake_up_process(child);
 		child->exit_code = SIGKILL;
+		wake_up_process(child);
 		pt_succ_return(regs, 0);
 		goto out;
 	}
 
 	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+		unsigned long flags;
+
 		if ((unsigned long) data > _NSIG) {
 			pt_error_return(regs, EIO);
 			goto out;
 		}
 		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-		wake_up_process(child);
 		child->exit_code = data;
+
+		write_lock_irqsave(&tasklist_lock, flags);
 		REMOVE_LINKS(child);
 		child->p_pptr = child->p_opptr;
 		SET_LINKS(child);
+		write_unlock_irqrestore(&tasklist_lock, flags);
+
+		wake_up_process(child);
 		pt_succ_return(regs, 0);
 		goto out;
 	}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov