git: 9419e086e1a3 - main - nfscommon: Use _PC_HAS_NAMEDATTR to check for named attributes

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Mon, 05 May 2025 00:55:58 UTC
The branch main has been updated by rmacklem:

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

commit 9419e086e1a37124d11e428892d60a514e5c579e
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-05-05 00:52:50 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-05-05 00:52:50 +0000

    nfscommon: Use _PC_HAS_NAMEDATTR to check for named attributes
    
    Commit 0f12c3cd0ddb added the _PC_HAS_NAMEDATTR name for pathconf(2).
    This commit uses this to determine if named attributes are
    associated with a file handle for the named_attr NFSv4
    attribute.
    
    This avoids the need for nfs_test_namedattr() function.
---
 sys/fs/nfs/nfs_commonsubs.c | 98 ++++++++++++---------------------------------
 sys/fs/nfs/nfsproto.h       |  2 +
 2 files changed, 27 insertions(+), 73 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 3e70eb50a54e..f3305ccdde80 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -223,7 +223,6 @@ static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
 
 /* local functions */
 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
-static bool nfs_test_namedattr(struct nfsrv_descript *nd, struct vnode *vp);
 static void nfsv4_wanted(struct nfsv4lock *lp);
 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
@@ -1282,70 +1281,6 @@ nfsmout:
 	return (error);
 }
 
-/*
- * Check to see if a named attribute exists for this file.
- */
-static bool
-nfs_test_namedattr(struct nfsrv_descript *nd, struct vnode *vp)
-{
-	struct uio io;
-	struct iovec iv;
-	struct componentname cn;
-	struct vnode *dvp;
-	struct dirent *dp;
-	int eofflag, error;
-	char *buf, *cp, *endcp;
-	bool ret;
-
-	if (vp == NULL || (vp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0)
-		return (false);
-	NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
-	    NOFOLLOW | LOCKLEAF);
-	cn.cn_lkflags = LK_SHARED;
-	cn.cn_nameptr = ".";
-	cn.cn_namelen = 1;
-	error = VOP_LOOKUP(vp, &dvp, &cn);
-	if (error != 0)
-		return (false);
-
-	/* Now we have to read the directory, looking for a valid entry. */
-	buf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK);
-	ret = false;
-	io.uio_offset = 0;
-	io.uio_segflg = UIO_SYSSPACE;
-	io.uio_rw = UIO_READ;
-	io.uio_td = NULL;
-	do {
-		iv.iov_base = buf;
-		iv.iov_len = DIRBLKSIZ;
-		io.uio_iov = &iv;
-		io.uio_iovcnt = 1;
-		io.uio_resid = DIRBLKSIZ;
-		error = VOP_READDIR(dvp, &io, nd->nd_cred, &eofflag, NULL,
-		    NULL);
-		if (error != 0 || io.uio_resid == DIRBLKSIZ)
-			break;
-		cp = buf;
-		endcp = &buf[DIRBLKSIZ - io.uio_resid];
-		while (cp < endcp) {
-			dp = (struct dirent *)cp;
-			if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
-			    ((dp->d_namlen == 1 && dp->d_name[0] != '.') ||
-			     (dp->d_namlen == 2 && (dp->d_name[0] != '.' ||
-			      dp->d_name[1] != '.')) || dp->d_namlen > 2)) {
-				ret = true;
-				break;
-			}
-			cp += dp->d_reclen;
-		}
-		if (ret)
-			break;
-	} while (eofflag == 0);
-	vput(dvp);
-	free(buf, M_TEMP);
-	return (ret);
-}
-
 /*
  * Get the attributes for V4.
  * If the compare flag is true, test for any attribute changes,
@@ -1442,6 +1377,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 			pc->pc_chownrestricted = 0;
 			pc->pc_caseinsensitive = 0;
 			pc->pc_casepreserving = 1;
+			pc->pc_has_namedattr = false;
 		}
 		if (sfp != NULL) {
 			sfp->sf_ffiles = UINT64_MAX;
@@ -1581,13 +1517,25 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 			break;
 		case NFSATTRBIT_NAMEDATTR:
 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
-			if (compare && !(*retcmpp)) {
-				bool named_attr;
-
-				named_attr = nfs_test_namedattr(nd, vp);
-				if ((named_attr && *tl != newnfs_true) ||
-				    (!named_attr && *tl != newnfs_false))
-					*retcmpp = NFSERR_NOTSAME;
+			if (compare) {
+				if (!(*retcmpp)) {
+					long has_named_attr;
+
+					if (vp == NULL || VOP_PATHCONF(vp,
+					    _PC_HAS_NAMEDATTR, &has_named_attr)
+					    != 0)
+						has_named_attr = 0;
+					if ((has_named_attr != 0 &&
+					     *tl != newnfs_true) ||
+					    (has_named_attr == 0 &&
+					    *tl != newnfs_false))
+						*retcmpp = NFSERR_NOTSAME;
+				}
+			} else if (pc != NULL) {
+				if (*tl == newnfs_true)
+					pc->pc_has_namedattr = true;
+				else
+					pc->pc_has_namedattr = false;
 			}
 			attrsum += NFSX_UNSIGNED;
 			break;
@@ -2684,6 +2632,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
 	size_t atsiz;
 	bool xattrsupp;
 	short irflag;
+	long has_named_attr;
 #ifdef QUOTA
 	struct dqblk dqb;
 	uid_t savuid;
@@ -2840,7 +2789,10 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
 			break;
 		case NFSATTRBIT_NAMEDATTR:
 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
-			if (nfs_test_namedattr(nd, vp))
+			if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, &has_named_attr)
+			    != 0)
+				has_named_attr = 0;
+			if (has_named_attr != 0)
 				*tl = newnfs_true;
 			else
 				*tl = newnfs_false;
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index d0660cafdedb..0a11e906569d 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -1414,6 +1414,7 @@ struct nfsv3_sattr {
  * NFSGETATTRBIT_PATHCONF0 - bits 0<->31
  */
 #define	NFSGETATTRBIT_PATHCONF0	(NFSATTRBIT_GETATTR0 |			\
+				NFSATTRBM_NAMEDATTR |			\
 			 	NFSATTRBM_CASEINSENSITIVE |		\
 			 	NFSATTRBM_CASEPRESERVING |		\
 			 	NFSATTRBM_CHOWNRESTRICTED |		\
@@ -1645,6 +1646,7 @@ struct nfsv3_pathconf {
 	u_int32_t pc_chownrestricted;
 	u_int32_t pc_caseinsensitive;
 	u_int32_t pc_casepreserving;
+	bool pc_has_namedattr;
 };
 
 /*