Re: [PATCH 12/13] nfsd: check for delegation conflicts vs. the same client
NeilBrown <[email protected]>
| Newsgroups | org.kernel.vger.ecryptfs,dev.linux.lists.netfs,org.kernel.vger.linux-cifs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.kernel.vger.linux-unionfs,org.kernel.vger.linux-xfs,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On Tue, 14 Oct 2025, Jeff Layton wrote: > RFC 8881 requires that the server reply with GDD_UNAVAIL when the client GDD4_UNAVAIL. Then "git grep" finds it for me. NeilBrown > requests a directory delegation that it already holds. > > When setting a directory delegation, check that the client associated > with the stateid doesn't match an existing delegation. If it does, > reject the setlease attempt. > > Signed-off-by: Jeff Layton <[email protected]> > --- > fs/nfsd/nfs4state.c | 29 ++++++++++++++++++++++++++++- > 1 file changed, 28 insertions(+), 1 deletion(-) > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c > index b06591f154aa372db710e071c69260f4639956d7..011e336dfd996daa82b706c3536628971369fb10 100644 > --- a/fs/nfsd/nfs4state.c > +++ b/fs/nfsd/nfs4state.c > @@ -88,6 +88,7 @@ void nfsd4_end_grace(struct nfsd_net *nn); > static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); > static void nfsd4_file_hash_remove(struct nfs4_file *fi); > static void deleg_reaper(struct nfsd_net *nn); > +static bool nfsd_dir_may_setlease(struct file_lease *new, struct file_lease *old); > > /* Locking: */ > > @@ -5550,6 +5551,31 @@ static const struct lease_manager_operations nfsd_lease_mng_ops = { > .lm_change = nfsd_change_deleg_cb, > }; > > +static const struct lease_manager_operations nfsd_dir_lease_mng_ops = { > + .lm_breaker_owns_lease = nfsd_breaker_owns_lease, > + .lm_break = nfsd_break_deleg_cb, > + .lm_change = nfsd_change_deleg_cb, > + .lm_may_setlease = nfsd_dir_may_setlease, > +}; > + > +static bool > +nfsd_dir_may_setlease(struct file_lease *new, struct file_lease *old) > +{ > + struct nfs4_delegation *od, *nd; > + > + /* Only conflicts with other nfsd dir delegs */ > + if (old->fl_lmops != &nfsd_dir_lease_mng_ops) > + return true; > + > + od = old->c.flc_owner; > + nd = new->c.flc_owner; > + > + /* Are these for the same client? No bueno if so */ > + if (od->dl_stid.sc_client == nd->dl_stid.sc_client) > + return false; > + return true; > +} > + > static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) > { > if (nfsd4_has_session(cstate)) > @@ -5888,12 +5914,13 @@ static struct file_lease *nfs4_alloc_init_lease(struct nfs4_delegation *dp) > fl = locks_alloc_lease(); > if (!fl) > return NULL; > - fl->fl_lmops = &nfsd_lease_mng_ops; > fl->c.flc_flags = FL_DELEG; > fl->c.flc_type = deleg_is_read(dp->dl_type) ? F_RDLCK : F_WRLCK; > fl->c.flc_owner = (fl_owner_t)dp; > fl->c.flc_pid = current->tgid; > fl->c.flc_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; > + fl->fl_lmops = S_ISDIR(file_inode(fl->c.flc_file)->i_mode) ? > + &nfsd_dir_lease_mng_ops : &nfsd_lease_mng_ops; > return fl; > } > > > -- > 2.51.0 > >