NFSD: simplify per-net file cache management
authorNeilBrown <neilb@suse.de>
Tue, 30 Nov 2021 23:58:14 +0000 (10:58 +1100)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 13 Dec 2021 18:42:59 +0000 (13:42 -0500)
We currently have a 'laundrette' for closing cached files - a different
work-item for each network-namespace.

These 'laundrettes' (aka struct nfsd_fcache_disposal) are currently on a
list, and are freed using rcu.

The list is not necessary as we have a per-namespace structure (struct
nfsd_net) which can hold a link to the nfsd_fcache_disposal.
The use of kfree_rcu is also unnecessary as the cache is cleaned of all
files associated with a given namespace, and no new files can be added,
before the nfsd_fcache_disposal is freed.

So add a '->fcache_disposal' link to nfsd_net, and discard the list
management and rcu usage.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/filecache.c
fs/nfsd/netns.h

index fdf89fcf1a0ca17ac03ab3027b1b36512c408aa0..aa5dca498b27e242f3fbbf7e993c26e20be7c1fe 100644 (file)
@@ -44,12 +44,9 @@ struct nfsd_fcache_bucket {
 static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
 
 struct nfsd_fcache_disposal {
-       struct list_head list;
        struct work_struct work;
-       struct net *net;
        spinlock_t lock;
        struct list_head freeme;
-       struct rcu_head rcu;
 };
 
 static struct workqueue_struct *nfsd_filecache_wq __read_mostly;
@@ -62,8 +59,6 @@ static long                           nfsd_file_lru_flags;
 static struct fsnotify_group           *nfsd_file_fsnotify_group;
 static atomic_long_t                   nfsd_filecache_count;
 static struct delayed_work             nfsd_filecache_laundrette;
-static DEFINE_SPINLOCK(laundrette_lock);
-static LIST_HEAD(laundrettes);
 
 static void nfsd_file_gc(void);
 
@@ -367,19 +362,13 @@ nfsd_file_list_remove_disposal(struct list_head *dst,
 static void
 nfsd_file_list_add_disposal(struct list_head *files, struct net *net)
 {
-       struct nfsd_fcache_disposal *l;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_fcache_disposal *l = nn->fcache_disposal;
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(l, &laundrettes, list) {
-               if (l->net == net) {
-                       spin_lock(&l->lock);
-                       list_splice_tail_init(files, &l->freeme);
-                       spin_unlock(&l->lock);
-                       queue_work(nfsd_filecache_wq, &l->work);
-                       break;
-               }
-       }
-       rcu_read_unlock();
+       spin_lock(&l->lock);
+       list_splice_tail_init(files, &l->freeme);
+       spin_unlock(&l->lock);
+       queue_work(nfsd_filecache_wq, &l->work);
 }
 
 static void
@@ -755,7 +744,7 @@ nfsd_file_cache_purge(struct net *net)
 }
 
 static struct nfsd_fcache_disposal *
-nfsd_alloc_fcache_disposal(struct net *net)
+nfsd_alloc_fcache_disposal(void)
 {
        struct nfsd_fcache_disposal *l;
 
@@ -763,7 +752,6 @@ nfsd_alloc_fcache_disposal(struct net *net)
        if (!l)
                return NULL;
        INIT_WORK(&l->work, nfsd_file_delayed_close);
-       l->net = net;
        spin_lock_init(&l->lock);
        INIT_LIST_HEAD(&l->freeme);
        return l;
@@ -772,61 +760,27 @@ nfsd_alloc_fcache_disposal(struct net *net)
 static void
 nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l)
 {
-       rcu_assign_pointer(l->net, NULL);
        cancel_work_sync(&l->work);
        nfsd_file_dispose_list(&l->freeme);
-       kfree_rcu(l, rcu);
-}
-
-static void
-nfsd_add_fcache_disposal(struct nfsd_fcache_disposal *l)
-{
-       spin_lock(&laundrette_lock);
-       list_add_tail_rcu(&l->list, &laundrettes);
-       spin_unlock(&laundrette_lock);
-}
-
-static void
-nfsd_del_fcache_disposal(struct nfsd_fcache_disposal *l)
-{
-       spin_lock(&laundrette_lock);
-       list_del_rcu(&l->list);
-       spin_unlock(&laundrette_lock);
-}
-
-static int
-nfsd_alloc_fcache_disposal_net(struct net *net)
-{
-       struct nfsd_fcache_disposal *l;
-
-       l = nfsd_alloc_fcache_disposal(net);
-       if (!l)
-               return -ENOMEM;
-       nfsd_add_fcache_disposal(l);
-       return 0;
+       kfree(l);
 }
 
 static void
 nfsd_free_fcache_disposal_net(struct net *net)
 {
-       struct nfsd_fcache_disposal *l;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_fcache_disposal *l = nn->fcache_disposal;
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(l, &laundrettes, list) {
-               if (l->net != net)
-                       continue;
-               nfsd_del_fcache_disposal(l);
-               rcu_read_unlock();
-               nfsd_free_fcache_disposal(l);
-               return;
-       }
-       rcu_read_unlock();
+       nfsd_free_fcache_disposal(l);
 }
 
 int
 nfsd_file_cache_start_net(struct net *net)
 {
-       return nfsd_alloc_fcache_disposal_net(net);
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       nn->fcache_disposal = nfsd_alloc_fcache_disposal();
+       return nn->fcache_disposal ? 0 : -ENOMEM;
 }
 
 void
index 021acdc0d03bb89ffea3763a78e4a6dda03518ad..9e8b77d2a3a47867b57d82cf242a6c69f22cadd3 100644 (file)
@@ -185,6 +185,8 @@ struct nfsd_net {
 
        /* utsname taken from the process that starts the server */
        char                    nfsd_name[UNX_MAXNODENAME+1];
+
+       struct nfsd_fcache_disposal *fcache_disposal;
 };
 
 /* Simple check to find out if a given net was properly initialized */