git: 709c18911ad7 - main - nfsd: Add support for the NFSv4.2 change_attr_type attribute

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Mon, 20 Jan 2025 21:52:42 UTC
The branch main has been updated by rmacklem:

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

commit 709c18911ad70978d47198556c0fb1c0e703fb68
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-01-20 21:51:33 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-01-20 21:51:33 +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
    Reported by:    Richard Kojedzinszky <richard@kojedz.in>
    Tested by:      Richard Kojedzinszky <richard@kojedz.in>
    MFC after:      2 weeks
---
 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 fc01630f77f9..d4d97f4eb966 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -2303,6 +2303,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);
@@ -3127,6 +3144,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_ */