]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nfs: Avoid transient zeroed case capability bits during probe
authorChuck Lever <chuck.lever@oracle.com>
Fri, 15 May 2026 15:35:10 +0000 (11:35 -0400)
committerChristian Brauner <brauner@kernel.org>
Fri, 15 May 2026 15:49:22 +0000 (17:49 +0200)
nfs_probe_fsinfo() clears NFS_CAP_CASE_INSENSITIVE and
NFS_CAP_CASE_NONPRESERVING ahead of the synchronous pathconf RPC and
sets them again only after the reply arrives. The code path is gated
by clp->rpc_ops->version < 4 and is therefore reached on NFSv2/v3
remount via nfs_reconfigure(), which calls nfs_probe_server() against
a live mount. Concurrent readers walking server->caps can observe the
cleared state for the duration of the round-trip and report the wrong
case-sensitivity attributes.

Compute the post-probe capability mask on the stack and assign it to
server->caps in a single store so readers see either the stale value
or the freshly computed one, never an intermediate zero. Preserve the
original behaviour of dropping the bits when the pathconf RPC itself
fails.

The analogous transient zero on the NFSv4 path lives in
nfs4_server_capabilities() and is left for a separate fix.

Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260507-case-sensitivity-v14-0-e62cc8200435@oracle.com?part=10
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://patch.msgid.link/20260515153515.362266-3-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/nfs/client.c

index 3db2f18315b87ba78e72f912f00c1018c31d75e5..28b66bb0dd33744079772f61752cee09a4af3e95 100644 (file)
@@ -937,20 +937,23 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
        pathinfo.fattr = fattr;
        nfs_fattr_init(fattr);
 
-       /* Clear before probing so a failed RPC does not retain stale bits. */
-       if (clp->rpc_ops->version < 4)
-               server->caps &= ~(NFS_CAP_CASE_INSENSITIVE |
-                                 NFS_CAP_CASE_NONPRESERVING);
-
        if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0) {
                if (server->namelen == 0)
                        server->namelen = pathinfo.max_namelen;
                if (clp->rpc_ops->version < 4) {
+                       unsigned int caps = server->caps;
+
+                       caps &= ~(NFS_CAP_CASE_INSENSITIVE |
+                                 NFS_CAP_CASE_NONPRESERVING);
                        if (pathinfo.case_insensitive)
-                               server->caps |= NFS_CAP_CASE_INSENSITIVE;
+                               caps |= NFS_CAP_CASE_INSENSITIVE;
                        if (!pathinfo.case_preserving)
-                               server->caps |= NFS_CAP_CASE_NONPRESERVING;
+                               caps |= NFS_CAP_CASE_NONPRESERVING;
+                       server->caps = caps;
                }
+       } else if (clp->rpc_ops->version < 4) {
+               server->caps &= ~(NFS_CAP_CASE_INSENSITIVE |
+                                 NFS_CAP_CASE_NONPRESERVING);
        }
 
        if (clp->rpc_ops->discover_trunking != NULL &&