git: ec1f285f2e63 - main - nfscl: Add support for the NFSv4.1/4.2 WANT_xxx flags

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Wed, 12 Jun 2024 23:12:36 UTC
The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=ec1f285f2e631b8aae3e08b3f68c6451a45c0941

commit ec1f285f2e631b8aae3e08b3f68c6451a45c0941
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-06-12 23:11:10 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-06-12 23:11:10 +0000

    nfscl: Add support for the NFSv4.1/4.2 WANT_xxx flags
    
    NFSv4.1/4.2 defined new OPEN_WANT_xxx flags that a client
    can use to hint to the server that delegations are or are
    not wanted.  This patch adds use of those delegations to
    the client.
    
    This patch should only affect the NFSv4.1/4.2 behaviour
    when delegations are enabled, which is not the default.
    
    MFC after:      1 month
---
 sys/fs/nfsclient/nfs_clrpcops.c | 77 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 9 deletions(-)

diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 8c5532268287..13bdc74655dd 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -389,13 +389,24 @@ nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
 		mode |= NFSV4OPEN_ACCESSREAD;
 	if (amode & FWRITE)
 		mode |= NFSV4OPEN_ACCESSWRITE;
+	if (NFSHASNFSV4N(nmp)) {
+		if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
+		    nfs_numnfscbd > 0) {
+			if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
+				mode |= NFSV4OPEN_WANTWRITEDELEG;
+			else
+				mode |= NFSV4OPEN_WANTANYDELEG;
+		} else
+			mode |= NFSV4OPEN_WANTNODELEG;
+	}
 	nfhp = np->n_fhp;
 
 	retrycnt = 0;
 	do {
 	    dp = NULL;
-	    error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
-		cred, p, NULL, &op, &newone, &ret, 1, true);
+	    error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len,
+		(mode & NFSV4OPEN_ACCESSBOTH), 1, cred, p, NULL,
+		&op, &newone, &ret, 1, true);
 	    if (error) {
 		return (error);
 	    }
@@ -547,7 +558,8 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
 	    cred);
 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
-	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
+	*tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH |
+	    NFSV4OPEN_WANTDELEGMASK));
 	*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
 	tsep = nfsmnt_mdssession(nmp);
 	*tl++ = tsep->nfsess_clientid.lval[0];
@@ -664,6 +676,13 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
 			    &ret, &acesize, p);
 			if (error)
 				goto nfsmout;
+		} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
+		    NFSHASNFSV4N(nmp)) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			deleg = fxdr_unsigned(uint32_t, *tl);
+			if (deleg == NFSV4OPEN_CONTENTION ||
+			    deleg == NFSV4OPEN_RESOURCE)
+				NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
 			error = NFSERR_BADXDR;
 			goto nfsmout;
@@ -1546,7 +1565,7 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
 			NFSM_BUILD(tl, uint32_t *, 6 * NFSX_UNSIGNED);
 			*tl++ = txdr_unsigned(NFSV4OP_OPEN);
 			*tl++ = 0;		/* seqid, ignored. */
-			*tl++ = txdr_unsigned(openmode);
+			*tl++ = txdr_unsigned(openmode | NFSV4OPEN_WANTNODELEG);
 			*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
 			*tl++ = 0;		/* ClientID, ignored. */
 			*tl = 0;
@@ -1668,6 +1687,13 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
 			ndp->nfsdl_stateid.other[0] = *tl++;
 			ndp->nfsdl_stateid.other[1] = *tl++;
 			ndp->nfsdl_stateid.other[2] = *tl++;
+		} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
+		    NFSHASNFSV4N(nmp)) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			deleg = fxdr_unsigned(uint32_t, *tl);
+			if (deleg == NFSV4OPEN_CONTENTION ||
+			    deleg == NFSV4OPEN_RESOURCE)
+				NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
 			error = NFSERR_BADXDR;
 			goto nfsmout;
@@ -2595,8 +2621,17 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 	 */
 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 	*tl++ = txdr_unsigned(owp->nfsow_seqid);
-	*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
-	    NFSV4OPEN_ACCESSREAD);
+	if (NFSHASNFSV4N(nmp)) {
+		if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
+		    nfs_numnfscbd > 0)
+			*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
+			    NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG);
+		else
+			*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
+			    NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG);
+	} else
+		*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
+		    NFSV4OPEN_ACCESSREAD);
 	*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
 	tsep = nfsmnt_mdssession(nmp);
 	*tl++ = tsep->nfsess_clientid.lval[0];
@@ -2714,6 +2749,13 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 			    &ret, &acesize, p);
 			if (error)
 				goto nfsmout;
+		} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
+		    NFSHASNFSV4N(nmp)) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			deleg = fxdr_unsigned(uint32_t, *tl);
+			if (deleg == NFSV4OPEN_CONTENTION ||
+			    deleg == NFSV4OPEN_RESOURCE)
+				NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
 			error = NFSERR_BADXDR;
 			goto nfsmout;
@@ -8109,7 +8151,8 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
 	    0, 0, cred);
 	NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
 	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
-	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
+	*tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH |
+	    NFSV4OPEN_WANTDELEGMASK));
 	*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
 	tsep = nfsmnt_mdssession(nmp);
 	*tl++ = tsep->nfsess_clientid.lval[0];
@@ -8210,6 +8253,13 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
 			    &ret, &acesize, p);
 			if (error != 0)
 				goto nfsmout;
+		} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
+		    NFSHASNFSV4N(nmp)) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			deleg = fxdr_unsigned(uint32_t, *tl);
+			if (deleg == NFSV4OPEN_CONTENTION ||
+			    deleg == NFSV4OPEN_RESOURCE)
+				NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
 			error = NFSERR_BADXDR;
 			goto nfsmout;
@@ -8301,8 +8351,17 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 	 */
 	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 	*tl++ = txdr_unsigned(owp->nfsow_seqid);
-	*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
-	    NFSV4OPEN_ACCESSREAD);
+	if (NFSHASNFSV4N(nmp)) {
+		if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
+		    nfs_numnfscbd > 0)
+			*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
+			    NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG);
+		else
+			*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
+			    NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG);
+	} else
+		*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
+		    NFSV4OPEN_ACCESSREAD);
 	*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
 	tsep = nfsmnt_mdssession(nmp);
 	*tl++ = tsep->nfsess_clientid.lval[0];