diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2022-09-09 01:14:13 +0300 |
---|---|---|
committer | Chuck Lever <chuck.lever@oracle.com> | 2022-09-26 21:02:36 +0300 |
commit | 34b91dda7124fc3259e4b2ae53e0c933dedfec01 (patch) | |
tree | a8acecaef866284c74efcb58f0d22c91cc12cdbc /fs/nfsd | |
parent | c0aa1913db57219e91a0a8832363cbafb3a9cf8f (diff) | |
download | linux-34b91dda7124fc3259e4b2ae53e0c933dedfec01.tar.xz |
NFSD: Make nfsd4_setattr() wait before returning NFS4ERR_DELAY
nfsd_setattr() can kick off a CB_RECALL (via
notify_change() -> break_lease()) if a delegation is present. Before
returning NFS4ERR_DELAY, give the client holding that delegation a
chance to return it and then retry the nfsd_setattr() again, once.
Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=354
Tested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/vfs.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7c17b4a93168..d4db595d33ea 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -413,6 +413,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, int host_err; bool get_write_count; bool size_change = (iap->ia_valid & ATTR_SIZE); + int retries; if (iap->ia_valid & ATTR_SIZE) { accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; @@ -467,7 +468,13 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, } inode_lock(inode); - host_err = __nfsd_setattr(dentry, iap); + for (retries = 1;;) { + host_err = __nfsd_setattr(dentry, iap); + if (host_err != -EAGAIN || !retries--) + break; + if (!nfsd_wait_for_delegreturn(rqstp, inode)) + break; + } if (attr->na_seclabel && attr->na_seclabel->len) attr->na_labelerr = security_inode_setsecctx(dentry, attr->na_seclabel->data, attr->na_seclabel->len); |