Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 05 Feb 2026 19:55:43 +0000
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 406c98d2ca1d - stable/15 - nfscl: Fix handling of case insensitive file systems
Message-ID:  <6984f5bf.3dfc0.3deb31dd@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by rmacklem:

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

commit 406c98d2ca1de620973446034bf487cd47e78598
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2026-01-21 00:21:52 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2026-02-05 19:53:58 +0000

    nfscl: Fix handling of case insensitive file systems
    
    Name caching must be handled somewhat differently
    for case insensitive file systems.  Negative name
    caching does not work and, for rename, all names
    associated with the rename'd vnode must be disabled.
    
    For a case insensitive ZFS file system that is exported,
    the unpatched code did work, since the change in mtime
    or ctime of the directory when other case names were
    created or rename'd would disable the false name cache
    hit.  However, an export of an msdosfs file system
    breaks the NFS client, because it only works if ctime/mtime
    is changed whenever a name is added/removed.  Depending
    on what the server file system is, this may not happen,
    due to clock resolution or lack of support for these
    attributes.
    
    This patch checks to see if the server file system is
    case insensitive and modifies the name caching to handle
    this.
    
    There is still a problem if a case insensitive file system
    is a subtree of a non-case insensitive is exported by the
    NFSv4 server.  This can be fixed someday, when the NFSv4
    client gets support for submounts within the mount.
    
    (cherry picked from commit f2155a6fb5681c3dca4524a3b2b862a72218a541)
---
 sys/fs/nfs/nfsport.h            |  2 ++
 sys/fs/nfsclient/nfs_clrpcops.c | 19 ++++++++++++++++---
 sys/fs/nfsclient/nfs_clvnops.c  | 12 +++++++++++-
 3 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 4e9aae70da6f..f6b6cfb22908 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -1040,6 +1040,7 @@ void ncl_copy_vattr(struct vnode *vp, struct vattr *dst, struct vattr *src);
 #define	NFSSTA_HASWRITEVERF	0x00040000  /* Has write verifier */
 #define	NFSSTA_GOTFSINFO	0x00100000  /* Got the fsinfo */
 #define	NFSSTA_OPENMODE		0x00200000  /* Must use correct open mode */
+#define	NFSSTA_CASEINSENSITIVE	0x00400000  /* Case insensitive fs */
 #define	NFSSTA_FLEXFILE		0x00800000  /* Use Flex File Layout */
 #define	NFSSTA_NOLAYOUTCOMMIT	0x04000000  /* Don't do LayoutCommit */
 #define	NFSSTA_SESSPERSIST	0x08000000  /* Has a persistent session */
@@ -1073,6 +1074,7 @@ void ncl_copy_vattr(struct vnode *vp, struct vattr *dst, struct vattr *src);
 #define	NFSHASPNFS(n)		((n)->nm_state & NFSSTA_PNFS)
 #define	NFSHASFLEXFILE(n)	((n)->nm_state & NFSSTA_FLEXFILE)
 #define	NFSHASOPENMODE(n)	((n)->nm_state & NFSSTA_OPENMODE)
+#define	NFSHASCASEINSENSITIVE(n) ((n)->nm_state & NFSSTA_CASEINSENSITIVE)
 #define	NFSHASONEOPENOWN(n)	(((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&	\
 				    (n)->nm_minorvers > 0)
 #define	NFSHASTLS(n)		(((n)->nm_newflag & NFSMNT_TLS) != 0)
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 9bdc2b776575..a0423ab23111 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -4995,11 +4995,13 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
     uint32_t *leasep, uint32_t *cloneblksizep, struct ucred *cred, NFSPROC_T *p,
     struct nfsvattr *nap, int *attrflagp)
 {
+	struct nfsvattr na;
+	struct nfsv3_pathconf pc;
 	u_int32_t *tl = NULL;
 	struct nfsrv_descript nfsd, *nd = &nfsd;
 	struct nfsmount *nmp;
 	nfsattrbit_t attrbits;
-	int error;
+	int attrflag, error;
 
 	*attrflagp = 0;
 	if (cloneblksizep != NULL)
@@ -5066,6 +5068,15 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
 		sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
 		sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
 	}
+
+	/* Try and find out if the server fs is case-insensitive. */
+	error = nfsrpc_pathconf(vp, &pc, NULL, NULL, cred, p, &na, &attrflag);
+	if (error == 0 && pc.pc_caseinsensitive != 0) {
+		NFSLOCKMNT(nmp);
+		nmp->nm_state |= NFSSTA_CASEINSENSITIVE;
+		NFSUNLOCKMNT(nmp);
+	}
+	error = 0;
 nfsmout:
 	m_freem(nd->nd_mrep);
 	return (error);
@@ -5086,9 +5097,11 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp,
 	int error;
 	struct nfsnode *np;
 
-	*has_namedattrp = false;
+	if (has_namedattrp != NULL)
+		*has_namedattrp = false;
 	*attrflagp = 0;
-	*clone_blksizep = 0;
+	if (clone_blksizep != NULL)
+		*clone_blksizep = 0;
 	nmp = VFSTONFS(vp->v_mount);
 	if (NFSHASNFSV4(nmp)) {
 		np = VTONFS(vp);
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 7ecd1619a0ad..0d54b869d74c 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1492,7 +1492,8 @@ handle_error:
 			return (EJUSTRETURN);
 		}
 
-		if ((cnp->cn_flags & MAKEENTRY) != 0 && dattrflag) {
+		if ((cnp->cn_flags & MAKEENTRY) != 0 && dattrflag &&
+		    !NFSHASCASEINSENSITIVE(nmp)) {
 			/*
 			 * Cache the modification time of the parent
 			 * directory from the post-op attributes in
@@ -2205,6 +2206,14 @@ nfs_rename(struct vop_rename_args *ap)
 	if ((error = NFSVOPLOCK(fvp, LK_EXCLUSIVE)) != 0)
 		goto out;
 
+	/*
+	 * For case insensitive file systems, there may be multiple
+	 * names cached for the one name being rename'd, so purge
+	 * all names from the cache.
+	 */
+	if (NFSHASCASEINSENSITIVE(nmp))
+		cache_purge(fvp);
+
 	/*
 	 * We have to flush B_DELWRI data prior to renaming
 	 * the file.  If we don't, the delayed-write buffers
@@ -2221,6 +2230,7 @@ nfs_rename(struct vop_rename_args *ap)
 	if ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || !NFSHASNFSV4(nmp) ||
 	    !NFSHASNFSV4N(nmp) || nfscl_mustflush(fvp) != 0)
 		error = VOP_FSYNC(fvp, MNT_WAIT, curthread);
+
 	NFSVOPUNLOCK(fvp);
 	if (error == 0 && tvp != NULL && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 ||
 	    !NFSHASNFSV4(nmp) || !NFSHASNFSV4N(nmp) ||


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6984f5bf.3dfc0.3deb31dd>