Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bdb5f21 authored by Bryan Schumaker's avatar Bryan Schumaker Committed by Trond Myklebust
Browse files

NFS: Add sequence_priviliged_ops for nfs4_proc_sequence()



If I mount an NFS v4.1 server to a single client multiple times and then
run xfstests over each mountpoint I usually get the client into a state
where recovery deadlocks.  The server informs the client of a
cb_path_down sequence error, the client then does a
bind_connection_to_session and checks the status of the lease.

I found that bind_connection_to_session sets the NFS4_SESSION_DRAINING
flag on the client, but this flag is never unset before
nfs4_check_lease() reaches nfs4_proc_sequence().  This causes the client
to deadlock, halting all NFS activity to the server.  nfs4_proc_sequence()
is only called by the state manager, so I can change it to run in privileged
mode to bypass the NFS4_SESSION_DRAINING check and avoid the deadlock.

Signed-off-by: default avatarBryan Schumaker <bjschuma@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@vger.kernel.org
parent f994c43d
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -6136,13 +6136,26 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
	rpc_call_start(task);
}

static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data)
{
	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
	nfs41_sequence_prepare(task, data);
}

static const struct rpc_call_ops nfs41_sequence_ops = {
	.rpc_call_done = nfs41_sequence_call_done,
	.rpc_call_prepare = nfs41_sequence_prepare,
	.rpc_release = nfs41_sequence_release,
};

static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
static const struct rpc_call_ops nfs41_sequence_privileged_ops = {
	.rpc_call_done = nfs41_sequence_call_done,
	.rpc_call_prepare = nfs41_sequence_prepare_privileged,
	.rpc_release = nfs41_sequence_release,
};

static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred,
					     const struct rpc_call_ops *seq_ops)
{
	struct nfs4_sequence_data *calldata;
	struct rpc_message msg = {
@@ -6152,7 +6165,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
	struct rpc_task_setup task_setup_data = {
		.rpc_client = clp->cl_rpcclient,
		.rpc_message = &msg,
		.callback_ops = &nfs41_sequence_ops,
		.callback_ops = seq_ops,
		.flags = RPC_TASK_ASYNC | RPC_TASK_SOFT,
	};

@@ -6179,7 +6192,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr

	if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
		return 0;
	task = _nfs41_proc_sequence(clp, cred);
	task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_ops);
	if (IS_ERR(task))
		ret = PTR_ERR(task);
	else
@@ -6193,7 +6206,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
	struct rpc_task *task;
	int ret;

	task = _nfs41_proc_sequence(clp, cred);
	task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_privileged_ops);
	if (IS_ERR(task)) {
		ret = PTR_ERR(task);
		goto out;