Commit f8423909 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

SUNRPC: Add a helper to allow pNFS drivers to selectively cancel RPC calls

Add the helper rpc_cancel_tasks(), which uses a caller-defined selection
function to define a set of in-flight RPC calls to cancel. This is
mainly intended for pNFS drivers which are subject to a layout recall,
and which may therefore want to cancel all pending I/O using that layout
in order to redrive it after the layout recall has been satisfied.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 39494194
...@@ -210,11 +210,16 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req); ...@@ -210,11 +210,16 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req);
void rpc_put_task(struct rpc_task *); void rpc_put_task(struct rpc_task *);
void rpc_put_task_async(struct rpc_task *); void rpc_put_task_async(struct rpc_task *);
bool rpc_task_set_rpc_status(struct rpc_task *task, int rpc_status); bool rpc_task_set_rpc_status(struct rpc_task *task, int rpc_status);
void rpc_task_try_cancel(struct rpc_task *task, int error);
void rpc_signal_task(struct rpc_task *); void rpc_signal_task(struct rpc_task *);
void rpc_exit_task(struct rpc_task *); void rpc_exit_task(struct rpc_task *);
void rpc_exit(struct rpc_task *, int); void rpc_exit(struct rpc_task *, int);
void rpc_release_calldata(const struct rpc_call_ops *, void *); void rpc_release_calldata(const struct rpc_call_ops *, void *);
void rpc_killall_tasks(struct rpc_clnt *); void rpc_killall_tasks(struct rpc_clnt *);
unsigned long rpc_cancel_tasks(struct rpc_clnt *clnt, int error,
bool (*fnmatch)(const struct rpc_task *,
const void *),
const void *data);
void rpc_execute(struct rpc_task *); void rpc_execute(struct rpc_task *);
void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); void rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
......
...@@ -873,6 +873,43 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) ...@@ -873,6 +873,43 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)
} }
EXPORT_SYMBOL_GPL(rpc_killall_tasks); EXPORT_SYMBOL_GPL(rpc_killall_tasks);
/**
* rpc_cancel_tasks - try to cancel a set of RPC tasks
* @clnt: Pointer to RPC client
* @error: RPC task error value to set
* @fnmatch: Pointer to selector function
* @data: User data
*
* Uses @fnmatch to define a set of RPC tasks that are to be cancelled.
* The argument @error must be a negative error value.
*/
unsigned long rpc_cancel_tasks(struct rpc_clnt *clnt, int error,
bool (*fnmatch)(const struct rpc_task *,
const void *),
const void *data)
{
struct rpc_task *task;
unsigned long count = 0;
if (list_empty(&clnt->cl_tasks))
return 0;
/*
* Spin lock all_tasks to prevent changes...
*/
spin_lock(&clnt->cl_lock);
list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
if (!RPC_IS_ACTIVATED(task))
continue;
if (!fnmatch(task, data))
continue;
rpc_task_try_cancel(task, error);
count++;
}
spin_unlock(&clnt->cl_lock);
return count;
}
EXPORT_SYMBOL_GPL(rpc_cancel_tasks);
/* /*
* Properly shut down an RPC client, terminating all outstanding * Properly shut down an RPC client, terminating all outstanding
* requests. * requests.
......
...@@ -872,6 +872,17 @@ void rpc_signal_task(struct rpc_task *task) ...@@ -872,6 +872,17 @@ void rpc_signal_task(struct rpc_task *task)
rpc_wake_up_queued_task(queue, task); rpc_wake_up_queued_task(queue, task);
} }
void rpc_task_try_cancel(struct rpc_task *task, int error)
{
struct rpc_wait_queue *queue;
if (!rpc_task_set_rpc_status(task, error))
return;
queue = READ_ONCE(task->tk_waitqueue);
if (queue)
rpc_wake_up_queued_task(queue, task);
}
void rpc_exit(struct rpc_task *task, int status) void rpc_exit(struct rpc_task *task, int status)
{ {
task->tk_status = status; task->tk_status = status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment