SUNRPC: Allow the rpc_release() callback to be run on another workqueue
A lot of the work done by the rpc_release() callback is inappropriate for rpciod as it will often involve things like starting a new rpc call in order to clean up state after an interrupted NFSv4 open() call, or calls to mntput(), etc. This patch allows the caller of rpc_run_task() to specify that the rpc_release callback should run on a different workqueue than the default rpciod_workqueue. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
383ba71938
commit
32bfb5c0f4
|
@ -123,6 +123,7 @@ struct rpc_task_setup {
|
|||
const struct rpc_message *rpc_message;
|
||||
const struct rpc_call_ops *callback_ops;
|
||||
void *callback_data;
|
||||
struct workqueue_struct *workqueue;
|
||||
unsigned short flags;
|
||||
signed char priority;
|
||||
};
|
||||
|
|
|
@ -326,7 +326,7 @@ static void rpc_make_runnable(struct rpc_task *task)
|
|||
int status;
|
||||
|
||||
INIT_WORK(&task->u.tk_work, rpc_async_schedule);
|
||||
status = queue_work(task->tk_workqueue, &task->u.tk_work);
|
||||
status = queue_work(rpciod_workqueue, &task->u.tk_work);
|
||||
if (status < 0) {
|
||||
printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
|
||||
task->tk_status = status;
|
||||
|
@ -832,7 +832,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
|
|||
task->tk_owner = current->tgid;
|
||||
|
||||
/* Initialize workqueue for async tasks */
|
||||
task->tk_workqueue = rpciod_workqueue;
|
||||
task->tk_workqueue = task_setup_data->workqueue;
|
||||
|
||||
task->tk_client = task_setup_data->rpc_client;
|
||||
if (task->tk_client != NULL) {
|
||||
|
@ -868,7 +868,7 @@ rpc_alloc_task(void)
|
|||
return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS);
|
||||
}
|
||||
|
||||
static void rpc_free_task(struct rcu_head *rcu)
|
||||
static void rpc_free_task_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct rpc_task *task = container_of(rcu, struct rpc_task, u.tk_rcu);
|
||||
dprintk("RPC: %5u freeing task\n", task->tk_pid);
|
||||
|
@ -898,12 +898,23 @@ out:
|
|||
return task;
|
||||
}
|
||||
|
||||
|
||||
void rpc_put_task(struct rpc_task *task)
|
||||
static void rpc_free_task(struct rpc_task *task)
|
||||
{
|
||||
const struct rpc_call_ops *tk_ops = task->tk_ops;
|
||||
void *calldata = task->tk_calldata;
|
||||
|
||||
if (task->tk_flags & RPC_TASK_DYNAMIC)
|
||||
call_rcu_bh(&task->u.tk_rcu, rpc_free_task_rcu);
|
||||
rpc_release_calldata(tk_ops, calldata);
|
||||
}
|
||||
|
||||
static void rpc_async_release(struct work_struct *work)
|
||||
{
|
||||
rpc_free_task(container_of(work, struct rpc_task, u.tk_work));
|
||||
}
|
||||
|
||||
void rpc_put_task(struct rpc_task *task)
|
||||
{
|
||||
if (!atomic_dec_and_test(&task->tk_count))
|
||||
return;
|
||||
/* Release resources */
|
||||
|
@ -915,9 +926,11 @@ void rpc_put_task(struct rpc_task *task)
|
|||
rpc_release_client(task->tk_client);
|
||||
task->tk_client = NULL;
|
||||
}
|
||||
if (task->tk_flags & RPC_TASK_DYNAMIC)
|
||||
call_rcu_bh(&task->u.tk_rcu, rpc_free_task);
|
||||
rpc_release_calldata(tk_ops, calldata);
|
||||
if (task->tk_workqueue != NULL) {
|
||||
INIT_WORK(&task->u.tk_work, rpc_async_release);
|
||||
queue_work(task->tk_workqueue, &task->u.tk_work);
|
||||
} else
|
||||
rpc_free_task(task);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_put_task);
|
||||
|
||||
|
|
Loading…
Reference in a new issue