patch-2.3.99-pre4 linux/net/sunrpc/sched.c

Next file: linux/net/sunrpc/sunrpc_syms.c
Previous file: linux/net/sunrpc/clnt.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre3/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
@@ -508,6 +508,7 @@
 		return 0;
 	}
 
+ restarted:
 	while (1) {
 		/*
 		 * Execute any pending callback.
@@ -586,10 +587,29 @@
 		}
 	}
 
+	if (task->tk_exit) {
+		task->tk_exit(task);
+		/* If tk_action is non-null, the user wants us to restart */
+		if (task->tk_action) {
+			if (!RPC_ASSASSINATED(task)) {
+				/* Release RPC slot and buffer memory */
+				if (task->tk_rqstp)
+					xprt_release(task);
+				if (task->tk_buffer) {
+					rpc_free(task->tk_buffer);
+					task->tk_buffer = NULL;
+				}
+				goto restarted;
+			}
+			printk(KERN_ERR "RPC: dead task tries to walk away.\n");
+		}
+	}
+
 	dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
 	status = task->tk_status;
-	if (task->tk_exit)
-		task->tk_exit(task);
+
+	/* Release all resources associated with the task */
+	rpc_release_task(task);
 
 	return status;
 }
@@ -599,22 +619,32 @@
  *
  * This may be called recursively if e.g. an async NFS task updates
  * the attributes and finds that dirty pages must be flushed.
+ * NOTE: Upon exit of this function the task is guaranteed to be
+ *	 released. In particular note that tk_release() will have
+ *	 been called, so your task memory may have been freed.
  */
 int
 rpc_execute(struct rpc_task *task)
 {
+	int status = -EIO;
 	if (rpc_inhibit) {
 		printk(KERN_INFO "RPC: execution inhibited!\n");
-		return -EIO;
+		goto out_release;
 	}
-	task->tk_flags |= RPC_TASK_RUNNING;
+
+	status = -EWOULDBLOCK;
 	if (task->tk_active) {
 		printk(KERN_ERR "RPC: active task was run twice!\n");
-		return -EWOULDBLOCK;
+		goto out_err;
 	}
+
 	task->tk_active = 1;
-	
+	task->tk_flags |= RPC_TASK_RUNNING;
 	return __rpc_execute(task);
+ out_release:
+	rpc_release_task(task);
+ out_err:
+	return status;
 }
 
 /*
@@ -700,7 +730,7 @@
 		}
 		if (flags & RPC_TASK_ASYNC)
 			return NULL;
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ>>4);
 	} while (!signalled());
 
@@ -758,6 +788,13 @@
 				current->pid);
 }
 
+static void
+rpc_default_free_task(struct rpc_task *task)
+{
+	dprintk("RPC: %4d freeing task\n", task->tk_pid);
+	rpc_free(task);
+}
+
 /*
  * Create a new task for the specified client.  We have to
  * clean up after an allocation failure, as the client may
@@ -774,6 +811,9 @@
 
 	rpc_init_task(task, clnt, callback, flags);
 
+	/* Replace tk_release */
+	task->tk_release = rpc_default_free_task;
+
 	dprintk("RPC: %4d allocated task\n", task->tk_pid);
 	task->tk_flags |= RPC_TASK_DYNAMIC;
 out:
@@ -849,12 +889,8 @@
 #ifdef RPC_DEBUG
 	task->tk_magic = 0;
 #endif
-
-	if (task->tk_flags & RPC_TASK_DYNAMIC) {
-		dprintk("RPC: %4d freeing task\n", task->tk_pid);
-		task->tk_flags &= ~RPC_TASK_DYNAMIC;
-		rpc_free(task);
-	}
+	if (task->tk_release)
+		task->tk_release(task);
 }
 
 /*
@@ -886,7 +922,6 @@
 		__rpc_wake_up(parent);
 	}
 	spin_unlock_bh(&rpc_queue_lock);
-	rpc_release_task(child);
 }
 
 /*
@@ -1028,7 +1063,7 @@
 		__rpc_schedule();
 		if (all_tasks) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(1);
 		}
 	}
@@ -1099,7 +1134,7 @@
 	 * wait briefly before checking the process id.
 	 */
 	current->sigpending = 0;
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(1);
 	/*
 	 * Display a message if we're going to wait longer.

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)