From: Manfred Spraul <manfred@colorfullife.com>

sunrpc uses sleep_on to wait until the rpciod thread has died.  This could
race if rpciod_down is called without lock_kernel.  Right now all calls in
the main tree are under lock_kernel, but rpciod is an exported function and
sleep_on should die.

Additionally, I've replaced spin_lock_irqsave() with spin_lock_irq():
rpciod_down sleeps, interrupts are guaranteed to be enabled.



---

 net/sunrpc/sched.c |   19 +++++++++++++------
 1 files changed, 13 insertions(+), 6 deletions(-)

diff -puN net/sunrpc/sched.c~sunrpc-sleep_on-removal net/sunrpc/sched.c
--- 25/net/sunrpc/sched.c~sunrpc-sleep_on-removal	2004-01-19 13:35:41.000000000 -0800
+++ 25-akpm/net/sunrpc/sched.c	2004-01-19 13:35:41.000000000 -0800
@@ -1060,7 +1060,7 @@ out:
 void
 rpciod_down(void)
 {
-	unsigned long flags;
+	DECLARE_WAITQUEUE(wait, current);
 
 	down(&rpciod_sema);
 	dprintk("rpciod_down pid %d sema %d\n", rpciod_pid, rpciod_users);
@@ -1085,17 +1085,24 @@ rpciod_down(void)
 	/*
 	 * Display a message if we're going to wait longer.
 	 */
-	while (rpciod_pid) {
-		dprintk("rpciod_down: waiting for pid %d to exit\n", rpciod_pid);
+	add_wait_queue(&rpciod_killer, &wait);
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (rpciod_pid == 0)
+			break;
+		dprintk("rpciod_down: waiting for pid %d to exit\n",
+			rpciod_pid);
 		if (signalled()) {
 			dprintk("rpciod_down: caught signal\n");
 			break;
 		}
-		interruptible_sleep_on(&rpciod_killer);
+		schedule();
 	}
-	spin_lock_irqsave(&current->sighand->siglock, flags);
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rpciod_killer, &wait);
+	spin_lock_irq(&current->sighand->siglock);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sighand->siglock, flags);
+	spin_unlock_irq(&current->sighand->siglock);
 out:
 	up(&rpciod_sema);
 }

_