From: Chuck Lever Date: Thu, 8 Sep 2022 22:14:13 +0000 (-0400) Subject: NFSD: Make nfsd4_setattr() wait before returning NFS4ERR_DELAY X-Git-Tag: block-6.1-2022-13-10~94^2~29 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=34b91dda7124;p=linux-block.git 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 Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton --- 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);