Commit e6abc8ca authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields

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: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 3c86794a
...@@ -1010,8 +1010,9 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) ...@@ -1010,8 +1010,9 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
cb->cb_seq_status = 1; cb->cb_seq_status = 1;
cb->cb_status = 0; cb->cb_status = 0;
if (minorversion) { if (minorversion) {
if (!nfsd41_cb_get_slot(clp, task)) if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task))
return; return;
cb->cb_holds_slot = true;
} }
rpc_call_start(task); rpc_call_start(task);
} }
...@@ -1038,6 +1039,9 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback ...@@ -1038,6 +1039,9 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
return true; return true;
} }
if (!cb->cb_holds_slot)
goto need_restart;
switch (cb->cb_seq_status) { switch (cb->cb_seq_status) {
case 0: case 0:
/* /*
...@@ -1076,6 +1080,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback ...@@ -1076,6 +1080,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
cb->cb_seq_status); cb->cb_seq_status);
} }
cb->cb_holds_slot = false;
clear_bit(0, &clp->cl_cb_slot_busy); clear_bit(0, &clp->cl_cb_slot_busy);
rpc_wake_up_next(&clp->cl_cb_waitq); rpc_wake_up_next(&clp->cl_cb_waitq);
dprintk("%s: freed slot, new seqid=%d\n", __func__, dprintk("%s: freed slot, new seqid=%d\n", __func__,
...@@ -1283,6 +1288,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, ...@@ -1283,6 +1288,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
cb->cb_seq_status = 1; cb->cb_seq_status = 1;
cb->cb_status = 0; cb->cb_status = 0;
cb->cb_need_restart = false; cb->cb_need_restart = false;
cb->cb_holds_slot = false;
} }
void nfsd4_run_cb(struct nfsd4_callback *cb) void nfsd4_run_cb(struct nfsd4_callback *cb)
......
...@@ -70,6 +70,7 @@ struct nfsd4_callback { ...@@ -70,6 +70,7 @@ struct nfsd4_callback {
int cb_seq_status; int cb_seq_status;
int cb_status; int cb_status;
bool cb_need_restart; bool cb_need_restart;
bool cb_holds_slot;
}; };
struct nfsd4_callback_ops { struct nfsd4_callback_ops {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment