[RHEL7,COMMIT] ms/nfsd: Don't release the callback slot unless it was actually held

Submitted by Konstantin Khorenko on Feb. 27, 2020, 10:01 a.m.

Details

Message ID 202002271001.01RA1Ow8024846@finist-ce7.sw.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko Feb. 27, 2020, 10:01 a.m.
The commit is pushed to "branch-rh7-3.10.0-1062.12.1.vz7.131.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1062.12.1.vz7.131.4
------>
commit 7454a530ff31b4ec340d39523a26f99123b5244d
Author: Trond Myklebust <trondmy@gmail.com>
Date:   Thu Feb 27 13:01:24 2020 +0300

    ms/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@vger.kernel.org
    Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
    Signed-off-by: J. Bruce Fields <bfields@redhat.com>
    (cherry picked from commit e6abc8caa6deb14be2a206253f7e1c5e37e9515b)
    Signed-off-by: Dave Wysochanski <dwysocha@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@virtuozzo.com
---
 fs/nfsd/nfs4callback.c | 8 +++++++-
 fs/nfsd/state.h        | 1 +
 2 files changed, 8 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 28b93eeb979cc..c69400f08ed4d 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 11e114f7b3395..d8bac46b3573a 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 {