Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 4 May 2024 21:32:36 GMT
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 3f65000b6b14 - main - nfsd: Fix Link conformance with RFC8881 for delegations
Message-ID:  <202405042132.444LWaDF089086@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by rmacklem:

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

commit 3f65000b6b1460a7a23cd83014bb41a68d1a8a19
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-05-04 21:30:07 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-05-04 21:30:07 +0000

    nfsd: Fix Link conformance with RFC8881 for delegations
    
    RFC8881 specifies that, when a Link operation occurs on an
    NFSv4, that file delegations issued to other clients must
    be recalled.  Discovered during a recent discussion on nfsv4@ietf.org.
    
    Although I have not observed a problem caused by not doing
    the required delegation recall, it is definitely required
    by the RFC, so this patch makes the server do the recall.
    
    Tested during a recent NFSv4 IETF Bakeathon event.
    
    MFC after:      1 week
---
 sys/fs/nfs/nfs_var.h            |  2 +-
 sys/fs/nfsserver/nfs_nfsdport.c | 12 +++++++-----
 sys/fs/nfsserver/nfs_nfsdserv.c | 11 +++++++++--
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 578fb3ce1340..950e0c097457 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -713,7 +713,7 @@ int nfsvno_rmdirsub(struct nameidata *, int, struct ucred *, NFSPROC_T *,
     struct nfsexstuff *);
 int nfsvno_rename(struct nameidata *, struct nameidata *, u_int32_t,
     u_int32_t, struct ucred *, NFSPROC_T *);
-int nfsvno_link(struct nameidata *, vnode_t, struct ucred *,
+int nfsvno_link(struct nameidata *, vnode_t, nfsquad_t, struct ucred *,
     NFSPROC_T *, struct nfsexstuff *);
 int nfsvno_fsync(vnode_t, u_int64_t, int, struct ucred *, NFSPROC_T *);
 int nfsvno_statfs(vnode_t, struct statfs *);
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 5eb16564cf00..6f5b2855bcf0 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1655,8 +1655,8 @@ out1:
  * Link vnode op.
  */
 int
-nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred,
-    struct thread *p, struct nfsexstuff *exp)
+nfsvno_link(struct nameidata *ndp, struct vnode *vp, nfsquad_t clientid,
+    struct ucred *cred, struct thread *p, struct nfsexstuff *exp)
 {
 	struct vnode *xp;
 	int error = 0;
@@ -1671,9 +1671,11 @@ nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred,
 	}
 	if (!error) {
 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
-		if (!VN_IS_DOOMED(vp))
-			error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
-		else
+		if (!VN_IS_DOOMED(vp)) {
+			error = nfsrv_checkremove(vp, 0, NULL, clientid, p);
+			if (error == 0)
+				error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
+		} else
 			error = EPERM;
 		if (ndp->ni_dvp == vp) {
 			vrele(ndp->ni_dvp);
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 8141ee6cbdb6..0c8bda6dc6a6 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -1797,6 +1797,7 @@ nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
 	char *bufp;
 	u_long *hashp;
 	struct thread *p = curthread;
+	nfsquad_t clientid;
 
 	if (nd->nd_repstat) {
 		nfsrv_postopattr(nd, getret, &at);
@@ -1858,8 +1859,14 @@ nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
 			    NULL);
 		}
 	}
-	if (!nd->nd_repstat)
-		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
+	if (!nd->nd_repstat) {
+		clientid.qval = 0;
+		if ((nd->nd_flag & (ND_IMPLIEDCLID | ND_NFSV41)) ==
+		    (ND_IMPLIEDCLID | ND_NFSV41))
+			clientid.qval = nd->nd_clientid.qval;
+		nd->nd_repstat = nfsvno_link(&named, vp, clientid, nd->nd_cred,
+		    p, exp);
+	}
 	if (nd->nd_flag & ND_NFSV3)
 		getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
 	if (dirp) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202405042132.444LWaDF089086>