[Devel] [PATCH RH7 1/3] ms/nfsd: Don't release the callback slot unless it was actually held

Vasily Averin vvs at virtuozzo.com
Tue Feb 25 08:52:56 MSK 2020


>From 43dc593eb55e257a6b1da9d51a3d8e453427370a Mon Sep 17 00:00:00 2001
From: Trond Myklebust <trondmy at gmail.com>
Date: Fri, 5 Apr 2019 08:54:37 -0700
Subject: [RHEL7.9 fs BZ1448750 PATCH 1/2] nfsd: Don't release the callback
 slot unless it was actually held

If there are multiple callbacks queued, waiting for the callback
slot when the callback gets shut down, then they all currently
end up acting as if they hold the slot, and call
nfsd4_cb_sequence_done() resulting in interesting side-effects.

In addition, the 'retry_nowait' path in nfsd4_cb_sequence_done()
causes a loop back to nfsd4_cb_prepare() without first freeing the
slot, which causes a deadlock when nfsd41_cb_get_slot() gets called
a second time.

This patch therefore adds a boolean to track whether or not the
callback did pick up the slot, so that it can do the right thing
in these 2 cases.

Cc: stable at vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust at hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields at redhat.com>
(cherry picked from commit e6abc8caa6deb14be2a206253f7e1c5e37e9515b)
Signed-off-by: Dave Wysochanski <dwysocha at redhat.com>

Taken from https://bugzilla.redhat.com/show_bug.cgi?id=1448750
https://jira.sw.ru/browse/PSBM-100902
Signed-off-by: Vasily Averin <vvs at virtuozzo.com
---
 fs/nfsd/nfs4callback.c | 8 +++++++-
 fs/nfsd/state.h        | 1 +
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 28b93ee..c69400f 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -930,8 +930,9 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
 	cb->cb_seq_status = 1;
 	cb->cb_status = 0;
 	if (minorversion) {
-		if (!nfsd41_cb_get_slot(clp, task))
+		if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task))
 			return;
+		cb->cb_holds_slot = true;
 	}
 	rpc_call_start(task);
 }
@@ -958,6 +959,9 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
 		return true;
 	}
 
+	if (!cb->cb_holds_slot)
+		goto need_restart;
+
 	switch (cb->cb_seq_status) {
 	case 0:
 		/*
@@ -995,6 +999,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
 			cb->cb_seq_status);
 	}
 
+	cb->cb_holds_slot = false;
 	clear_bit(0, &clp->cl_cb_slot_busy);
 	rpc_wake_up_next(&clp->cl_cb_waitq);
 	dprintk("%s: freed slot, new seqid=%d\n", __func__,
@@ -1202,6 +1207,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
 	cb->cb_seq_status = 1;
 	cb->cb_status = 0;
 	cb->cb_need_restart = false;
+	cb->cb_holds_slot = false;
 }
 
 void nfsd4_run_cb(struct nfsd4_callback *cb)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 11e114f..d8bac46 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -70,6 +70,7 @@ struct nfsd4_callback {
 	int cb_seq_status;
 	int cb_status;
 	bool cb_need_restart;
+	bool cb_holds_slot;
 };
 
 struct nfsd4_callback_ops {
-- 
1.8.3.1



More information about the Devel mailing list