## Automatically generated incremental diff
## From:   linux-2.4.7-pre9
## To:     linux-2.4.7
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.7-pre9/Makefile linux/Makefile
--- linux-2.4.7-pre9/Makefile	Mon Dec  3 22:57:00 2001
+++ linux/Makefile	Mon Dec  3 22:57:10 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 7
-EXTRAVERSION =-pre9
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.7-pre9/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/alpha/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/alpha/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -264,32 +264,7 @@
 	if (!child)
 		goto out_notsk;
 	if (request == PTRACE_ATTACH) {
-		ret = -EPERM;
-		if (child == current)
-			goto out;
-		if ((!child->mm->dumpable ||
-		     (current->uid != child->euid) ||
-		     (current->uid != child->suid) ||
-		     (current->uid != child->uid) ||
-		     (current->gid != child->egid) ||
-		     (current->gid != child->sgid) ||
-		     (current->gid != child->gid) ||
-		     (!cap_issubset(child->cap_permitted, current->cap_permitted)))
-		    && !capable(CAP_SYS_PTRACE))
-			goto out;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out;
-		child->ptrace |= PT_PTRACED;
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/arm/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/arm/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -594,32 +594,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-		    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/cris/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/cris/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -115,32 +115,7 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out_tsk;
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-		    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/i386/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/i386/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -165,34 +165,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if(((current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		rmb();
-		if (!child->mm->dumpable && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/ia64/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/ia64/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -768,32 +768,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-		    (current->gid != child->egid) ||
-		    (current->gid != child->sgid) ||
-		    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-		    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_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);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/m68k/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/m68k/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -118,32 +118,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-		    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irqsave(&tasklist_lock, flags);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irqrestore(&tasklist_lock, flags);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/mips/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/mips/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -66,34 +66,7 @@
 		goto out;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-		    (current->gid != child->sgid) ||
-	 	    (current->gid != child->gid) ||
-		    (!cap_issubset(child->cap_permitted,
-		                  current->cap_permitted)) ||
-                    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		res = 0;
+		res = ptrace_attach(child);
 		goto out_tsk;
 	}
 	res = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/mips64/kernel/ptrace.c linux/arch/mips64/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/mips64/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/mips64/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -62,32 +62,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
@@ -336,32 +311,7 @@
 		goto out;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/parisc/kernel/ptrace.c linux/arch/parisc/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/parisc/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/parisc/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -61,32 +61,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_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);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/ppc/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/ppc/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -118,33 +118,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out_tsk;
-		if ((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-		    (current->gid != child->sgid) ||
-		    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-		    (current->gid != child->gid))
-		    && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/s390/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/s390/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -233,31 +233,7 @@
 		goto out;
 	if (request == PTRACE_ATTACH) 
 	{
-		if (child == current)
-			goto out;
-		if ((!child->mm->dumpable ||
-		     (current->uid != child->euid) ||
-		     (current->uid != child->suid) ||
-		     (current->uid != child->uid) ||
-		     (current->gid != child->egid) ||
-		     (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
-			goto out;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irqsave(&tasklist_lock, flags);
-		if (child->p_pptr != current) 
-		{
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irqrestore(&tasklist_lock, flags);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/s390x/kernel/ptrace.c linux/arch/s390x/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/s390x/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/s390x/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -247,31 +247,7 @@
 		goto out;
 	if (request == PTRACE_ATTACH) 
 	{
-		if (child == current)
-			goto out;
-		if ((!child->mm->dumpable ||
-		     (current->uid != child->euid) ||
-		     (current->uid != child->suid) ||
-		     (current->uid != child->uid) ||
-		     (current->gid != child->egid) ||
-		     (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
-			goto out;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irqsave(&tasklist_lock, flags);
-		if (child->p_pptr != current) 
-		{
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irqrestore(&tasklist_lock, flags);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out;
 	}
 	ret = -ESRCH;
@@ -433,31 +409,7 @@
 		goto out;
 	if (request == PTRACE_ATTACH) 
 	{
-		if (child == current)
-			goto out;
-		if ((!child->mm->dumpable ||
-		     (current->uid != child->euid) ||
-		     (current->uid != child->suid) ||
-		     (current->uid != child->uid) ||
-		     (current->gid != child->egid) ||
-		     (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
-			goto out;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irqsave(&tasklist_lock, flags);
-		if (child->p_pptr != current) 
-		{
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		write_unlock_irqrestore(&tasklist_lock, flags);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/sh/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/sh/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -173,34 +173,7 @@
 		goto out_tsk;
 
 	if (request == PTRACE_ATTACH) {
-		if (child == tsk)
-			goto out_tsk;
-		if(((tsk->uid != child->euid) ||
-		    (tsk->uid != child->suid) ||
-		    (tsk->uid != child->uid) ||
-	 	    (tsk->gid != child->egid) ||
-	 	    (tsk->gid != child->sgid) ||
-	 	    (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) ||
-	 	    (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		rmb();
-		if (!child->mm->dumpable && !capable(CAP_SYS_PTRACE))
-			goto out_tsk;
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED)
-			goto out_tsk;
-		child->ptrace |= PT_PTRACED;
-
-		write_lock_irq(&tasklist_lock);
-		if (child->p_pptr != tsk) {
-			REMOVE_LINKS(child);
-			child->p_pptr = tsk;
-			SET_LINKS(child);
-		}
-		write_unlock_irq(&tasklist_lock);
-
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
+		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
 	ret = -ESRCH;
diff -urN linux-2.4.7-pre9/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/sparc/kernel/ptrace.c	Mon Dec  3 22:57:00 2001
+++ linux/arch/sparc/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -320,38 +320,10 @@
 	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
 		unsigned long flags;
 
-		if(child == current) {
-			/* Try this under SunOS/Solaris, bwa haha
-			 * You'll never be able to kill the process. ;-)
-			 */
+		if (ptrace_attach(child)) {
 			pt_error_return(regs, EPERM);
 			goto out_tsk;
 		}
-		if((!child->mm->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->uid) ||
-		    (current->uid != child->suid) ||
-		    (current->gid != child->egid) ||
-		    (current->gid != child->sgid) || 
-	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-		    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
-			pt_error_return(regs, EPERM);
-			goto out_tsk;
-		}
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED) {
-			pt_error_return(regs, EPERM);
-			goto out_tsk;
-		}
-		child->ptrace |= PT_PTRACED;
-		write_lock_irqsave(&tasklist_lock, flags);
-		if(child->p_pptr != current) {
-			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);
 		goto out_tsk;
 	}
diff -urN linux-2.4.7-pre9/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.4.7-pre9/arch/sparc64/config.in	Mon Dec  3 22:57:01 2001
+++ linux/arch/sparc64/config.in	Mon Dec  3 22:57:10 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.147 2001/07/18 07:52:34 davem Exp $
+# $Id: config.in,v 1.148 2001/07/20 07:10:35 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -207,7 +207,9 @@
 endmenu
 
 source drivers/fc4/Config.in
+
 source drivers/message/fusion/Config.in
+
 source drivers/ieee1394/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
diff -urN linux-2.4.7-pre9/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.4.7-pre9/arch/sparc64/defconfig	Mon Dec  3 22:57:01 2001
+++ linux/arch/sparc64/defconfig	Mon Dec  3 22:57:10 2001
@@ -364,13 +364,23 @@
 CONFIG_NET_FC=y
 
 #
-# IEEE 1394 (FireWire) support
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
 #
 CONFIG_IEEE1394=m
+
+#
+# Device Drivers
+#
 CONFIG_IEEE1394_PCILYNX=m
 # CONFIG_IEEE1394_PCILYNX_LOCALRAM is not set
 # CONFIG_IEEE1394_PCILYNX_PORTS is not set
 CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+# CONFIG_IEEE1394_VIDEO1394 is not set
+CONFIG_IEEE1394_SBP2=m
 CONFIG_IEEE1394_RAWIO=m
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 
diff -urN linux-2.4.7-pre9/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- linux-2.4.7-pre9/arch/sparc64/kernel/ptrace.c	Mon Dec  3 22:57:01 2001
+++ linux/arch/sparc64/kernel/ptrace.c	Mon Dec  3 22:57:10 2001
@@ -170,38 +170,10 @@
 	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
 		unsigned long flags;
 
-		if (child == current) {
-			/* Try this under SunOS/Solaris, bwa haha
-			 * You'll never be able to kill the process. ;-)
-			 */
+		if (ptrace_attach(child)) {
 			pt_error_return(regs, EPERM);
 			goto out_tsk;
 		}
-		if ((!child->mm->dumpable ||
-		     (current->uid != child->euid) ||
-		     (current->uid != child->uid) ||
-		     (current->uid != child->suid) ||
-		     (current->gid != child->egid) ||
-		     (current->gid != child->sgid) ||
-		     (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-		     (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
-			pt_error_return(regs, EPERM);
-			goto out_tsk;
-		}
-		/* the same process cannot be attached many times */
-		if (child->ptrace & PT_PTRACED) {
-			pt_error_return(regs, EPERM);
-			goto out_tsk;
-		}
-		child->ptrace |= PT_PTRACED;
-		write_lock_irqsave(&tasklist_lock, flags);
-		if (child->p_pptr != current) {
-			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);
 		goto out_tsk;
 	}
diff -urN linux-2.4.7-pre9/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- linux-2.4.7-pre9/drivers/ide/ide-tape.c	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ide/ide-tape.c	Mon Dec  3 22:57:10 2001
@@ -419,6 +419,7 @@
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/smp_lock.h>
+#include <linux/completion.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -978,7 +979,7 @@
 	int logical_blk_num;			/* logical block number */
 	__u16 wrt_pass_cntr;			/* write pass counter */
 	__u32 update_frame_cntr;		/* update frame counter */
-	struct semaphore *sem;
+	struct completion *waiting;
 	int onstream_write_error;		/* write error recovery active */
 	int header_ok;				/* header frame verified ok */
 	int linux_media;			/* reading linux-specifc media */
@@ -1886,8 +1887,8 @@
 						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->sem)
-						up(tape->sem);
+					if (tape->waiting)
+						complete(tape->waiting);
 				}
 			}
 			remove_stage = 1;
@@ -1903,8 +1904,8 @@
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->sem)
-						up(tape->sem);
+					if (tape->waiting)
+						complete(tape->waiting);
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
@@ -3064,15 +3065,15 @@
 }
 
 /*
- *	idetape_wait_for_request installs a semaphore in a pending request
+ *	idetape_wait_for_request installs a completion in a pending request
  *	and sleeps until it is serviced.
  *
  *	The caller should ensure that the request will not be serviced
- *	before we install the semaphore (usually by disabling interrupts).
+ *	before we install the completion (usually by disabling interrupts).
  */
 static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
 {
-	DECLARE_MUTEX_LOCKED(sem);
+	DECLARE_COMPLETION(wait);
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
@@ -3081,12 +3082,12 @@
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
-	rq->sem = &sem;
-	tape->sem = &sem;
+	rq->waiting = &wait;
+	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
-	down(&sem);
-	rq->sem = NULL;
-	tape->sem = NULL;
+	wait_for_completion(&wait);
+	rq->waiting = NULL;
+	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
 
diff -urN linux-2.4.7-pre9/drivers/ieee1394/Makefile linux/drivers/ieee1394/Makefile
--- linux-2.4.7-pre9/drivers/ieee1394/Makefile	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ieee1394/Makefile	Mon Dec  3 22:57:10 2001
@@ -8,7 +8,7 @@
 
 list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-		 highlevel.o csr.o guid.o ieee1394_syms.o
+		 highlevel.o csr.o nodemgr.o ieee1394_syms.o
 
 obj-$(CONFIG_IEEE1394) += ieee1394.o
 obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
@@ -16,8 +16,6 @@
 obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
 obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
 obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
-obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-obj-$(CONFIG_IEEE1394_IP1394) += ip1394.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.7-pre9/drivers/ieee1394/guid.c linux/drivers/ieee1394/guid.c
--- linux-2.4.7-pre9/drivers/ieee1394/guid.c	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ieee1394/guid.c	Wed Dec 31 16:00:00 1969
@@ -1,305 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * GUID collection and management
- *
- * Copyright (C) 2000 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-
-#include "ieee1394_types.h"
-#include "ieee1394.h"
-#include "hosts.h"
-#include "ieee1394_transactions.h"
-#include "highlevel.h"
-#include "csr.h"
-
-
-static atomic_t outstanding_requests;
-
-static LIST_HEAD(guid_list);
-rwlock_t guid_lock = RW_LOCK_UNLOCKED;
-
-struct guid_entry {
-        struct list_head list;
-        atomic_t refcount;
-
-        u64 guid;
-
-        struct hpsb_host *host;
-        nodeid_t node_id;
-        
-        atomic_t generation;
-};
-
-struct guid_req {
-	struct hpsb_packet *pkt;
-	int retry;
-	unsigned int hdr_size;
-	int hdr_ptr;
-	u32 bus_info[5];
-	struct tq_struct tq;
-};
-
-static struct guid_entry *create_guid_entry(void)
-{
-        struct guid_entry *ge;
-        unsigned long flags;
-
-        ge = kmalloc(sizeof(struct guid_entry), SLAB_ATOMIC);
-        if (!ge) return NULL;
-
-        INIT_LIST_HEAD(&ge->list);
-        atomic_set(&ge->refcount, 0);
-        ge->guid = (u64) -1;
-        ge->host = NULL;
-        ge->node_id = 0;
-        atomic_set(&ge->generation, -1);
-
-        write_lock_irqsave(&guid_lock, flags);
-        list_add_tail(&ge->list, &guid_list);
-        write_unlock_irqrestore(&guid_lock, flags);
-
-        return ge;
-}
-
-static struct guid_entry *find_entry(u64 guid)
-{
-        struct list_head *lh;
-        struct guid_entry *ge;
-        
-        lh = guid_list.next;
-        while (lh != &guid_list) {
-                ge = list_entry(lh, struct guid_entry, list);
-                if (ge->guid == guid) return ge;
-                lh = lh->next;
-        }
-
-        return NULL;
-}
-
-static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid)
-{
-        struct guid_entry *ge;
-        unsigned long flags;
-
-        HPSB_DEBUG("Node %d on %s host: GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-                   nodeid & NODE_MASK, host->template->name, ((u8 *)&guid)[0],
-		   ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3],
-		   ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6],
-		   ((u8 *)&guid)[7]);
-
-        read_lock_irqsave(&guid_lock, flags);
-        ge = find_entry(guid);
-        read_unlock_irqrestore(&guid_lock, flags);
-
-        if (!ge) ge = create_guid_entry();
-        if (!ge) return;
-
-        ge->host = host;
-        ge->node_id = nodeid;
-        ge->guid = guid;
-
-        atomic_set(&ge->generation, get_hpsb_generation());
-}
-
-static void pkt_complete(struct guid_req *req)
-{
-        struct hpsb_packet *pkt = req->pkt;
-	struct hpsb_host *host = pkt->host;
-	nodeid_t nodeid = pkt->node_id;
-
-	if (hpsb_packet_success (pkt)) {
-		HPSB_ERR("GUID quadlet transaction error for %d, retry: %d", nodeid,
-			 req->retry);
-		req->retry++;
-		if (req->retry > 3)
-			goto finish;
-		else
-			goto retry;
-        }
-
-	/* Copy our received quadlet */
-	req->bus_info[req->hdr_ptr++] = be32_to_cpu(pkt->header[3]);
-
-	/* First quadlet, let's get some info */
-	if (req->hdr_ptr == 1) {
-		/* Get the bus_info_length from first quadlet */
-		req->hdr_size = req->bus_info[0] >> 24;
-
-		/* Make sure this isn't one of those minimal proprietary
-		 * ROMs. IMO, we should just barf all over them. We need
-		 * atleast four bus_info quads to get our EUI-64.  */
-		if (req->hdr_size < 4) {
-			HPSB_INFO("Node %d on %s host has non-standard ROM format (%d quads), "
-				  "cannot parse", nodeid, host->template->name, req->hdr_size);
-			goto finish;
-		}
-
-		/* Make sure we don't overflow. We have one quad for this
-		 * first bus info block, the other 4 should be part of the
-		 * bus info itself.  */
-		if (req->hdr_size > (sizeof (req->bus_info) >> 2) - 1)
-			req->hdr_size = (sizeof (req->bus_info) >> 2) - 1;
-	}
-
-	/* We've got all the info we need, so let's check the EUI-64, and
-	 * add it to our list.  */
-	if (req->hdr_ptr >= req->hdr_size + 1) {
-		associate_guid(pkt->host, pkt->node_id,
-			((u64)req->bus_info[3] << 32) | req->bus_info[4]);
-		goto finish;
-	}
-
-retry:
-
-	/* Here, we either retry a failed retrieve, or we have incremented
-	 * our counter, to get the next quad in our header.  */
-	free_tlabel(pkt->host, pkt->node_id, pkt->tlabel);
-	free_hpsb_packet(pkt);
-	pkt = hpsb_make_readqpacket(host, nodeid, CSR_REGISTER_BASE +
-				    CSR_CONFIG_ROM + (req->hdr_ptr<<2));
-	if (!pkt) {
-		kfree(req);
-		HPSB_ERR("Out of memory in GUID processing");
-		return;
-	}
-
-	req->pkt = pkt;
-	req->retry = 0;
-
-	queue_task(&req->tq, &pkt->complete_tq);
-	if (!hpsb_send_packet(pkt)) {
-		HPSB_NOTICE("Failed to send GUID request to node %d", nodeid);
-		goto finish;
-	}
-
-	return;
-
-finish:
-
-	free_tlabel(pkt->host, nodeid, pkt->tlabel);
-	free_hpsb_packet(pkt);
-	kfree(req);
-
-	if (atomic_dec_and_test(&outstanding_requests)) {
-		/* Do something useful */
-	}
-
-	return;
-}
-
-
-static void host_reset(struct hpsb_host *host)
-{
-        struct guid_req *greq;
-        struct hpsb_packet *pkt;
-        struct selfid *sid = (struct selfid *)host->topology_map;
-        int nodecount = host->node_count;
-        nodeid_t nodeid = LOCAL_BUS;
-
-        for (; nodecount; nodecount--, nodeid++, sid++) {
-                while (sid->extended)
-			sid++;
-                if (!sid->link_active)
-			continue;
-		if (nodeid == host->node_id)
-			continue;
-
-                greq = kmalloc(sizeof(struct guid_req), SLAB_ATOMIC);
-                if (!greq) {
-                        HPSB_ERR("Out of memory in GUID processing");
-                        return;
-                }
-
-		pkt = hpsb_make_readqpacket(host, nodeid, CSR_REGISTER_BASE +
-					    CSR_CONFIG_ROM);
-
-                if (!pkt) {
-                        kfree(greq);
-                        HPSB_ERR("Out of memory in GUID processing");
-                        return;
-                }
-
-		INIT_TQUEUE(&greq->tq, (void (*)(void*))pkt_complete, greq);
-
-		greq->hdr_size = 4;
-		greq->hdr_ptr = 0;
-		greq->retry = 0;
-                greq->pkt = pkt;
-
-                queue_task(&greq->tq, &pkt->complete_tq);
-
-                if (!hpsb_send_packet(pkt)) {
-                        free_tlabel(pkt->host, pkt->node_id, pkt->tlabel);
-                        free_hpsb_packet(pkt);
-                        kfree(greq);
-                        HPSB_NOTICE("Failed to send GUID request to node %d", nodeid);
-                }
-
-		HPSB_DEBUG("GUID request sent to node %d", nodeid & NODE_MASK);
-
-                atomic_inc(&outstanding_requests);
-        }
-}
-
-
-struct guid_entry *hpsb_guid_get_handle(u64 guid)
-{
-        unsigned long flags;
-        struct guid_entry *ge;
-
-        read_lock_irqsave(&guid_lock, flags);
-        ge = find_entry(guid);
-        if (ge) atomic_inc(&ge->refcount);
-        read_unlock_irqrestore(&guid_lock, flags);
-
-        return ge;
-}
-
-struct hpsb_host *hpsb_guid_localhost(struct guid_entry *ge)
-{
-        if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL;
-        if (ge->node_id == ge->host->node_id) return ge->host;
-        return NULL;
-}
-
-int hpsb_guid_fill_packet(struct guid_entry *ge, struct hpsb_packet *pkt)
-{
-        if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0;
-
-        pkt->host = ge->host;
-        pkt->node_id = ge->node_id;
-        pkt->generation = atomic_read(&ge->generation);
-        return 1;
-}
-
-
-static struct hpsb_highlevel_ops guid_ops = {
-        host_reset:  host_reset,
-};
-
-static struct hpsb_highlevel *hl;
-
-void init_ieee1394_guid(void)
-{
-        atomic_set(&outstanding_requests, 0);
-
-        hl = hpsb_register_highlevel("GUID manager", &guid_ops);
-        if (!hl) {
-                HPSB_ERR("out of memory during ieee1394 initialization");
-        }
-}
-
-void cleanup_ieee1394_guid(void)
-{
-        hpsb_unregister_highlevel(hl);
-}
diff -urN linux-2.4.7-pre9/drivers/ieee1394/guid.h linux/drivers/ieee1394/guid.h
--- linux-2.4.7-pre9/drivers/ieee1394/guid.h	Thu Mar  1 16:57:11 2001
+++ linux/drivers/ieee1394/guid.h	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-
-#ifndef _IEEE1394_GUID_H
-#define _IEEE1394_GUID_H
-
-
-/*
- * General information: Finding out which GUID belongs to which node is done by
- * sending packets and therefore waiting for the answers.  Wherever it is
- * mentioned that a node is inaccessible this could just as well mean that we
- * just don't know yet (usually, bus reset handlers can't rely on GUIDs being
- * associated with current nodes).
- */
-
-struct guid_entry;
-typedef struct guid_entry *hpsb_guid_t;
-
-
-/*
- * Returns a guid handle (which has its reference count incremented) or NULL if
- * there is the GUID in question is not known of.  Getting a valid handle does
- * not mean that the node with this GUID is currently accessible (might not be
- * plugged in or powered down).
- */
-hpsb_guid_t hpsb_guid_get_handle(u64 guid);
-
-/*
- * If the handle refers to a local host, this function will return the pointer
- * to the hpsb_host structure.  It will return NULL otherwise.  Once you have
- * established it is a local host, you can use that knowledge from then on (the
- * GUID won't wander to an external node).
- *
- * Note that the local GUID currently isn't collected, so this will always
- * return NULL.
- */
-struct hpsb_host *hpsb_guid_localhost(hpsb_guid_t handle);
-
-/*
- * This will fill in the given, pre-initialised hpsb_packet with the current
- * information from the GUID handle (host, node ID, generation number).  It will
- * return false if the node owning the GUID is not accessible (and not modify the 
- * hpsb_packet) and return true otherwise.
- *
- * Note that packet sending may still fail in hpsb_send_packet if a bus reset
- * happens while you are trying to set up the packet (due to obsolete generation
- * number).  It will at least reliably fail so that you don't accidentally and
- * unknowingly send your packet to the wrong node.
- */
-int hpsb_guid_fill_packet(hpsb_guid_t handle, struct hpsb_packet *pkt);
-
-
-void init_ieee1394_guid(void);
-void cleanup_ieee1394_guid(void);
-
-#endif /* _IEEE1394_GUID_H */
diff -urN linux-2.4.7-pre9/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.7-pre9/drivers/ieee1394/ieee1394_core.c	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Mon Dec  3 22:57:10 2001
@@ -29,7 +29,7 @@
 #include "highlevel.h"
 #include "ieee1394_transactions.h"
 #include "csr.h"
-#include "guid.h"
+#include "nodemgr.h"
 
 
 atomic_t hpsb_generation = ATOMIC_INIT(0);
@@ -782,13 +782,13 @@
 {
         init_hpsb_highlevel();
         init_csr();
-        init_ieee1394_guid();
+        init_ieee1394_nodemgr();
 	return 0;
 }
 
 static void __exit ieee1394_cleanup(void)
 {
-        cleanup_ieee1394_guid();
+        cleanup_ieee1394_nodemgr();
         cleanup_csr();
 }
 
diff -urN linux-2.4.7-pre9/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- linux-2.4.7-pre9/drivers/ieee1394/ieee1394_syms.c	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ieee1394/ieee1394_syms.c	Mon Dec  3 22:57:10 2001
@@ -18,7 +18,7 @@
 #include "ieee1394_core.h"
 #include "ieee1394_transactions.h"
 #include "highlevel.h"
-#include "guid.h"
+#include "nodemgr.h"
 
 EXPORT_SYMBOL(hpsb_register_lowlevel);
 EXPORT_SYMBOL(hpsb_unregister_lowlevel);
@@ -76,5 +76,5 @@
 EXPORT_SYMBOL(highlevel_host_reset);
 EXPORT_SYMBOL(highlevel_add_one_host);
 EXPORT_SYMBOL(hpsb_guid_get_handle);
-EXPORT_SYMBOL(hpsb_guid_localhost);
+EXPORT_SYMBOL(hpsb_get_host_by_ge);
 EXPORT_SYMBOL(hpsb_guid_fill_packet);
diff -urN linux-2.4.7-pre9/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- linux-2.4.7-pre9/drivers/ieee1394/nodemgr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ieee1394/nodemgr.c	Mon Dec  3 22:57:10 2001
@@ -0,0 +1,391 @@
+/*
+ * Node information (ConfigROM) collection and management.
+ *
+ * Copyright (C) 2000 Andreas E. Bombe
+ *               2001 Ben Collins <bcollins@debian.net>
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+
+#include "ieee1394_types.h"
+#include "ieee1394.h"
+#include "hosts.h"
+#include "ieee1394_transactions.h"
+#include "highlevel.h"
+#include "csr.h"
+
+
+/* Basically what we do here is start off retrieving the bus_info block.
+ * From there will fill in some info about the node, verify it is of IEEE
+ * 1394 type, and the the crc checks out ok. After that we start off with
+ * the root directory, and subdirectories. To do this, we retrieve the
+ * quadlet header for a directory, find out the length, and retrieve the
+ * complete directory entry (be it a leaf or a directory). We then process
+ * it and add the info to our structure for that particular node.
+ *
+ * We verify CRC's along the way for each directory/block/leaf. The
+ * entire node structure is generic, and simply stores the information in
+ * a way that's easy to parse by the protocol interface.
+ *
+ * XXX: Most of this isn't done yet :)  */
+
+
+static atomic_t outstanding_requests;
+
+static LIST_HEAD(node_list);
+rwlock_t node_lock = RW_LOCK_UNLOCKED;
+
+static LIST_HEAD(host_info_list);
+spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
+
+struct host_info {
+	struct hpsb_host *host;
+	int pid;
+	wait_queue_head_t reset_wait;
+	struct list_head list;
+};
+
+struct node_entry {
+        struct list_head list;
+        atomic_t refcount;
+
+        u64 guid;
+
+        struct hpsb_host *host;
+        nodeid_t node_id;
+        
+        atomic_t generation;
+};
+
+static struct node_entry *create_node_entry(void)
+{
+        struct node_entry *ge;
+        unsigned long flags;
+
+        ge = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
+        if (!ge) return NULL;
+
+        INIT_LIST_HEAD(&ge->list);
+        atomic_set(&ge->refcount, 0);
+        ge->guid = (u64) -1;
+        ge->host = NULL;
+        ge->node_id = 0;
+        atomic_set(&ge->generation, -1);
+
+        write_lock_irqsave(&node_lock, flags);
+        list_add_tail(&ge->list, &node_list);
+        write_unlock_irqrestore(&node_lock, flags);
+
+        return ge;
+}
+
+static struct node_entry *find_entry(u64 guid)
+{
+        struct list_head *lh;
+        struct node_entry *ge;
+        
+        lh = node_list.next;
+        while (lh != &node_list) {
+                ge = list_entry(lh, struct node_entry, list);
+                if (ge->guid == guid) return ge;
+                lh = lh->next;
+        }
+
+        return NULL;
+}
+
+static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid)
+{
+        struct node_entry *ge;
+        unsigned long flags;
+
+        HPSB_DEBUG("Node %d on %s host: GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+                   nodeid & NODE_MASK, host->template->name, ((u8 *)&guid)[0],
+		   ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3],
+		   ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6],
+		   ((u8 *)&guid)[7]);
+
+        read_lock_irqsave(&node_lock, flags);
+        ge = find_entry(guid);
+        read_unlock_irqrestore(&node_lock, flags);
+
+        if (!ge) ge = create_node_entry();
+        if (!ge) return;
+
+        ge->host = host;
+        ge->node_id = nodeid;
+        ge->guid = guid;
+
+        atomic_set(&ge->generation, get_hpsb_generation());
+}
+
+/* This is where we probe the nodes for their information and provided
+ * features.  */
+static void nodemgr_node_probe(struct hpsb_host *host)
+{
+        struct selfid *sid = (struct selfid *)host->topology_map;
+        int nodecount = host->node_count;
+        nodeid_t nodeid = LOCAL_BUS;
+	quadlet_t buffer[5], quad;
+	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
+	int retval;
+
+	/* We need to detect when the ConfigROM's generation has changed,
+	 * so we only update the node's info when it needs to be.  */
+        for (; nodecount; nodecount--, nodeid++, sid++) {
+		int header_count = 0;
+		unsigned header_size = 0;
+                while (sid->extended)
+			sid++;
+                if (!sid->link_active)
+			continue;
+		if (nodeid == host->node_id)
+			continue;
+
+		HPSB_DEBUG("Initiating ConfigROM request for node %d", nodeid & NODE_MASK);
+
+		retval = hpsb_read(host, nodeid, base, &quad, 4);
+		buffer[header_count++] = be32_to_cpu(quad);
+
+		if (retval) {
+			HPSB_ERR("ConfigROM quadlet transaction error for %d",
+				 nodeid & NODE_MASK);
+			continue;
+		}
+
+		header_size = buffer[0] >> 24;
+
+		if (header_size < 4) {
+			HPSB_INFO("Node %d on %s host has non-standard ROM format (%d quads), "
+				  "cannot parse", nodeid & NODE_MASK, host->template->name,
+				  header_size);
+			continue;
+		}
+
+		while (header_count <= header_size && (header_count<<2) < sizeof(buffer)) {
+			retval = hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4);
+			buffer[header_count++] = be32_to_cpu(quad);
+
+			if (retval) {
+				HPSB_ERR("ConfigROM quadlet transaction error for %d",
+					 nodeid & NODE_MASK);
+				goto failed_read;
+			}
+
+		}
+
+		associate_guid(host, nodeid, be64_to_cpu(((u64)buffer[3] << 32) | buffer[4]));
+failed_read:
+		continue;
+        }
+
+	/* Need to detect when nodes are no longer associated with
+	 * anything. I believe we can do this using the generation of the
+	 * entries after a reset, compared the the hosts generation.  */
+}
+
+
+struct node_entry *hpsb_guid_get_handle(u64 guid)
+{
+        unsigned long flags;
+        struct node_entry *ge;
+
+        read_lock_irqsave(&node_lock, flags);
+        ge = find_entry(guid);
+        if (ge) atomic_inc(&ge->refcount);
+        read_unlock_irqrestore(&node_lock, flags);
+
+        return ge;
+}
+
+struct hpsb_host *hpsb_get_host_by_ge(struct node_entry *ge)
+{
+        if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL;
+        if (ge->node_id == ge->host->node_id) return ge->host;
+        return NULL;
+}
+
+int hpsb_guid_fill_packet(struct node_entry *ge, struct hpsb_packet *pkt)
+{
+        if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0;
+
+        pkt->host = ge->host;
+        pkt->node_id = ge->node_id;
+        pkt->generation = atomic_read(&ge->generation);
+        return 1;
+}
+
+static int nodemgr_reset_handler(void *__hi)
+{
+	struct host_info *hi = (struct host_info *)__hi;
+	struct hpsb_host *host = hi->host;
+
+	/* Standard thread setup */
+	lock_kernel();
+	daemonize();
+	strcpy(current->comm, "NodeMngr");
+	unlock_kernel();
+
+	for (;;) {
+		if (signal_pending(current))
+			break;
+
+		/* Let's take a short pause to make sure all the devices
+		 * have time to settle.  */
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/50);
+
+		if (hi && host)
+			nodemgr_node_probe(host);
+
+		/* Wait for the next bus reset */
+		if (hi && host)
+			interruptible_sleep_on(&hi->reset_wait);
+	}
+
+	return(0);
+}
+
+static void nodemgr_add_host(struct hpsb_host *host)
+{
+	struct host_info *hi = kmalloc (sizeof (struct host_info), GFP_KERNEL);
+	int flags;
+
+	if (!hi) {
+		HPSB_ERR ("Out of memory in Node Manager");
+		return;
+	}
+
+	hi->host = host;
+	INIT_LIST_HEAD(&hi->list);
+	hi->pid = -1;
+	init_waitqueue_head(&hi->reset_wait);
+
+	spin_lock_irqsave (&host_info_lock, flags);
+	list_add_tail (&hi->list, &host_info_list);
+	spin_unlock_irqrestore (&host_info_lock, flags);
+
+	return;
+}
+
+static void nodemgr_schedule_thread (void *__hi)
+{
+	struct host_info *hi = (struct host_info *)__hi;
+
+	hi->pid = kernel_thread(nodemgr_reset_handler, hi,
+				CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
+}
+
+static void nodemgr_host_reset(struct hpsb_host *host)
+{
+	struct list_head *lh;
+	struct host_info *hi = NULL;
+	int flags;
+
+	spin_lock_irqsave (&host_info_lock, flags);
+	lh = host_info_list.next;
+	while (lh != &host_info_list) {
+		struct host_info *myhi = list_entry(lh, struct host_info, list);
+		if (myhi->host == host) {
+			hi = myhi;
+			break;
+		}
+		lh = lh->next;
+	}
+
+	if (hi == NULL) {
+		HPSB_ERR ("Could not process reset of non-existent host in Node Manager");
+		goto done_reset_host;
+	}
+
+	if (hi->pid >= 0) {
+		wake_up(&hi->reset_wait);
+	} else {
+		if (in_interrupt()) {
+			static struct tq_struct task;
+			memset(&task, 0, sizeof(struct tq_struct));
+
+			task.routine = nodemgr_schedule_thread;
+			task.data = (void*)hi;
+
+			if (schedule_task(&task) < 0)
+				HPSB_ERR ("Failed to schedule Node Manager thread!\n");
+		} else {
+			nodemgr_schedule_thread(hi);
+		}
+	}
+
+done_reset_host:
+	spin_unlock_irqrestore (&host_info_lock, flags);
+
+	return;
+}
+
+static void nodemgr_remove_host(struct hpsb_host *host)
+{
+	struct list_head *lh;
+	struct host_info *hi = NULL;
+	int flags;
+
+	spin_lock_irqsave (&host_info_lock, flags);
+	lh = host_info_list.next;
+	while (lh != &host_info_list) {
+		struct host_info *myhi = list_entry(lh, struct host_info, list);
+		if (myhi->host == host) {
+			hi = myhi;
+			break;
+		}
+		lh = lh->next;
+	}
+
+	if (hi == NULL) {
+		HPSB_ERR ("Could not remove non-exitent host in Node Manager");
+		goto done_remove_host;
+	}
+
+	if (hi->pid >= 0)
+		kill_proc(hi->pid, SIGINT, 1);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ*2);   /* 2 second delay */
+
+	kfree (hi);
+
+done_remove_host:
+	spin_unlock_irqrestore (&host_info_lock, flags);
+
+	return;
+}
+
+static struct hpsb_highlevel_ops guid_ops = {
+	add_host:	nodemgr_add_host,
+	host_reset:	nodemgr_host_reset,
+	remove_host:	nodemgr_remove_host,
+};
+
+static struct hpsb_highlevel *hl;
+
+void init_ieee1394_nodemgr(void)
+{
+        atomic_set(&outstanding_requests, 0);
+
+        hl = hpsb_register_highlevel("Node manager", &guid_ops);
+        if (!hl) {
+                HPSB_ERR("Out of memory during ieee1394 initialization");
+        }
+}
+
+void cleanup_ieee1394_nodemgr(void)
+{
+        hpsb_unregister_highlevel(hl);
+}
diff -urN linux-2.4.7-pre9/drivers/ieee1394/nodemgr.h linux/drivers/ieee1394/nodemgr.h
--- linux-2.4.7-pre9/drivers/ieee1394/nodemgr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ieee1394/nodemgr.h	Mon Dec  3 22:57:10 2001
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2000	Andreas E. Bombe
+ *               2001	Ben Collins <bcollins@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _IEEE1394_NODEMGR_H
+#define _IEEE1394_NODEMGR_H
+
+
+/*
+ * General information: Finding out which GUID belongs to which node is done by
+ * sending packets and therefore waiting for the answers.  Wherever it is
+ * mentioned that a node is inaccessible this could just as well mean that we
+ * just don't know yet (usually, bus reset handlers can't rely on GUIDs being
+ * associated with current nodes).
+ */
+
+struct node_entry;
+typedef struct node_entry *hpsb_guid_t;
+
+
+/*
+ * Returns a guid handle (which has its reference count incremented) or NULL if
+ * there is the GUID in question is not known of.  Getting a valid handle does
+ * not mean that the node with this GUID is currently accessible (might not be
+ * plugged in or powered down).
+ */
+hpsb_guid_t hpsb_guid_get_handle(u64 guid);
+
+/*
+ * If the handle refers to a local host, this function will return the pointer
+ * to the hpsb_host structure.  It will return NULL otherwise.  Once you have
+ * established it is a local host, you can use that knowledge from then on (the
+ * GUID won't wander to an external node).
+ *
+ * Note that the local GUID currently isn't collected, so this will always
+ * return NULL.
+ */
+struct hpsb_host *hpsb_get_host_by_ge(hpsb_guid_t handle);
+
+/*
+ * This will fill in the given, pre-initialised hpsb_packet with the current
+ * information from the GUID handle (host, node ID, generation number).  It will
+ * return false if the node owning the GUID is not accessible (and not modify the 
+ * hpsb_packet) and return true otherwise.
+ *
+ * Note that packet sending may still fail in hpsb_send_packet if a bus reset
+ * happens while you are trying to set up the packet (due to obsolete generation
+ * number).  It will at least reliably fail so that you don't accidentally and
+ * unknowingly send your packet to the wrong node.
+ */
+int hpsb_guid_fill_packet(hpsb_guid_t handle, struct hpsb_packet *pkt);
+
+
+void init_ieee1394_nodemgr(void);
+void cleanup_ieee1394_nodemgr(void);
+
+#endif /* _IEEE1394_NODEMGR_H */
diff -urN linux-2.4.7-pre9/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- linux-2.4.7-pre9/drivers/ieee1394/ohci1394.c	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ieee1394/ohci1394.c	Mon Dec  3 22:57:10 2001
@@ -178,7 +178,7 @@
 MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
 
 static char version[] __devinitdata =
-	"ohci1394.c:v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>";
+	"v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -216,6 +216,7 @@
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
 			break;
+
 		mdelay(1);
 	}
 
@@ -243,6 +244,7 @@
 		r = reg_read(ohci, OHCI1394_PhyControl);
 		if (!(r & 0x00004000))
 			break;
+
 		mdelay(1);
 	}
 
@@ -516,22 +518,6 @@
 	/* Set the configuration ROM mapping register */
 	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
 
-	/* Set bus options */
-	reg_write(ohci, OHCI1394_BusOptions, 
-		  cpu_to_be32(ohci->csr_config_rom_cpu[2]));
-
-#if 0	
-	/* Write the GUID into the csr config rom */
-	ohci->csr_config_rom_cpu[3] = 
-		be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
-	ohci->csr_config_rom_cpu[4] = 
-		be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
-#endif
-
-	/* Write the config ROM header */
-	reg_write(ohci, OHCI1394_ConfigROMhdr, 
-		  cpu_to_be32(ohci->csr_config_rom_cpu[0]));
-
 	ohci->max_packet_size = 
 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
 	PRINT(KERN_DEBUG, ohci->id, "Max packet size = %d bytes",
@@ -725,7 +711,7 @@
 			OHCI_DMA_ALLOC("single, block transmit packet");
 
 			if (ohci->payload_swap)
-				block_swab32(packet->data, packet->data_size>>2);
+				block_swab32(packet->data, packet->data_size >> 2);
 
                         d->prg_cpu[idx]->end.branchAddress = 0;
                         d->prg_cpu[idx]->end.status = 0;
@@ -1897,6 +1883,9 @@
 	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo));
 	cf_unit_end(&cr);
 
+	DBGMSG(ohci->id, "GUID: %08x:%08x\n", reg_read(ohci, OHCI1394_GUIDHi),
+		reg_read(ohci, OHCI1394_GUIDLo));
+
 	/* IEEE P1212 suggests the initial ROM header CRC should only
 	 * cover the header itself (and not the entire ROM). Since we use
 	 * this, then we can make our bus_info_len the same as the CRC
@@ -1991,6 +1980,7 @@
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
 			break;
+
 		mdelay(10);
 	}
 
@@ -2180,7 +2170,7 @@
 	if (ohci->ir_context == NULL)
 		FAIL("Failed to allocate IR context");
 
-        ohci->ISO_channel_usage= 0;
+	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
 	if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
@@ -2190,10 +2180,6 @@
 		FAIL("Failed to allocate shared interrupt %d", dev->irq);
 
 	ohci_init_config_rom(ohci);
-
-	DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
-	       *((char *)ohci->csr_config_rom_cpu+4));
-
 
 	/* Tell the highlevel this host is ready */
 	highlevel_add_one_host (host);
diff -urN linux-2.4.7-pre9/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- linux-2.4.7-pre9/drivers/ieee1394/pcilynx.c	Mon Dec  3 22:57:01 2001
+++ linux/drivers/ieee1394/pcilynx.c	Mon Dec  3 22:57:10 2001
@@ -1351,6 +1351,7 @@
 
         lynx->id = num_of_cards-1;
         lynx->dev = dev;
+	lynx->host->pdev = dev;
 
 	lynx->lock = SPIN_LOCK_UNLOCKED;
 	lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;
diff -urN linux-2.4.7-pre9/fs/namei.c linux/fs/namei.c
--- linux-2.4.7-pre9/fs/namei.c	Mon Dec  3 22:57:02 2001
+++ linux/fs/namei.c	Mon Dec  3 22:57:11 2001
@@ -1688,6 +1688,10 @@
 	error = -EINVAL;
 	if (is_subdir(new_dentry, old_dentry))
 		goto out_unlock;
+	/* Don't eat your daddy, dear... */
+	/* This also avoids locking issues */
+	if (old_dentry->d_parent == new_dentry)
+		goto out_unlock;
 	target = new_dentry->d_inode;
 	if (target) { /* Hastur! Hastur! Hastur! */
 		triple_down(&old_dir->i_zombie,
diff -urN linux-2.4.7-pre9/fs/proc/base.c linux/fs/proc/base.c
--- linux-2.4.7-pre9/fs/proc/base.c	Mon Dec  3 22:57:02 2001
+++ linux/fs/proc/base.c	Mon Dec  3 22:57:11 2001
@@ -645,6 +645,20 @@
 
 /* building an inode */
 
+static int task_dumpable(struct task_struct *task)
+{
+	int dumpable = 0;
+	struct mm_struct *mm;
+
+	task_lock(task);
+	mm = task->mm;
+	if (mm)
+		dumpable = mm->dumpable;
+	task_unlock(task);
+	return dumpable;
+}
+
+
 static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
 {
 	struct inode * inode;
@@ -670,7 +684,7 @@
 	inode->u.proc_i.task = task;
 	inode->i_uid = 0;
 	inode->i_gid = 0;
-	if (ino == PROC_PID_INO || task->mm->dumpable) {
+	if (ino == PROC_PID_INO || task_dumpable(task)) {
 		inode->i_uid = task->euid;
 		inode->i_gid = task->egid;
 	}
diff -urN linux-2.4.7-pre9/include/linux/mm.h linux/include/linux/mm.h
--- linux-2.4.7-pre9/include/linux/mm.h	Tue Jul  3 15:42:55 2001
+++ linux/include/linux/mm.h	Mon Dec  3 22:57:11 2001
@@ -442,6 +442,7 @@
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
+extern int ptrace_attach(struct task_struct *tsk);
 
 /*
  * On a two-level page table, this ends up being trivial. Thus the
diff -urN linux-2.4.7-pre9/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- linux-2.4.7-pre9/include/linux/mtd/cfi.h	Tue Jun 12 10:30:27 2001
+++ linux/include/linux/mtd/cfi.h	Mon Dec  3 22:57:11 2001
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.21 2001/06/03 01:32:57 nico Exp $
+ * $Id: cfi.h,v 1.22 2001/07/06 09:29:07 dwmw2 Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/types.h>
+#include <linux/interrupt.h>
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/cfi_endian.h>
 
diff -urN linux-2.4.7-pre9/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.7-pre9/kernel/ksyms.c	Mon Dec  3 22:57:02 2001
+++ linux/kernel/ksyms.c	Mon Dec  3 22:57:11 2001
@@ -45,6 +45,7 @@
 #include <linux/fs.h>
 #include <linux/tty.h>
 #include <linux/in6.h>
+#include <linux/completion.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -361,6 +362,10 @@
 EXPORT_SYMBOL(add_wait_queue);
 EXPORT_SYMBOL(add_wait_queue_exclusive);
 EXPORT_SYMBOL(remove_wait_queue);
+
+/* completion handling */
+EXPORT_SYMBOL(wait_for_completion);
+EXPORT_SYMBOL(complete);
 
 /* The notion of irq probe/assignment is foreign to S/390 */
 
diff -urN linux-2.4.7-pre9/kernel/ptrace.c linux/kernel/ptrace.c
--- linux-2.4.7-pre9/kernel/ptrace.c	Mon Mar 19 12:35:08 2001
+++ linux/kernel/ptrace.c	Mon Dec  3 22:57:11 2001
@@ -16,6 +16,51 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
+int ptrace_attach(struct task_struct *task)
+{
+	task_lock(task);
+	if (task->pid <= 1)
+		goto bad;
+	if (task == current)
+		goto bad;
+	if (!task->mm)
+		goto bad;
+	if(((current->uid != task->euid) ||
+	    (current->uid != task->suid) ||
+	    (current->uid != task->uid) ||
+ 	    (current->gid != task->egid) ||
+ 	    (current->gid != task->sgid) ||
+ 	    (!cap_issubset(task->cap_permitted, current->cap_permitted)) ||
+ 	    (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+		goto bad;
+	rmb();
+	if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+		goto bad;
+	/* the same process cannot be attached many times */
+	if (task->ptrace & PT_PTRACED)
+		goto bad;
+
+	/* Go */
+	task->ptrace |= PT_PTRACED;
+	task_unlock(task);
+
+	write_lock_irq(&tasklist_lock);
+	if (task->p_pptr != current) {
+		REMOVE_LINKS(task);
+		task->p_pptr = current;
+		SET_LINKS(task);
+	}
+	write_unlock_irq(&tasklist_lock);
+
+	send_sig(SIGSTOP, task, 1);
+	return 0;
+
+bad:
+	task_unlock(task);
+	return -EPERM;
+}
+
+
 /*
  * Access another process' address space, one page at a time.
  */
