git: a6b4af5e07af - stable/14 - nfsd: Add support for the NFSv4.2 change_attr_type attribute

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Sat, 01 Feb 2025 03:25:30 UTC
The branch stable/14 has been updated by rmacklem:

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

commit a6b4af5e07af3309695de49207f9edba524e748f
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-01-20 21:51:33 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-02-01 03:23:15 +0000

    nfsd: Add support for the NFSv4.2 change_attr_type attribute
    
    Richard Kojedzinszky reported an intermittent problem where
    the Linux NFSv4.2 client would sometimes not see changes done
    to a directory by another client, although the change attribute
    for the directory had changed.
    
    A test patch that added the change_attr_type attribute to the
    server and always returned NFS4_CHANGE_TYPE_VERSION_COUNTER_NOPNFS
    seems to have resolved the issue.  Somewhat oddly, the Linux
    knfsd server does not support this attribute but does not
    seem to exhibit the stale caching problem.
    
    This patch uses the VFCF_FILEREVINC flag on a file system (UFS, ZFS)
    to return NFS4_CHANGE_TYPE_VERSION_COUNTER_NOPNFS.  It also
    returns NFS4_CHANGE_TYPE_TIME_METADATA if VFCF_FILEREVCT is set,
    which may be useful for exported fuse file systems.
    
    PR:     284186
    
    (cherry picked from commit 709c18911ad70978d47198556c0fb1c0e703fb68)
---
 sys/fs/nfs/nfs_commonsubs.c | 32 ++++++++++++++++++++++++++++++++
 sys/fs/nfs/nfsproto.h       | 11 ++++++++++-
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 510e497bce2e..9e10bba28c90 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -2307,6 +2307,23 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 			if (compare && !(*retcmpp) && i != nfs_srvmaxio)
 				*retcmpp = NFSERR_NOTSAME;
 			break;
+		case NFSATTRBIT_CHANGEATTRTYPE:
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			if (compare) {
+				if (!(*retcmpp)) {
+				    tuint = NFSV4CHANGETYPE_UNDEFINED;
+				    if ((vp->v_mount->mnt_vfc->vfc_flags &
+					VFCF_FILEREVINC) != 0)
+					tuint = NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS;
+				    else if ((vp->v_mount->mnt_vfc->vfc_flags &
+					VFCF_FILEREVCT) != 0)
+					tuint = NFSV4CHANGETYPE_TIME_METADATA;
+				    if (fxdr_unsigned(uint32_t, *tl) != tuint)
+					*retcmpp = NFSERR_NOTSAME;
+				}
+			}
+			attrsum += NFSX_UNSIGNED;
+			break;
 		default:
 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
 				bitpos);
@@ -3131,6 +3148,21 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
 			*tl = 0;
 			retnum += 2 * NFSX_UNSIGNED;
 			break;
+		case NFSATTRBIT_CHANGEATTRTYPE:
+			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+			*tl = txdr_unsigned(NFSV4CHANGETYPE_UNDEFINED);
+			if (mp != NULL) {
+				if ((mp->mnt_vfc->vfc_flags &
+				    VFCF_FILEREVINC) != 0)
+					*tl = txdr_unsigned(
+					   NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS);
+				else if ((mp->mnt_vfc->vfc_flags &
+				    VFCF_FILEREVCT) != 0)
+					*tl = txdr_unsigned(
+					   NFSV4CHANGETYPE_TIME_METADATA);
+			}
+			retnum += NFSX_UNSIGNED;
+			break;
 		default:
 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
 		}
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index ce7acf102d41..323746ebbb6c 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -1176,6 +1176,7 @@ struct nfsv3_sattr {
 	NFSATTRBM_LAYOUTBLKSIZE |					\
 	NFSATTRBM_LAYOUTALIGNMENT |					\
 	NFSATTRBM_SUPPATTREXCLCREAT |					\
+	NFSATTRBM_CHANGEATTRTYPE |					\
 	NFSATTRBM_XATTRSUPPORT)
 
 /*
@@ -1221,7 +1222,8 @@ struct nfsv3_sattr {
  * NFSATTRBIT_NFSV42 - Attributes only supported by NFSv4.2.
  */
 #define	NFSATTRBIT_NFSV42_2						\
-	(NFSATTRBM_XATTRSUPPORT |					\
+	(NFSATTRBM_CHANGEATTRTYPE |					\
+	NFSATTRBM_XATTRSUPPORT |					\
 	NFSATTRBM_MODEUMASK)
 
 /*
@@ -1657,4 +1659,11 @@ typedef struct nfsv4stateid nfsv4stateid_t;
 #define	NFSV4SXATTR_CREATE	1
 #define	NFSV4SXATTR_REPLACE	2
 
+/* Values for ChangeAttrType (RFC-7862). */
+#define	NFSV4CHANGETYPE_MONOTONIC_INCR		0
+#define	NFSV4CHANGETYPE_VERS_COUNTER		1
+#define	NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS	2
+#define	NFSV4CHANGETYPE_TIME_METADATA		3
+#define	NFSV4CHANGETYPE_UNDEFINED		4
+
 #endif	/* _NFS_NFSPROTO_H_ */