Skip to content

Commit

Permalink
SUNRPC: Add a helper to allow pNFS drivers to selectively cancel RPC …
Browse files Browse the repository at this point in the history
…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 <[email protected]>
Signed-off-by: Anna Schumaker <[email protected]>
  • Loading branch information
Trond Myklebust authored and amschuma-ntap committed Oct 6, 2022
1 parent 3949419 commit f842390
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 0 deletions.
5 changes: 5 additions & 0 deletions include/linux/sunrpc/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_async(struct rpc_task *);
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_exit_task(struct rpc_task *);
void rpc_exit(struct rpc_task *, int);
void rpc_release_calldata(const struct rpc_call_ops *, void *);
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_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
void rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
Expand Down
37 changes: 37 additions & 0 deletions net/sunrpc/clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,43 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)
}
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
* requests.
Expand Down
11 changes: 11 additions & 0 deletions net/sunrpc/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,17 @@ void rpc_signal_task(struct rpc_task *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)
{
task->tk_status = status;
Expand Down

0 comments on commit f842390

Please sign in to comment.