]> www.infradead.org Git - users/hch/configfs.git/commitdiff
nfsd: fix nfsd4_deleg_getattr_conflict in presence of third party lease
authorNeilBrown <neilb@suse.de>
Wed, 28 Aug 2024 23:06:28 +0000 (09:06 +1000)
committerChuck Lever <chuck.lever@oracle.com>
Fri, 30 Aug 2024 14:48:29 +0000 (10:48 -0400)
It is not safe to dereference fl->c.flc_owner without first confirming
fl->fl_lmops is the expected manager.  nfsd4_deleg_getattr_conflict()
tests fl_lmops but largely ignores the result and assumes that flc_owner
is an nfs4_delegation anyway.  This is wrong.

With this patch we restore the "!= &nfsd_lease_mng_ops" case to behave
as it did before the change mentioned below.  This is the same as the
current code, but without any reference to a possible delegation.

Fixes: c5967721e106 ("NFSD: handle GETATTR conflict with write delegation")
Signed-off-by: NeilBrown <neilb@suse.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4state.c

index 07f2496850c4c63e0e0bd765160da71e10aacedb..a366fb1c1b9b4f23a290ed96449ce0614a149207 100644 (file)
@@ -8859,7 +8859,15 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
                         */
                        if (type == F_RDLCK)
                                break;
-                       goto break_lease;
+
+                       nfsd_stats_wdeleg_getattr_inc(nn);
+                       spin_unlock(&ctx->flc_lock);
+
+                       status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
+                       if (status != nfserr_jukebox ||
+                           !nfsd_wait_for_delegreturn(rqstp, inode))
+                               return status;
+                       return 0;
                }
                if (type == F_WRLCK) {
                        struct nfs4_delegation *dp = fl->c.flc_owner;
@@ -8868,7 +8876,6 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
                                spin_unlock(&ctx->flc_lock);
                                return 0;
                        }
-break_lease:
                        nfsd_stats_wdeleg_getattr_inc(nn);
                        dp = fl->c.flc_owner;
                        refcount_inc(&dp->dl_stid.sc_count);