diff mbox series

[v2,3/3] NFSD: Make nfsd4_rename() wait before returning NFS4ERR_DELAY

Message ID 165953746619.1658.12640644653566498600.stgit@manet.1015granger.net (mailing list archive)
State New, archived
Headers show
Series Wait for DELEGRETURN before returning NFS4ERR_DELAY | expand

Commit Message

Chuck Lever Aug. 3, 2022, 2:37 p.m. UTC
nfsd_rename() can kick off a CB_RECALL (via
vfs_rename() -> leases_conflict()) 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_rename()
again, once.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs4proc.c |   31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 62a267bb2ce5..2e484aafc41c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1056,17 +1056,32 @@  nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
 	struct nfsd4_rename *rename = &u->rename;
 	__be32 status;
+	int retries;
 
 	if (opens_in_grace(SVC_NET(rqstp)))
 		return nfserr_grace;
-	status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
-			     rename->rn_snamelen, &cstate->current_fh,
-			     rename->rn_tname, rename->rn_tnamelen);
-	if (status)
-		return status;
-	set_change_info(&rename->rn_sinfo, &cstate->current_fh);
-	set_change_info(&rename->rn_tinfo, &cstate->save_fh);
-	return nfs_ok;
+
+	retries = 1;
+	do {
+		status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
+				     rename->rn_snamelen, &cstate->current_fh,
+				     rename->rn_tname, rename->rn_tnamelen);
+		if (status == nfs_ok) {
+			set_change_info(&rename->rn_sinfo, &cstate->current_fh);
+			set_change_info(&rename->rn_tinfo, &cstate->save_fh);
+			break;
+		}
+		if (status != nfserr_jukebox)
+			break;
+		if (!retries--)
+			break;
+
+		fh_clear_pre_post_attrs(&cstate->save_fh);
+		fh_clear_pre_post_attrs(&cstate->current_fh);
+		nfsd4_wait_for_delegreturn(rqstp, &cstate->current_fh);
+	} while (1);
+
+	return status;
 }
 
 static __be32