nfs: move the nfs4_data_server_cache into struct nfs_net
authorJeff Layton <jlayton@kernel.org>
Thu, 10 Apr 2025 20:42:04 +0000 (16:42 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 28 Apr 2025 03:25:44 +0000 (23:25 -0400)
Since struct nfs4_pnfs_ds should not be shared between net namespaces,
move from a global list of objects to a per-netns list and spinlock.

Tested-by: Sargun Dillon <sargun@sargun.me>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Link: https://lore.kernel.org/r/20250410-nfs-ds-netns-v2-2-f80b7979ba80@kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/client.c
fs/nfs/netns.h
fs/nfs/pnfs_nfs.c

index 02c916a..2115c11 100644 (file)
@@ -1199,6 +1199,10 @@ void nfs_clients_init(struct net *net)
        INIT_LIST_HEAD(&nn->nfs_volume_list);
 #if IS_ENABLED(CONFIG_NFS_V4)
        idr_init(&nn->cb_ident_idr);
+#endif
+#if IS_ENABLED(CONFIG_NFS_V4_1)
+       INIT_LIST_HEAD(&nn->nfs4_data_server_cache);
+       spin_lock_init(&nn->nfs4_data_server_lock);
 #endif
        spin_lock_init(&nn->nfs_client_lock);
        nn->boot_time = ktime_get_real();
@@ -1216,6 +1220,9 @@ void nfs_clients_exit(struct net *net)
        nfs_cleanup_cb_ident_idr(net);
        WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
        WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
+#if IS_ENABLED(CONFIG_NFS_V4_1)
+       WARN_ON_ONCE(!list_empty(&nn->nfs4_data_server_cache));
+#endif
 }
 
 #ifdef CONFIG_PROC_FS
index a68b216..6ba3ea3 100644 (file)
@@ -31,7 +31,11 @@ struct nfs_net {
        unsigned short nfs_callback_tcpport;
        unsigned short nfs_callback_tcpport6;
        int cb_users[NFS4_MAX_MINOR_VERSION + 1];
-#endif
+#endif /* CONFIG_NFS_V4 */
+#if IS_ENABLED(CONFIG_NFS_V4_1)
+       struct list_head nfs4_data_server_cache;
+       spinlock_t nfs4_data_server_lock;
+#endif /* CONFIG_NFS_V4_1 */
        struct nfs_netns_client *nfs_client;
        spinlock_t nfs_client_lock;
        ktime_t boot_time;
index 2ee20a0..91ef486 100644 (file)
@@ -16,6 +16,7 @@
 #include "nfs4session.h"
 #include "internal.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS
 
@@ -504,14 +505,14 @@ EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);
 /*
  * Data server cache
  *
- * Data servers can be mapped to different device ids.
- * nfs4_pnfs_ds reference counting
+ * Data servers can be mapped to different device ids, but should
+ * never be shared between net namespaces.
+ *
+ * nfs4_pnfs_ds reference counting:
  *   - set to 1 on allocation
  *   - incremented when a device id maps a data server already in the cache.
  *   - decremented when deviceid is removed from the cache.
  */
-static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
-static LIST_HEAD(nfs4_data_server_cache);
 
 /* Debug routines */
 static void
@@ -604,12 +605,12 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
  * Lookup DS by addresses.  nfs4_ds_cache_lock is held
  */
 static struct nfs4_pnfs_ds *
-_data_server_lookup_locked(const struct net *net, const struct list_head *dsaddrs)
+_data_server_lookup_locked(const struct nfs_net *nn, const struct list_head *dsaddrs)
 {
        struct nfs4_pnfs_ds *ds;
 
-       list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
-               if (ds->ds_net == net && _same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
+       list_for_each_entry(ds, &nn->nfs4_data_server_cache, ds_node)
+               if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
                        return ds;
        return NULL;
 }
@@ -653,10 +654,11 @@ static void destroy_ds(struct nfs4_pnfs_ds *ds)
 
 void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds)
 {
-       if (refcount_dec_and_lock(&ds->ds_count,
-                               &nfs4_ds_cache_lock)) {
+       struct nfs_net *nn = net_generic(ds->ds_net, nfs_net_id);
+
+       if (refcount_dec_and_lock(&ds->ds_count, &nn->nfs4_data_server_lock)) {
                list_del_init(&ds->ds_node);
-               spin_unlock(&nfs4_ds_cache_lock);
+               spin_unlock(&nn->nfs4_data_server_lock);
                destroy_ds(ds);
        }
 }
@@ -718,6 +720,7 @@ out_err:
 struct nfs4_pnfs_ds *
 nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flags)
 {
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
        struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
        char *remotestr;
 
@@ -733,8 +736,8 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla
        /* this is only used for debugging, so it's ok if its NULL */
        remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
 
-       spin_lock(&nfs4_ds_cache_lock);
-       tmp_ds = _data_server_lookup_locked(net, dsaddrs);
+       spin_lock(&nn->nfs4_data_server_lock);
+       tmp_ds = _data_server_lookup_locked(nn, dsaddrs);
        if (tmp_ds == NULL) {
                INIT_LIST_HEAD(&ds->ds_addrs);
                list_splice_init(dsaddrs, &ds->ds_addrs);
@@ -743,7 +746,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla
                INIT_LIST_HEAD(&ds->ds_node);
                ds->ds_net = net;
                ds->ds_clp = NULL;
-               list_add(&ds->ds_node, &nfs4_data_server_cache);
+               list_add(&ds->ds_node, &nn->nfs4_data_server_cache);
                dprintk("%s add new data server %s\n", __func__,
                        ds->ds_remotestr);
        } else {
@@ -755,7 +758,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla
                        refcount_read(&tmp_ds->ds_count));
                ds = tmp_ds;
        }
-       spin_unlock(&nfs4_ds_cache_lock);
+       spin_unlock(&nn->nfs4_data_server_lock);
 out:
        return ds;
 }