linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Fixes for the NFS automounter
@ 2025-08-04  1:29 Trond Myklebust
  2025-08-04  1:29 ` [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem Trond Myklebust
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Trond Myklebust @ 2025-08-04  1:29 UTC (permalink / raw)
  To: linux-nfs

From: Trond Myklebust <trond.myklebust@hammerspace.com>

This series addresses 2 sets of issues with the NFS automount
functionality:

1. Capabilities are being inherited from the parent directory instead
   of assuming that the subdirectory may have different properties than
   the parent. This is particularly problematic when the parent is a
   referral.
2. We appear to be repeating some operations unnecessarily when
   traversing a submount point.

Trond Myklebust (2):
  NFS: Fix the setting of capabilities when automounting a new
    filesystem
  NFSv4: Remove duplicate lookups, capability probes and fsinfo calls

 fs/nfs/client.c      | 44 +++++++++++++++++++++-
 fs/nfs/internal.h    |  2 +-
 fs/nfs/nfs4_fs.h     |  5 ++-
 fs/nfs/nfs4client.c  | 20 +---------
 fs/nfs/nfs4getroot.c | 14 +++----
 fs/nfs/nfs4proc.c    | 89 ++++++++++++++++++++------------------------
 6 files changed, 93 insertions(+), 81 deletions(-)

-- 
2.50.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem
  2025-08-04  1:29 [PATCH 0/2] Fixes for the NFS automounter Trond Myklebust
@ 2025-08-04  1:29 ` Trond Myklebust
  2025-08-04 16:07   ` Benjamin Coddington
  2025-08-04  1:29 ` [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls Trond Myklebust
  2025-08-24  7:00 ` [PATCH 0/2] Fixes for the NFS automounter Scott Haiden
  2 siblings, 1 reply; 9+ messages in thread
From: Trond Myklebust @ 2025-08-04  1:29 UTC (permalink / raw)
  To: linux-nfs

From: Trond Myklebust <trond.myklebust@hammerspace.com>

Capabilities cannot be inherited when we cross into a new filesystem.
They need to be reset to the minimal defaults, and then probed for
again.

Fixes: 54ceac451598 ("NFS: Share NFS superblocks per-protocol per-server per-FSID")
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/client.c     | 44 ++++++++++++++++++++++++++++++++++++++++++--
 fs/nfs/internal.h   |  2 +-
 fs/nfs/nfs4client.c | 20 +-------------------
 fs/nfs/nfs4proc.c   |  2 +-
 4 files changed, 45 insertions(+), 23 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index e13eb429b8b5..8fb4a950dd55 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -682,6 +682,44 @@ struct nfs_client *nfs_init_client(struct nfs_client *clp,
 }
 EXPORT_SYMBOL_GPL(nfs_init_client);
 
+static void nfs4_server_set_init_caps(struct nfs_server *server)
+{
+#if IS_ENABLED(CONFIG_NFS_V4)
+	/* Set the basic capabilities */
+	server->caps = server->nfs_client->cl_mvops->init_caps;
+	if (server->flags & NFS_MOUNT_NORDIRPLUS)
+		server->caps &= ~NFS_CAP_READDIRPLUS;
+	if (server->nfs_client->cl_proto == XPRT_TRANSPORT_RDMA)
+		server->caps &= ~NFS_CAP_READ_PLUS;
+
+	/*
+	 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
+	 * authentication.
+	 */
+	if (nfs4_disable_idmapping &&
+	    server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
+		server->caps |= NFS_CAP_UIDGID_NOMAP;
+#endif
+}
+
+void nfs_server_set_init_caps(struct nfs_server *server)
+{
+	switch (server->nfs_client->rpc_ops->version) {
+	case 2:
+		server->caps = NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
+		break;
+	case 3:
+		server->caps = NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
+		if (!(server->flags & NFS_MOUNT_NORDIRPLUS))
+			server->caps |= NFS_CAP_READDIRPLUS;
+		break;
+	default:
+		nfs4_server_set_init_caps(server);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(nfs_server_set_init_caps);
+
 /*
  * Create a version 2 or 3 client
  */
@@ -726,7 +764,6 @@ static int nfs_init_server(struct nfs_server *server,
 	/* Initialise the client representation from the mount data */
 	server->flags = ctx->flags;
 	server->options = ctx->options;
-	server->caps |= NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
 
 	switch (clp->rpc_ops->version) {
 	case 2:
@@ -762,6 +799,8 @@ static int nfs_init_server(struct nfs_server *server,
 	if (error < 0)
 		goto error;
 
+	nfs_server_set_init_caps(server);
+
 	/* Preserve the values of mount_server-related mount options */
 	if (ctx->mount_server.addrlen) {
 		memcpy(&server->mountd_address, &ctx->mount_server.address,
@@ -934,7 +973,6 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour
 	target->acregmax = source->acregmax;
 	target->acdirmin = source->acdirmin;
 	target->acdirmax = source->acdirmax;
-	target->caps = source->caps;
 	target->options = source->options;
 	target->auth_info = source->auth_info;
 	target->port = source->port;
@@ -1169,6 +1207,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
 	if (error < 0)
 		goto out_free_server;
 
+	nfs_server_set_init_caps(server);
+
 	/* probe the filesystem info for this server filesystem */
 	error = nfs_probe_server(server, fh);
 	if (error < 0)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 0143e0794d32..1a18d8d9be25 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -231,7 +231,7 @@ extern struct nfs_client *
 nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
 				struct nfs4_sessionid *, u32);
 extern struct nfs_server *nfs_create_server(struct fs_context *);
-extern void nfs4_server_set_init_caps(struct nfs_server *);
+extern void nfs_server_set_init_caps(struct nfs_server *);
 extern struct nfs_server *nfs4_create_server(struct fs_context *);
 extern struct nfs_server *nfs4_create_referral_server(struct fs_context *);
 extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 2ea98f1f116f..6fddf43d729c 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1074,24 +1074,6 @@ static void nfs4_session_limit_xasize(struct nfs_server *server)
 #endif
 }
 
-void nfs4_server_set_init_caps(struct nfs_server *server)
-{
-	/* Set the basic capabilities */
-	server->caps |= server->nfs_client->cl_mvops->init_caps;
-	if (server->flags & NFS_MOUNT_NORDIRPLUS)
-			server->caps &= ~NFS_CAP_READDIRPLUS;
-	if (server->nfs_client->cl_proto == XPRT_TRANSPORT_RDMA)
-		server->caps &= ~NFS_CAP_READ_PLUS;
-
-	/*
-	 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
-	 * authentication.
-	 */
-	if (nfs4_disable_idmapping &&
-			server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
-		server->caps |= NFS_CAP_UIDGID_NOMAP;
-}
-
 static int nfs4_server_common_setup(struct nfs_server *server,
 		struct nfs_fh *mntfh, bool auth_probe)
 {
@@ -1110,7 +1092,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
 	if (error < 0)
 		return error;
 
-	nfs4_server_set_init_caps(server);
+	nfs_server_set_init_caps(server);
 
 	/* Probe the root fh to retrieve its FSID and filehandle */
 	error = nfs4_get_rootfh(server, mntfh, auth_probe);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d7dc669d84c5..c7c7ec22f21d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4092,7 +4092,7 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 	};
 	int err;
 
-	nfs4_server_set_init_caps(server);
+	nfs_server_set_init_caps(server);
 	do {
 		err = nfs4_handle_exception(server,
 				_nfs4_server_capabilities(server, fhandle),
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls
  2025-08-04  1:29 [PATCH 0/2] Fixes for the NFS automounter Trond Myklebust
  2025-08-04  1:29 ` [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem Trond Myklebust
@ 2025-08-04  1:29 ` Trond Myklebust
  2025-08-04 16:43   ` Benjamin Coddington
  2025-08-24  7:00 ` [PATCH 0/2] Fixes for the NFS automounter Scott Haiden
  2 siblings, 1 reply; 9+ messages in thread
From: Trond Myklebust @ 2025-08-04  1:29 UTC (permalink / raw)
  To: linux-nfs

From: Trond Myklebust <trond.myklebust@hammerspace.com>

When crossing into a new filesystem, the NFSv4 client will look up the
new directory, and then call nfs4_server_capabilities() as well as
nfs4_do_fsinfo() at least twice.

This patch removes the duplicate calls, and reduces the initial lookup
to retrieve just a minimal set of attributes.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/nfs4_fs.h     |  5 ++-
 fs/nfs/nfs4getroot.c | 14 +++----
 fs/nfs/nfs4proc.c    | 87 ++++++++++++++++++++------------------------
 3 files changed, 48 insertions(+), 58 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index d3ca91f60fc1..c34c89af9c7d 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
 	bool	(*match_stateid)(const nfs4_stateid *,
 			const nfs4_stateid *);
 	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
-			struct nfs_fsinfo *);
+				 struct nfs_fattr *);
 	void	(*free_lock_state)(struct nfs_server *,
 			struct nfs4_lock_state *);
 	int	(*test_and_free_expired)(struct nfs_server *,
@@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
 extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int, int);
 extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, const struct cred *, struct nfs4_setclientid_res *);
 extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, const struct cred *);
-extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool);
+extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *,
+				struct nfs_fattr *, bool);
 extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, const struct cred *cred);
 extern int nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred);
 extern int nfs4_destroy_clientid(struct nfs_client *clp);
diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c
index 1a69479a3a59..e67ea345de69 100644
--- a/fs/nfs/nfs4getroot.c
+++ b/fs/nfs/nfs4getroot.c
@@ -12,30 +12,28 @@
 
 int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool auth_probe)
 {
-	struct nfs_fsinfo fsinfo;
+	struct nfs_fattr *fattr = nfs_alloc_fattr();
 	int ret = -ENOMEM;
 
-	fsinfo.fattr = nfs_alloc_fattr();
-	if (fsinfo.fattr == NULL)
+	if (fattr == NULL)
 		goto out;
 
 	/* Start by getting the root filehandle from the server */
-	ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo, auth_probe);
+	ret = nfs4_proc_get_rootfh(server, mntfh, fattr, auth_probe);
 	if (ret < 0) {
 		dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
 		goto out;
 	}
 
-	if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
-			|| !S_ISDIR(fsinfo.fattr->mode)) {
+	if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) || !S_ISDIR(fattr->mode)) {
 		printk(KERN_ERR "nfs4_get_rootfh:"
 		       " getroot encountered non-directory\n");
 		ret = -ENOTDIR;
 		goto out;
 	}
 
-	memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
+	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
 out:
-	nfs_free_fattr(fsinfo.fattr);
+	nfs_free_fattr(fattr);
 	return ret;
 }
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c7c7ec22f21d..7d2b67e06cc3 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4240,15 +4240,18 @@ static int nfs4_discover_trunking(struct nfs_server *server,
 }
 
 static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		struct nfs_fsinfo *info)
+			     struct nfs_fattr *fattr)
 {
-	u32 bitmask[3];
+	u32 bitmask[3] = {
+		[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
+		      FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,
+	};
 	struct nfs4_lookup_root_arg args = {
 		.bitmask = bitmask,
 	};
 	struct nfs4_lookup_res res = {
 		.server = server,
-		.fattr = info->fattr,
+		.fattr = fattr,
 		.fh = fhandle,
 	};
 	struct rpc_message msg = {
@@ -4257,27 +4260,20 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
 		.rpc_resp = &res,
 	};
 
-	bitmask[0] = nfs4_fattr_bitmap[0];
-	bitmask[1] = nfs4_fattr_bitmap[1];
-	/*
-	 * Process the label in the upcoming getfattr
-	 */
-	bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
-
-	nfs_fattr_init(info->fattr);
+	nfs_fattr_init(fattr);
 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		struct nfs_fsinfo *info)
+			    struct nfs_fattr *fattr)
 {
 	struct nfs4_exception exception = {
 		.interruptible = true,
 	};
 	int err;
 	do {
-		err = _nfs4_lookup_root(server, fhandle, info);
-		trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
+		err = _nfs4_lookup_root(server, fhandle, fattr);
+		trace_nfs4_lookup_root(server, fhandle, fattr, err);
 		switch (err) {
 		case 0:
 		case -NFS4ERR_WRONGSEC:
@@ -4290,8 +4286,9 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
 	return err;
 }
 
-static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
-				struct nfs_fsinfo *info, rpc_authflavor_t flavor)
+static int nfs4_lookup_root_sec(struct nfs_server *server,
+				struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+				rpc_authflavor_t flavor)
 {
 	struct rpc_auth_create_args auth_args = {
 		.pseudoflavor = flavor,
@@ -4301,7 +4298,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
 	auth = rpcauth_create(&auth_args, server->client);
 	if (IS_ERR(auth))
 		return -EACCES;
-	return nfs4_lookup_root(server, fhandle, info);
+	return nfs4_lookup_root(server, fhandle, fattr);
 }
 
 /*
@@ -4314,7 +4311,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
  * negative errno value.
  */
 static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
-			      struct nfs_fsinfo *info)
+			      struct nfs_fattr *fattr)
 {
 	/* Per 3530bis 15.33.5 */
 	static const rpc_authflavor_t flav_array[] = {
@@ -4330,8 +4327,9 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 	if (server->auth_info.flavor_len > 0) {
 		/* try each flavor specified by user */
 		for (i = 0; i < server->auth_info.flavor_len; i++) {
-			status = nfs4_lookup_root_sec(server, fhandle, info,
-						server->auth_info.flavors[i]);
+			status = nfs4_lookup_root_sec(
+				server, fhandle, fattr,
+				server->auth_info.flavors[i]);
 			if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
 				continue;
 			break;
@@ -4339,7 +4337,7 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 	} else {
 		/* no flavors specified by user, try default list */
 		for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
-			status = nfs4_lookup_root_sec(server, fhandle, info,
+			status = nfs4_lookup_root_sec(server, fhandle, fattr,
 						      flav_array[i]);
 			if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
 				continue;
@@ -4363,28 +4361,22 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
  * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
  * @server: initialized nfs_server handle
  * @fhandle: we fill in the pseudo-fs root file handle
- * @info: we fill in an FSINFO struct
+ * @fattr: we fill in a bare bones struct fattr
  * @auth_probe: probe the auth flavours
  *
  * Returns zero on success, or a negative errno.
  */
 int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
-			 struct nfs_fsinfo *info,
-			 bool auth_probe)
+			 struct nfs_fattr *fattr, bool auth_probe)
 {
 	int status = 0;
 
 	if (!auth_probe)
-		status = nfs4_lookup_root(server, fhandle, info);
+		status = nfs4_lookup_root(server, fhandle, fattr);
 
 	if (auth_probe || status == NFS4ERR_WRONGSEC)
-		status = server->nfs_client->cl_mvops->find_root_sec(server,
-				fhandle, info);
-
-	if (status == 0)
-		status = nfs4_server_capabilities(server, fhandle);
-	if (status == 0)
-		status = nfs4_do_fsinfo(server, fhandle, info);
+		status = server->nfs_client->cl_mvops->find_root_sec(
+			server, fhandle, fattr);
 
 	return nfs4_map_errors(status);
 }
@@ -10351,10 +10343,10 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
  * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
  * possible) as per RFC3530bis and RFC5661 Security Considerations sections
  */
-static int
-_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
-		    struct nfs_fsinfo *info,
-		    struct nfs4_secinfo_flavors *flavors, bool use_integrity)
+static int _nfs41_proc_secinfo_no_name(struct nfs_server *server,
+				       struct nfs_fh *fhandle,
+				       struct nfs4_secinfo_flavors *flavors,
+				       bool use_integrity)
 {
 	struct nfs41_secinfo_no_name_args args = {
 		.style = SECINFO_STYLE_CURRENT_FH,
@@ -10398,9 +10390,9 @@ _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
 	return status;
 }
 
-static int
-nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
-			   struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
+static int nfs41_proc_secinfo_no_name(struct nfs_server *server,
+				      struct nfs_fh *fhandle,
+				      struct nfs4_secinfo_flavors *flavors)
 {
 	struct nfs4_exception exception = {
 		.interruptible = true,
@@ -10412,7 +10404,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
 
 		/* try to use integrity protection with machine cred */
 		if (_nfs4_is_integrity_protected(server->nfs_client))
-			err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+			err = _nfs41_proc_secinfo_no_name(server, fhandle,
 							  flavors, true);
 
 		/*
@@ -10422,7 +10414,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
 		 * the current filesystem's rpc_client and the user cred.
 		 */
 		if (err == -NFS4ERR_WRONGSEC)
-			err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+			err = _nfs41_proc_secinfo_no_name(server, fhandle,
 							  flavors, false);
 
 		switch (err) {
@@ -10438,9 +10430,8 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
 	return err;
 }
 
-static int
-nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
-		    struct nfs_fsinfo *info)
+static int nfs41_find_root_sec(struct nfs_server *server,
+			       struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	int err;
 	struct page *page;
@@ -10456,14 +10447,14 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 	}
 
 	flavors = page_address(page);
-	err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
+	err = nfs41_proc_secinfo_no_name(server, fhandle, flavors);
 
 	/*
 	 * Fall back on "guess and check" method if
 	 * the server doesn't support SECINFO_NO_NAME
 	 */
 	if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
-		err = nfs4_find_root_sec(server, fhandle, info);
+		err = nfs4_find_root_sec(server, fhandle, fattr);
 		goto out_freepage;
 	}
 	if (err)
@@ -10488,8 +10479,8 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 			flavor = RPC_AUTH_MAXFLAVOR;
 
 		if (flavor != RPC_AUTH_MAXFLAVOR) {
-			err = nfs4_lookup_root_sec(server, fhandle,
-						   info, flavor);
+			err = nfs4_lookup_root_sec(server, fhandle, fattr,
+						   flavor);
 			if (!err)
 				break;
 		}
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem
  2025-08-04  1:29 ` [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem Trond Myklebust
@ 2025-08-04 16:07   ` Benjamin Coddington
  0 siblings, 0 replies; 9+ messages in thread
From: Benjamin Coddington @ 2025-08-04 16:07 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On 3 Aug 2025, at 21:29, Trond Myklebust wrote:

> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>
> Capabilities cannot be inherited when we cross into a new filesystem.
> They need to be reset to the minimal defaults, and then probed for
> again.
>
> Fixes: 54ceac451598 ("NFS: Share NFS superblocks per-protocol per-server per-FSID")
> Cc: stable@vger.kernel.org
> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

Reviewed-by: Benjamin Coddington <bcodding@redhat.com>

Ben


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls
  2025-08-04  1:29 ` [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls Trond Myklebust
@ 2025-08-04 16:43   ` Benjamin Coddington
  2025-08-04 16:54     ` Trond Myklebust
  0 siblings, 1 reply; 9+ messages in thread
From: Benjamin Coddington @ 2025-08-04 16:43 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On 3 Aug 2025, at 21:29, Trond Myklebust wrote:

> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>
> When crossing into a new filesystem, the NFSv4 client will look up the
> new directory, and then call nfs4_server_capabilities() as well as
> nfs4_do_fsinfo() at least twice.
>
> This patch removes the duplicate calls, and reduces the initial lookup
> to retrieve just a minimal set of attributes.
>
> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> ---
>  fs/nfs/nfs4_fs.h     |  5 ++-
>  fs/nfs/nfs4getroot.c | 14 +++----
>  fs/nfs/nfs4proc.c    | 87 ++++++++++++++++++++------------------------
>  3 files changed, 48 insertions(+), 58 deletions(-)
>
> diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> index d3ca91f60fc1..c34c89af9c7d 100644
> --- a/fs/nfs/nfs4_fs.h
> +++ b/fs/nfs/nfs4_fs.h
> @@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
>  	bool	(*match_stateid)(const nfs4_stateid *,
>  			const nfs4_stateid *);
>  	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
> -			struct nfs_fsinfo *);
> +				 struct nfs_fattr *);
>  	void	(*free_lock_state)(struct nfs_server *,
>  			struct nfs4_lock_state *);
>  	int	(*test_and_free_expired)(struct nfs_server *,
> @@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
>  extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int, int);
>  extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, const struct cred *, struct nfs4_setclientid_res *);
>  extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, const struct cred *);
> -extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool);
> +extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *,
> +				struct nfs_fattr *, bool);
>  extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, const struct cred *cred);
>  extern int nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred);
>  extern int nfs4_destroy_clientid(struct nfs_client *clp);
> diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c
> index 1a69479a3a59..e67ea345de69 100644
> --- a/fs/nfs/nfs4getroot.c
> +++ b/fs/nfs/nfs4getroot.c
> @@ -12,30 +12,28 @@
>
>  int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool auth_probe)
>  {
> -	struct nfs_fsinfo fsinfo;
> +	struct nfs_fattr *fattr = nfs_alloc_fattr();
>  	int ret = -ENOMEM;
>
> -	fsinfo.fattr = nfs_alloc_fattr();
> -	if (fsinfo.fattr == NULL)
> +	if (fattr == NULL)
>  		goto out;
>
>  	/* Start by getting the root filehandle from the server */
> -	ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo, auth_probe);
> +	ret = nfs4_proc_get_rootfh(server, mntfh, fattr, auth_probe);
>  	if (ret < 0) {
>  		dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
>  		goto out;
>  	}
>
> -	if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
> -			|| !S_ISDIR(fsinfo.fattr->mode)) {
> +	if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) || !S_ISDIR(fattr->mode)) {
>  		printk(KERN_ERR "nfs4_get_rootfh:"
>  		       " getroot encountered non-directory\n");
>  		ret = -ENOTDIR;
>  		goto out;
>  	}
>
> -	memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
> +	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
>  out:
> -	nfs_free_fattr(fsinfo.fattr);
> +	nfs_free_fattr(fattr);
>  	return ret;
>  }
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index c7c7ec22f21d..7d2b67e06cc3 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -4240,15 +4240,18 @@ static int nfs4_discover_trunking(struct nfs_server *server,
>  }
>
>  static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
> -		struct nfs_fsinfo *info)
> +			     struct nfs_fattr *fattr)
>  {
> -	u32 bitmask[3];
> +	u32 bitmask[3] = {
> +		[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
> +		      FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,

Just a thought when noticing this change --

Don't we want at least FATTR4_WORD0_FILEID and
FATTR4_WORD1_MOUNTED_ON_FILEID as well here?

Reviewed-by: Benjamin Coddington <bcodding@redhat.com>

Ben


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls
  2025-08-04 16:43   ` Benjamin Coddington
@ 2025-08-04 16:54     ` Trond Myklebust
  2025-08-04 19:07       ` Benjamin Coddington
  0 siblings, 1 reply; 9+ messages in thread
From: Trond Myklebust @ 2025-08-04 16:54 UTC (permalink / raw)
  To: Benjamin Coddington; +Cc: linux-nfs

On Mon, 2025-08-04 at 12:43 -0400, Benjamin Coddington wrote:
> On 3 Aug 2025, at 21:29, Trond Myklebust wrote:
> 
> > From: Trond Myklebust <trond.myklebust@hammerspace.com>
> > 
> > When crossing into a new filesystem, the NFSv4 client will look up
> > the
> > new directory, and then call nfs4_server_capabilities() as well as
> > nfs4_do_fsinfo() at least twice.
> > 
> > This patch removes the duplicate calls, and reduces the initial
> > lookup
> > to retrieve just a minimal set of attributes.
> > 
> > Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> > ---
> >  fs/nfs/nfs4_fs.h     |  5 ++-
> >  fs/nfs/nfs4getroot.c | 14 +++----
> >  fs/nfs/nfs4proc.c    | 87 ++++++++++++++++++++--------------------
> > ----
> >  3 files changed, 48 insertions(+), 58 deletions(-)
> > 
> > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> > index d3ca91f60fc1..c34c89af9c7d 100644
> > --- a/fs/nfs/nfs4_fs.h
> > +++ b/fs/nfs/nfs4_fs.h
> > @@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
> >  	bool	(*match_stateid)(const nfs4_stateid *,
> >  			const nfs4_stateid *);
> >  	int	(*find_root_sec)(struct nfs_server *, struct
> > nfs_fh *,
> > -			struct nfs_fsinfo *);
> > +				 struct nfs_fattr *);
> >  	void	(*free_lock_state)(struct nfs_server *,
> >  			struct nfs4_lock_state *);
> >  	int	(*test_and_free_expired)(struct nfs_server *,
> > @@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *,
> > struct nfs_server *,
> >  extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct
> > nfs4_sequence_res *, int, int);
> >  extern int nfs4_proc_setclientid(struct nfs_client *, u32,
> > unsigned short, const struct cred *, struct nfs4_setclientid_res
> > *);
> >  extern int nfs4_proc_setclientid_confirm(struct nfs_client *,
> > struct nfs4_setclientid_res *arg, const struct cred *);
> > -extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh
> > *, struct nfs_fsinfo *, bool);
> > +extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh
> > *,
> > +				struct nfs_fattr *, bool);
> >  extern int nfs4_proc_bind_conn_to_session(struct nfs_client *,
> > const struct cred *cred);
> >  extern int nfs4_proc_exchange_id(struct nfs_client *clp, const
> > struct cred *cred);
> >  extern int nfs4_destroy_clientid(struct nfs_client *clp);
> > diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c
> > index 1a69479a3a59..e67ea345de69 100644
> > --- a/fs/nfs/nfs4getroot.c
> > +++ b/fs/nfs/nfs4getroot.c
> > @@ -12,30 +12,28 @@
> > 
> >  int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh
> > *mntfh, bool auth_probe)
> >  {
> > -	struct nfs_fsinfo fsinfo;
> > +	struct nfs_fattr *fattr = nfs_alloc_fattr();
> >  	int ret = -ENOMEM;
> > 
> > -	fsinfo.fattr = nfs_alloc_fattr();
> > -	if (fsinfo.fattr == NULL)
> > +	if (fattr == NULL)
> >  		goto out;
> > 
> >  	/* Start by getting the root filehandle from the server */
> > -	ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo,
> > auth_probe);
> > +	ret = nfs4_proc_get_rootfh(server, mntfh, fattr,
> > auth_probe);
> >  	if (ret < 0) {
> >  		dprintk("nfs4_get_rootfh: getroot error = %d\n", -
> > ret);
> >  		goto out;
> >  	}
> > 
> > -	if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
> > -			|| !S_ISDIR(fsinfo.fattr->mode)) {
> > +	if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) ||
> > !S_ISDIR(fattr->mode)) {
> >  		printk(KERN_ERR "nfs4_get_rootfh:"
> >  		       " getroot encountered non-directory\n");
> >  		ret = -ENOTDIR;
> >  		goto out;
> >  	}
> > 
> > -	memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server-
> > >fsid));
> > +	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
> >  out:
> > -	nfs_free_fattr(fsinfo.fattr);
> > +	nfs_free_fattr(fattr);
> >  	return ret;
> >  }
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index c7c7ec22f21d..7d2b67e06cc3 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -4240,15 +4240,18 @@ static int nfs4_discover_trunking(struct
> > nfs_server *server,
> >  }
> > 
> >  static int _nfs4_lookup_root(struct nfs_server *server, struct
> > nfs_fh *fhandle,
> > -		struct nfs_fsinfo *info)
> > +			     struct nfs_fattr *fattr)
> >  {
> > -	u32 bitmask[3];
> > +	u32 bitmask[3] = {
> > +		[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
> > +		      FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,
> 
> Just a thought when noticing this change --
> 
> Don't we want at least FATTR4_WORD0_FILEID and
> FATTR4_WORD1_MOUNTED_ON_FILEID as well here?


Only FATTR4_WORD0_TYPE and FATTR4_WORD0_FSID are used by the caller, so
we don't actually need FATTR4_WORD0_CHANGE or FATTR4_WORD0_SIZE either.
I put them in so that the test for the auth flavour would have more
chances of catching a problem.

Note that neither FATTR4_WORD0_FILEID or FATTR4_WORD1_MOUNTED_ON_FILEID
are mandatory attributes, so I also chose to avoid them + all the
timestamps for that reason.

> 
> Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
> 
> Ben
> 

-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trondmy@kernel.org, trond.myklebust@hammerspace.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls
  2025-08-04 16:54     ` Trond Myklebust
@ 2025-08-04 19:07       ` Benjamin Coddington
  2025-08-05 13:35         ` Benjamin Coddington
  0 siblings, 1 reply; 9+ messages in thread
From: Benjamin Coddington @ 2025-08-04 19:07 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On 4 Aug 2025, at 12:54, Trond Myklebust wrote:

> On Mon, 2025-08-04 at 12:43 -0400, Benjamin Coddington wrote:
>> On 3 Aug 2025, at 21:29, Trond Myklebust wrote:
>>
>>> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>>>
>>> When crossing into a new filesystem, the NFSv4 client will look up
>>> the
>>> new directory, and then call nfs4_server_capabilities() as well as
>>> nfs4_do_fsinfo() at least twice.
>>>
>>> This patch removes the duplicate calls, and reduces the initial
>>> lookup
>>> to retrieve just a minimal set of attributes.
>>>
>>> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
>>> ---
>>>  fs/nfs/nfs4_fs.h     |  5 ++-
>>>  fs/nfs/nfs4getroot.c | 14 +++----
>>>  fs/nfs/nfs4proc.c    | 87 ++++++++++++++++++++--------------------
>>> ----
>>>  3 files changed, 48 insertions(+), 58 deletions(-)
>>>
>>> diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
>>> index d3ca91f60fc1..c34c89af9c7d 100644
>>> --- a/fs/nfs/nfs4_fs.h
>>> +++ b/fs/nfs/nfs4_fs.h
>>> @@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
>>>  	bool	(*match_stateid)(const nfs4_stateid *,
>>>  			const nfs4_stateid *);
>>>  	int	(*find_root_sec)(struct nfs_server *, struct
>>> nfs_fh *,
>>> -			struct nfs_fsinfo *);
>>> +				 struct nfs_fattr *);
>>>  	void	(*free_lock_state)(struct nfs_server *,
>>>  			struct nfs4_lock_state *);
>>>  	int	(*test_and_free_expired)(struct nfs_server *,
>>> @@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *,
>>> struct nfs_server *,
>>>  extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct
>>> nfs4_sequence_res *, int, int);
>>>  extern int nfs4_proc_setclientid(struct nfs_client *, u32,
>>> unsigned short, const struct cred *, struct nfs4_setclientid_res
>>> *);
>>>  extern int nfs4_proc_setclientid_confirm(struct nfs_client *,
>>> struct nfs4_setclientid_res *arg, const struct cred *);
>>> -extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh
>>> *, struct nfs_fsinfo *, bool);
>>> +extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh
>>> *,
>>> +				struct nfs_fattr *, bool);
>>>  extern int nfs4_proc_bind_conn_to_session(struct nfs_client *,
>>> const struct cred *cred);
>>>  extern int nfs4_proc_exchange_id(struct nfs_client *clp, const
>>> struct cred *cred);
>>>  extern int nfs4_destroy_clientid(struct nfs_client *clp);
>>> diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c
>>> index 1a69479a3a59..e67ea345de69 100644
>>> --- a/fs/nfs/nfs4getroot.c
>>> +++ b/fs/nfs/nfs4getroot.c
>>> @@ -12,30 +12,28 @@
>>>
>>>  int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh
>>> *mntfh, bool auth_probe)
>>>  {
>>> -	struct nfs_fsinfo fsinfo;
>>> +	struct nfs_fattr *fattr = nfs_alloc_fattr();
>>>  	int ret = -ENOMEM;
>>>
>>> -	fsinfo.fattr = nfs_alloc_fattr();
>>> -	if (fsinfo.fattr == NULL)
>>> +	if (fattr == NULL)
>>>  		goto out;
>>>
>>>  	/* Start by getting the root filehandle from the server */
>>> -	ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo,
>>> auth_probe);
>>> +	ret = nfs4_proc_get_rootfh(server, mntfh, fattr,
>>> auth_probe);
>>>  	if (ret < 0) {
>>>  		dprintk("nfs4_get_rootfh: getroot error = %d\n", -
>>> ret);
>>>  		goto out;
>>>  	}
>>>
>>> -	if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
>>> -			|| !S_ISDIR(fsinfo.fattr->mode)) {
>>> +	if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) ||
>>> !S_ISDIR(fattr->mode)) {
>>>  		printk(KERN_ERR "nfs4_get_rootfh:"
>>>  		       " getroot encountered non-directory\n");
>>>  		ret = -ENOTDIR;
>>>  		goto out;
>>>  	}

