]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
NFS: Fix RCU dereference of cl_xprt in nfs_compare_super_address
authorSean Chang <seanwascoding@gmail.com>
Sun, 19 Apr 2026 16:31:38 +0000 (00:31 +0800)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 22 Apr 2026 12:53:23 +0000 (08:53 -0400)
The cl_xprt pointer in struct rpc_clnt is marked as __rcu. Accessing
it directly in nfs_compare_super_address() is unsafe and triggers
Sparse warnings.

Fix this by using rcu_dereference() within an RCU read-side critical
section to retrieve the transport pointer. This addresses the sparse
warning and ensures atomic access to the pointer, as the transport
can be updated via transport switching even while the superblock
remains active under sb_lock.

Fixes: 7e3fcf61abde ("nfs: don't share mounts between network namespaces")
Signed-off-by: Sean Chang <seanwascoding@gmail.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/super.c

index 7a318581f85b2a277bc19a379130ff0bb0a1339a..4cd420b14ce3f3436199ea6f654177741d9eb48a 100644 (file)
@@ -1166,12 +1166,18 @@ static int nfs_set_super(struct super_block *s, struct fs_context *fc)
 static int nfs_compare_super_address(struct nfs_server *server1,
                                     struct nfs_server *server2)
 {
+       struct rpc_xprt *xprt1, *xprt2;
        struct sockaddr *sap1, *sap2;
-       struct rpc_xprt *xprt1 = server1->client->cl_xprt;
-       struct rpc_xprt *xprt2 = server2->client->cl_xprt;
+
+       rcu_read_lock();
+
+       xprt1 = rcu_dereference(server1->client->cl_xprt);
+       xprt2 = rcu_dereference(server2->client->cl_xprt);
 
        if (!net_eq(xprt1->xprt_net, xprt2->xprt_net))
-               return 0;
+               goto out_unlock;
+
+       rcu_read_unlock();
 
        sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr;
        sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr;
@@ -1203,6 +1209,10 @@ static int nfs_compare_super_address(struct nfs_server *server1,
        }
 
        return 1;
+
+out_unlock:
+       rcu_read_unlock();
+       return 0;
 }
 
 static int nfs_compare_userns(const struct nfs_server *old,