patch for 2.1.75 sunrpc/sched.c

Bill Hawes (whawes@star.net)
Mon, 22 Dec 1997 17:41:36 -0500


This is a multi-part message in MIME format.
--------------4BD89774DBA3C600EC9E8162
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I've found a possible problem in the RPC code in sched.c related to the
scheduling queue. The code there appears to require that interrupts be
disabled for operations adding or removing tasks from the wait queues,
but a call to rpc_make_runnable() is made from rpc_run_child without
disabling interrupts. Since child tasks are ASYNC and rpc_run_child is
called from ordinary task context, this violates the intended protection
for the queues.

It's probably not very likely, but if an interrupt (e.g. a timer)
occurred while the queue was being modified, conceivably the queue could
be corrupted.

The attached patch disables interrupts around the call to
rpc_make_runnable.

Regards,
Bill
--------------4BD89774DBA3C600EC9E8162
Content-Type: text/plain; charset=us-ascii; name="sunrpc_75-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sunrpc_75-patch"

--- net/sunrpc/sched.c.old Mon Dec 22 10:45:46 1997
+++ net/sunrpc/sched.c Mon Dec 22 18:06:04 1997
@@ -92,7 +92,8 @@
}

/*
- * Remove request from queue
+ * Remove request from queue.
+ * Note: must be called with interrupts disabled.
*/
void
rpc_remove_wait_queue(struct rpc_task *task)
@@ -149,6 +150,9 @@

/*
* Make an RPC task runnable.
+ *
+ * Note: If the task is ASYNC, this must be called with
+ * interrupts disabled to protect the wait queue operation.
*/
static inline void
rpc_make_runnable(struct rpc_task *task)
@@ -687,20 +691,26 @@
{
struct rpc_task *task;

- if (!(task = rpc_new_task(clnt, NULL, RPC_TASK_ASYNC|RPC_TASK_CHILD))) {
- parent->tk_status = -ENOMEM;
- return NULL;
- }
+ task = rpc_new_task(clnt, NULL, RPC_TASK_ASYNC | RPC_TASK_CHILD);
+ if (!task)
+ goto fail;
task->tk_exit = rpc_child_exit;
task->tk_calldata = parent;
-
return task;
+
+fail:
+ parent->tk_status = -ENOMEM;
+ return NULL;
}

void
rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
{
+ unsigned long oldflags;
+
+ save_flags(oldflags); cli();
rpc_make_runnable(child);
+ restore_flags(oldflags);
rpc_sleep_on(&childq, task, func, NULL);
}

--------------4BD89774DBA3C600EC9E8162--