Fix a second potential rpc_wakeup race...

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Trond Myklebust
2006-11-11 22:18:03 -05:00
parent cc4dc59e55
commit e6b3c4db6f
6 changed files with 65 additions and 57 deletions

View File

@ -266,12 +266,28 @@ static int rpc_wait_bit_interruptible(void *word)
return 0;
}
static void rpc_set_active(struct rpc_task *task)
{
if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0)
return;
spin_lock(&rpc_sched_lock);
#ifdef RPC_DEBUG
task->tk_magic = RPC_TASK_MAGIC_ID;
task->tk_pid = rpc_task_id++;
#endif
/* Add to global list of all tasks */
list_add_tail(&task->tk_task, &all_tasks);
spin_unlock(&rpc_sched_lock);
}
/*
* Mark an RPC call as having completed by clearing the 'active' bit
*/
static inline void rpc_mark_complete_task(struct rpc_task *task)
static void rpc_mark_complete_task(struct rpc_task *task)
{
rpc_clear_active(task);
smp_mb__before_clear_bit();
clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
smp_mb__after_clear_bit();
wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE);
}
@ -335,9 +351,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
return;
}
/* Mark the task as being activated if so needed */
rpc_set_active(task);
__rpc_add_wait_queue(q, task);
BUG_ON(task->tk_callback != NULL);
@ -348,6 +361,9 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
rpc_action action, rpc_action timer)
{
/* Mark the task as being activated if so needed */
rpc_set_active(task);
/*
* Protect the queue operations.
*/
@ -673,8 +689,6 @@ static int __rpc_execute(struct rpc_task *task)
}
dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status);
/* Wake up anyone who is waiting for task completion */
rpc_mark_complete_task(task);
/* Release all resources associated with the task */
rpc_release_task(task);
return status;
@ -788,15 +802,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
task->tk_flags |= RPC_TASK_NOINTR;
}
#ifdef RPC_DEBUG
task->tk_magic = RPC_TASK_MAGIC_ID;
task->tk_pid = rpc_task_id++;
#endif
/* Add to global list of all tasks */
spin_lock(&rpc_sched_lock);
list_add_tail(&task->tk_task, &all_tasks);
spin_unlock(&rpc_sched_lock);
BUG_ON(task->tk_ops == NULL);
/* starting timestamp */
@ -849,16 +854,35 @@ cleanup:
goto out;
}
void rpc_release_task(struct rpc_task *task)
void rpc_put_task(struct rpc_task *task)
{
const struct rpc_call_ops *tk_ops = task->tk_ops;
void *calldata = task->tk_calldata;
if (!atomic_dec_and_test(&task->tk_count))
return;
/* Release resources */
if (task->tk_rqstp)
xprt_release(task);
if (task->tk_msg.rpc_cred)
rpcauth_unbindcred(task);
if (task->tk_client) {
rpc_release_client(task->tk_client);
task->tk_client = NULL;
}
if (task->tk_flags & RPC_TASK_DYNAMIC)
rpc_free_task(task);
if (tk_ops->rpc_release)
tk_ops->rpc_release(calldata);
}
EXPORT_SYMBOL(rpc_put_task);
void rpc_release_task(struct rpc_task *task)
{
#ifdef RPC_DEBUG
BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);
#endif
if (!atomic_dec_and_test(&task->tk_count))
return;
dprintk("RPC: %4d release task\n", task->tk_pid);
/* Remove from global task list */
@ -871,23 +895,13 @@ void rpc_release_task(struct rpc_task *task)
/* Synchronously delete any running timer */
rpc_delete_timer(task);
/* Release resources */
if (task->tk_rqstp)
xprt_release(task);
if (task->tk_msg.rpc_cred)
rpcauth_unbindcred(task);
if (task->tk_client) {
rpc_release_client(task->tk_client);
task->tk_client = NULL;
}
#ifdef RPC_DEBUG
task->tk_magic = 0;
#endif
if (task->tk_flags & RPC_TASK_DYNAMIC)
rpc_free_task(task);
if (tk_ops->rpc_release)
tk_ops->rpc_release(calldata);
/* Wake up anyone who is waiting for task completion */
rpc_mark_complete_task(task);
rpc_put_task(task);
}
/**