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

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
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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 *);
+37 −0
Original line number Diff line number Diff line
@@ -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.
+11 −0
Original line number Diff line number Diff line
@@ -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;