git: 96b2f4a91241 - main - p9fs: implement basic pathconf support

From: Alex Richardson <arichardson_at_FreeBSD.org>
Date: Thu, 07 May 2026 05:02:55 UTC
The branch main has been updated by arichardson:

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

commit 96b2f4a9124158f27c4c27c32f6fa1a6018250fb
Author:     Alex Richardson <arichardson@FreeBSD.org>
AuthorDate: 2026-05-07 04:22:23 +0000
Commit:     Alex Richardson <arichardson@FreeBSD.org>
CommitDate: 2026-05-07 04:23:04 +0000

    p9fs: implement basic pathconf support
    
    This is needed for various pjdfstest tests which fail with syntax errors
    if pathconf _PC_NAME_MAX/_PC_PATH_MAX return -1. For NAME_MAX we can use
    the 9P2000.L Tstatfs call to get namelen from the host. While this could
    theoretically be different for nested filesystems in the shared mount it
    is a much better guess than just returning 255.
    There does not seem to be a way to get the host PATH_MAX, so we just
    return the conservative kernel default.
    
    Found while fixing https://github.com/CTSRD-CHERI/cheribsd/issues/2617.
    
    Reviewed by:    markj, kib
    MFC after:      1 week
    Differential Revision: https://reviews.freebsd.org/D56493
---
 sys/fs/p9fs/p9fs.h       |  1 +
 sys/fs/p9fs/p9fs_vnops.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/sys/fs/p9fs/p9fs.h b/sys/fs/p9fs/p9fs.h
index 2470734fef4d..b469495ef69e 100644
--- a/sys/fs/p9fs/p9fs.h
+++ b/sys/fs/p9fs/p9fs.h
@@ -154,6 +154,7 @@ struct p9fs_session {
 	struct mtx p9fs_mtx;				/* mutex used for guarding the chain.*/
 	STAILQ_HEAD( ,p9fs_node) virt_node_list;	/* list of p9fs nodes in this session*/
 	struct p9_fid *mnt_fid;				/* to save nobody 's fid for unmounting as root user */
+	unsigned int name_max;				/* cached max filename length */
 };
 
 struct p9fs_mount {
diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c
index 7141e9700602..ad739a219acb 100644
--- a/sys/fs/p9fs/p9fs_vnops.c
+++ b/sys/fs/p9fs/p9fs_vnops.c
@@ -37,10 +37,12 @@
 #include <sys/fcntl.h>
 #include <sys/namei.h>
 #include <sys/priv.h>
-#include <sys/stat.h>
-#include <sys/vnode.h>
 #include <sys/rwlock.h>
+#include <sys/stat.h>
+#include <sys/syslimits.h>
+#include <sys/unistd.h>
 #include <sys/vmmeter.h>
+#include <sys/vnode.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
@@ -2248,6 +2250,72 @@ p9fs_delayed_setsize(struct vop_delayed_setsize_args *ap)
 	return (0);
 }
 
+static unsigned int
+p9fs_get_name_max(struct p9fs_node *np)
+{
+	struct p9fs_session *vses = np->p9fs_ses;
+	struct p9_statfs statfs;
+	struct p9_fid *vfid;
+	unsigned int name_max;
+	int error = 0;
+
+	name_max = atomic_load_int(&vses->name_max);
+	if (name_max != 0)
+		return (name_max);
+
+	P9_DEBUG(VOPS, "%s: querying _PC_NAME_MAX\n", __func__);
+	vfid = p9fs_get_fid(vses->clnt, np, NULL, VFID, -1, &error);
+	if (vfid != NULL) {
+		error = p9_client_statfs(vfid, &statfs);
+		if (error == 0) {
+			/*
+			 * Note that this is not strictly correct if you have
+			 * nested mounts on the host (e.g. when using qemu with
+			 * multidevs=remap), but is a better estimate than just
+			 * returning 255.
+			 */
+			name_max = statfs.namelen;
+		}
+	}
+	P9_DEBUG(VOPS, "%s: max_name=%u error=%d\n", __func__, name_max, error);
+	if (error != 0 || name_max == 0) {
+		printf("p9fs: warning: failed to query name_max (error %d), "
+		    "using fallback %d\n", error, NAME_MAX);
+		name_max = NAME_MAX; /* fallback and prevent retrying */
+	}
+	atomic_store_int(&vses->name_max, name_max);
+	return (name_max);
+}
+
+/*
+ * Return POSIX pathconf information applicable to p9fs filesystems.
+ */
+static int
+p9fs_pathconf(struct vop_pathconf_args *ap)
+{
+	int error = 0;
+	struct vnode *vp = ap->a_vp;
+	struct p9fs_node *np = P9FS_VTON(vp);
+
+	switch (ap->a_name) {
+	case _PC_NAME_MAX:
+		*ap->a_retval = p9fs_get_name_max(np);
+		break;
+	case _PC_SYMLINK_MAX:
+	case _PC_PATH_MAX:
+		/*
+		 * These are conservative estimates, the real value depends on
+		 * the host file system.
+		 */
+		*ap->a_retval = MAXPATHLEN;
+		break;
+	default:
+		error = vop_stdpathconf(ap);
+		break;
+	}
+	return (error);
+}
+
 struct vop_vector p9fs_vnops = {
 	.vop_default =		&default_vnodeops,
 	.vop_lookup =		p9fs_lookup,
@@ -2257,6 +2325,7 @@ struct vop_vector p9fs_vnops = {
 	.vop_delayed_setsize =	p9fs_delayed_setsize,
 	.vop_getattr =		p9fs_getattr_dotl,
 	.vop_setattr =		p9fs_setattr_dotl,
+	.vop_pathconf =		p9fs_pathconf,
 	.vop_reclaim =		p9fs_reclaim,
 	.vop_inactive =		p9fs_inactive,
 	.vop_readdir =		p9fs_readdir,