On Mon, 2024-03-04 at 15:40 +1100, NeilBrown wrote: > move_to_close_lru() is currently called with ->st_mutex held. > This can lead to a deadlock as move_to_close_lru() waits for sc_count to > drop to 2, and some threads holding a reference might be waiting for the > mutex. These references will never be dropped so sc_count will never > reach 2. > > There can be no harm in dropping ->st_mutex before > move_to_close_lru() because the only place that takes the mutex is > nfsd4_lock_ol_stateid(), and it quickly aborts if sc_type is > NFS4_CLOSED_STID, which it will be before move_to_close_lru() is called. > > See also > https://lore.kernel.org/lkml/4dd1fe21e11344e5969bb112e954affb@xxxxxx/T/ > where this problem was raised but not successfully resolved. > > Signed-off-by: NeilBrown <neilb@xxxxxxx> > Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx> > Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> > --- > fs/nfsd/nfs4state.c | 11 +++++++---- > 1 file changed, 7 insertions(+), 4 deletions(-) > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c > index 47e879d5d68a..05181b4a3ce8 100644 > --- a/fs/nfsd/nfs4state.c > +++ b/fs/nfsd/nfs4state.c > @@ -6998,7 +6998,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, > return status; > } > > -static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) > +static bool nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) > { > struct nfs4_client *clp = s->st_stid.sc_client; > bool unhashed; > @@ -7015,11 +7015,11 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) > list_for_each_entry(stp, &reaplist, st_locks) > nfs4_free_cpntf_statelist(clp->net, &stp->st_stid); > free_ol_stateid_reaplist(&reaplist); > + return false; > } else { > spin_unlock(&clp->cl_lock); > free_ol_stateid_reaplist(&reaplist); > - if (unhashed) > - move_to_close_lru(s, clp->net); > + return unhashed; > } > } > > @@ -7035,6 +7035,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > struct nfs4_ol_stateid *stp; > struct net *net = SVC_NET(rqstp); > struct nfsd_net *nn = net_generic(net, nfsd_net_id); > + bool need_move_to_close_list; > > dprintk("NFSD: nfsd4_close on file %pd\n", > cstate->current_fh.fh_dentry); > @@ -7057,8 +7058,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > */ > nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); > > - nfsd4_close_open_stateid(stp); > + need_move_to_close_list = nfsd4_close_open_stateid(stp); > mutex_unlock(&stp->st_mutex); > + if (need_move_to_close_list) > + move_to_close_lru(stp, net); > > /* v4.1+ suggests that we send a special stateid in here, since the > * clients should just ignore this anyway. Since this is not useful Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>