]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFS: Fix the setting of capabilities when automounting a new filesystem
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 3 Aug 2025 21:31:59 +0000 (14:31 -0700)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 4 Aug 2025 16:16:45 +0000 (09:16 -0700)
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
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/client.c
fs/nfs/internal.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c

index e13eb429b8b567393005c0516caac665236f66b0..8fb4a950dd5581d6bcd7150ae588a774a263ffc2 100644 (file)
@@ -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)
index 0143e0794d32d842c9372a2a22012ceb211335c3..1a18d8d9be25d70660bc09f2b0e2e5076a66ee99 100644 (file)
@@ -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,
index 2ea98f1f116fe4d05c460709bcdadfffeda16a15..6fddf43d729c8cf2559ac551dfc23aef1dcc4531 100644 (file)
@@ -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);
index d7dc669d84c5b3581596257932b1a86c1bc84ab9..c7c7ec22f21d7532a4a5f61eb2ec35b658c7b519 100644 (file)
@@ -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),