.. now I think we won't have fattr->mode here, more below:

>>>
>>> -	memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server-
>>>> fsid));
>>> +	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
>>>  out:
>>> -	nfs_free_fattr(fsinfo.fattr);
>>> +	nfs_free_fattr(fattr);
>>>  	return ret;
>>>  }
>>> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>>> index c7c7ec22f21d..7d2b67e06cc3 100644
>>> --- a/fs/nfs/nfs4proc.c
>>> +++ b/fs/nfs/nfs4proc.c
>>> @@ -4240,15 +4240,18 @@ static int nfs4_discover_trunking(struct
>>> nfs_server *server,
>>>  }
>>>
>>>  static int _nfs4_lookup_root(struct nfs_server *server, struct
>>> nfs_fh *fhandle,
>>> -		struct nfs_fsinfo *info)
>>> +			     struct nfs_fattr *fattr)
>>>  {
>>> -	u32 bitmask[3];
>>> +	u32 bitmask[3] = {
>>> +		[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
>>> +		      FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,
>>
>> Just a thought when noticing this change --
>>
>> Don't we want at least FATTR4_WORD0_FILEID and
>> FATTR4_WORD1_MOUNTED_ON_FILEID as well here?
>
>
> Only FATTR4_WORD0_TYPE and FATTR4_WORD0_FSID are used by the caller, so
> we don't actually need FATTR4_WORD0_CHANGE or FATTR4_WORD0_SIZE either.
> I put them in so that the test for the auth flavour would have more
> chances of catching a problem.

Ah, I see now...  we're going to call ->fsinfo() again (as you stated in the
description).

But I don't see how _CHANGE or _SIZE are used..  and as I was hunting around
there's that check in nfs4_get_rootfh() (above) for S_ISDIR(fattr->mode), but this
dropped the fsinfo call out of nfs4_proc_get_rootfh(), so I think
fattr->mode will never be set.

> Note that neither FATTR4_WORD0_FILEID or FATTR4_WORD1_MOUNTED_ON_FILEID
> are mandatory attributes, so I also chose to avoid them + all the
> timestamps for that reason.

Gotcha, making sense.  This is tricky for me to review, maybe I should just
test it..  :)

Ben


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls
  2025-08-04 19:07       ` Benjamin Coddington
@ 2025-08-05 13:35         ` Benjamin Coddington
  0 siblings, 0 replies; 9+ messages in thread
From: Benjamin Coddington @ 2025-08-05 13:35 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On 4 Aug 2025, at 15:07, Benjamin Coddington wrote:

> On 4 Aug 2025, at 12:54, Trond Myklebust wrote:
>
>> On Mon, 2025-08-04 at 12:43 -0400, Benjamin Coddington wrote:
>>> On 3 Aug 2025, at 21:29, Trond Myklebust wrote:
>>>
>>>> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>>>>
>>>> When crossing into a new filesystem, the NFSv4 client will look up
>>>> the
>>>> new directory, and then call nfs4_server_capabilities() as well as
>>>> nfs4_do_fsinfo() at least twice.
>>>>
>>>> This patch removes the duplicate calls, and reduces the initial
>>>> lookup
>>>> to retrieve just a minimal set of attributes.
>>>>
>>>> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
>>>> ---
>>>>  fs/nfs/nfs4_fs.h     |  5 ++-
>>>>  fs/nfs/nfs4getroot.c | 14 +++----
>>>>  fs/nfs/nfs4proc.c    | 87 ++++++++++++++++++++--------------------
>>>> ----
>>>>  3 files changed, 48 insertions(+), 58 deletions(-)
>>>>
>>>> diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
>>>> index d3ca91f60fc1..c34c89af9c7d 100644
>>>> --- a/fs/nfs/nfs4_fs.h
>>>> +++ b/fs/nfs/nfs4_fs.h
>>>> @@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
>>>>  	bool	(*match_stateid)(const nfs4_stateid *,
>>>>  			const nfs4_stateid *);
>>>>  	int	(*find_root_sec)(struct nfs_server *, struct
>>>> nfs_fh *,
>>>> -			struct nfs_fsinfo *);
>>>> +				 struct nfs_fattr *);
>>>>  	void	(*free_lock_state)(struct nfs_server *,
>>>>  			struct nfs4_lock_state *);
>>>>  	int	(*test_and_free_expired)(struct nfs_server *,
>>>> @@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *,
>>>> struct nfs_server *,
>>>>  extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct
>>>> nfs4_sequence_res *, int, int);
>>>>  extern int nfs4_proc_setclientid(struct nfs_client *, u32,
>>>> unsigned short, const struct cred *, struct nfs4_setclientid_res
>>>> *);
>>>>  extern int nfs4_proc_setclientid_confirm(struct nfs_client *,
>>>> struct nfs4_setclientid_res *arg, const struct cred *);
>>>> -extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh
>>>> *, struct nfs_fsinfo *, bool);
>>>> +extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh
>>>> *,
>>>> +				struct nfs_fattr *, bool);
>>>>  extern int nfs4_proc_bind_conn_to_session(struct nfs_client *,
>>>> const struct cred *cred);
>>>>  extern int nfs4_proc_exchange_id(struct nfs_client *clp, const
>>>> struct cred *cred);
>>>>  extern int nfs4_destroy_clientid(struct nfs_client *clp);
>>>> diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c
>>>> index 1a69479a3a59..e67ea345de69 100644
>>>> --- a/fs/nfs/nfs4getroot.c
>>>> +++ b/fs/nfs/nfs4getroot.c
>>>> @@ -12,30 +12,28 @@
>>>>
>>>>  int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh
>>>> *mntfh, bool auth_probe)
>>>>  {
>>>> -	struct nfs_fsinfo fsinfo;
>>>> +	struct nfs_fattr *fattr = nfs_alloc_fattr();
>>>>  	int ret = -ENOMEM;
>>>>
>>>> -	fsinfo.fattr = nfs_alloc_fattr();
>>>> -	if (fsinfo.fattr == NULL)
>>>> +	if (fattr == NULL)
>>>>  		goto out;
>>>>
>>>>  	/* Start by getting the root filehandle from the server */
>>>> -	ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo,
>>>> auth_probe);
>>>> +	ret = nfs4_proc_get_rootfh(server, mntfh, fattr,
>>>> auth_probe);
>>>>  	if (ret < 0) {
>>>>  		dprintk("nfs4_get_rootfh: getroot error = %d\n", -
>>>> ret);
>>>>  		goto out;
>>>>  	}
>>>>
>>>> -	if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
>>>> -			|| !S_ISDIR(fsinfo.fattr->mode)) {
>>>> +	if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) ||
>>>> !S_ISDIR(fattr->mode)) {
>>>>  		printk(KERN_ERR "nfs4_get_rootfh:"
>>>>  		       " getroot encountered non-directory\n");
>>>>  		ret = -ENOTDIR;
>>>>  		goto out;
>>>>  	}
>
> .. now I think we won't have fattr->mode here, more below:
>
>>>>
>>>> -	memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server-
>>>>> fsid));
>>>> +	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
>>>>  out:
>>>> -	nfs_free_fattr(fsinfo.fattr);
>>>> +	nfs_free_fattr(fattr);
>>>>  	return ret;
>>>>  }
>>>> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>>>> index c7c7ec22f21d..7d2b67e06cc3 100644
>>>> --- a/fs/nfs/nfs4proc.c
>>>> +++ b/fs/nfs/nfs4proc.c
>>>> @@ -4240,15 +4240,18 @@ static int nfs4_discover_trunking(struct
>>>> nfs_server *server,
>>>>  }
>>>>
>>>>  static int _nfs4_lookup_root(struct nfs_server *server, struct
>>>> nfs_fh *fhandle,
>>>> -		struct nfs_fsinfo *info)
>>>> +			     struct nfs_fattr *fattr)
>>>>  {
>>>> -	u32 bitmask[3];
>>>> +	u32 bitmask[3] = {
>>>> +		[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
>>>> +		      FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,
>>>
>>> Just a thought when noticing this change --
>>>
>>> Don't we want at least FATTR4_WORD0_FILEID and
>>> FATTR4_WORD1_MOUNTED_ON_FILEID as well here?
>>
>>
>> Only FATTR4_WORD0_TYPE and FATTR4_WORD0_FSID are used by the caller, so
>> we don't actually need FATTR4_WORD0_CHANGE or FATTR4_WORD0_SIZE either.
>> I put them in so that the test for the auth flavour would have more
>> chances of catching a problem.
>
> Ah, I see now...  we're going to call ->fsinfo() again (as you stated in the
> description).
>
> But I don't see how _CHANGE or _SIZE are used..  and as I was hunting around
> there's that check in nfs4_get_rootfh() (above) for S_ISDIR(fattr->mode), but this
> dropped the fsinfo call out of nfs4_proc_get_rootfh(), so I think
> fattr->mode will never be set.

I ran this through some basic testing, and I see now that _TYPE gets into
fattr->mode when we decode, which of course makes sense.

So, FWIW - this makes sense and looks good to me now.

Ben


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/2] Fixes for the NFS automounter
  2025-08-04  1:29 [PATCH 0/2] Fixes for the NFS automounter Trond Myklebust
  2025-08-04  1:29 ` [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem Trond Myklebust
  2025-08-04  1:29 ` [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls Trond Myklebust
@ 2025-08-24  7:00 ` Scott Haiden
  2 siblings, 0 replies; 9+ messages in thread
From: Scott Haiden @ 2025-08-24  7:00 UTC (permalink / raw)
  To: trondmy; +Cc: linux-nfs

Hello,

I think this patch 
(https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=b01f21cacde9f2878492cf318fee61bf4ccad323) 
might have broken the getxattr system call over NFS.

On v6.16.1, I was able to call `getxattr` on files in an NFS 4.2 mount, 
but with this patch, running the same command I get:

     $ cd /path/to/nfs4.2/mount
     $ getfattr -n user.hash.sha512 'S01E01 - Kassa.mkv'
     S01E01 - Kassa.mkv: user.hash.sha512: Operation not supported

Without this patch, it just returns the xattr with no problem.

Am I missing a mount option? Or, is it possible this commit introduced a 
bug?

I ran a git bisect between v6.16.1 and v6.16.2 and it pointed to this 
patch's backport to the stable tree.

Thanks,
--Scott


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-08-24  7:00 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-04  1:29 [PATCH 0/2] Fixes for the NFS automounter Trond Myklebust
2025-08-04  1:29 ` [PATCH 1/2] NFS: Fix the setting of capabilities when automounting a new filesystem Trond Myklebust
2025-08-04 16:07   ` Benjamin Coddington
2025-08-04  1:29 ` [PATCH 2/2] NFSv4: Remove duplicate lookups, capability probes and fsinfo calls Trond Myklebust
2025-08-04 16:43   ` Benjamin Coddington
2025-08-04 16:54     ` Trond Myklebust
2025-08-04 19:07       ` Benjamin Coddington
2025-08-05 13:35         ` Benjamin Coddington
2025-08-24  7:00 ` [PATCH 0/2] Fixes for the NFS automounter Scott Haiden

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).