mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-08 14:23:19 +00:00
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: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
39494194f9
commit
f8423909ec
@ -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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user