]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
NFS: Fix the setting of capabilities when automounting a new filesystem
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 17 Aug 2025 02:28:12 +0000 (22:28 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:21:34 +0000 (16:21 +0200)
[ Upstream commit b01f21cacde9f2878492cf318fee61bf4ccad323 ]

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>
[ adapted to older fs_context-less API structures ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfs/client.c
fs/nfs/internal.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c

index 323cef064f2a436fed11c6a2b381baf95a1a1248..bdece12af53e48d7af847597b0cda5795f99bfcc 100644 (file)
@@ -646,6 +646,42 @@ 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;
+
+       /*
+        * 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
  */
@@ -683,9 +719,6 @@ static int nfs_init_server(struct nfs_server *server,
        /* Initialise the client representation from the mount data */
        server->flags = data->flags;
        server->options = data->options;
-       server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
-               NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
-               NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
 
        if (data->rsize)
                server->rsize = nfs_block_size(data->rsize, NULL);
@@ -710,6 +743,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 (data->mount_server.addrlen) {
                memcpy(&server->mountd_address, &data->mount_server.address,
@@ -834,7 +869,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;
@@ -1042,6 +1076,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_fsinfo(server, fh, fattr_fsinfo);
        if (error < 0)
index bfb53756654d9a25c68fb69434135e36ba6d93af..46fc42d575ce47a8752007fce3f9402c44ac81f3 100644 (file)
@@ -172,6 +172,7 @@ nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
                                struct nfs4_sessionid *, u32);
 extern struct nfs_server *nfs_create_server(struct nfs_mount_info *,
                                        struct nfs_subversion *);
+extern void nfs_server_set_init_caps(struct nfs_server *);
 extern struct nfs_server *nfs4_create_server(
                                        struct nfs_mount_info *,
                                        struct nfs_subversion *);
index 1f4bdcda3fdad1fe4ef4bfdc44c0b522390858b6..eeab44727a7666390641fbb5013f19f8fa5aeddb 100644 (file)
@@ -1011,18 +1011,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
        if (error < 0)
                goto out;
 
-       /* Set the basic capabilities */
-       server->caps |= server->nfs_client->cl_mvops->init_caps;
-       if (server->flags & NFS_MOUNT_NORDIRPLUS)
-                       server->caps &= ~NFS_CAP_READDIRPLUS;
-       /*
-        * 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;
-
+       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 2145360d81aca03c2c05564d5436a2ef4a5a159f..5f8de86b27982088a27e6e5c07cadd5fa7f549a9 100644 (file)
@@ -3884,6 +3884,8 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
                .interruptible = true,
        };
        int err;
+
+       nfs_server_set_init_caps(server);
        do {
                err = nfs4_handle_exception(server,
                                _nfs4_server_capabilities(server, fhandle),