Commit 1463b38e authored by NeilBrown's avatar NeilBrown Committed by Chuck Lever

NFSD: simplify per-net file cache management

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: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 1e37d0e5
...@@ -44,12 +44,9 @@ struct nfsd_fcache_bucket { ...@@ -44,12 +44,9 @@ struct nfsd_fcache_bucket {
static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
struct nfsd_fcache_disposal { struct nfsd_fcache_disposal {
struct list_head list;
struct work_struct work; struct work_struct work;
struct net *net;
spinlock_t lock; spinlock_t lock;
struct list_head freeme; struct list_head freeme;
struct rcu_head rcu;
}; };
static struct workqueue_struct *nfsd_filecache_wq __read_mostly; static struct workqueue_struct *nfsd_filecache_wq __read_mostly;
...@@ -62,8 +59,6 @@ static long nfsd_file_lru_flags; ...@@ -62,8 +59,6 @@ static long nfsd_file_lru_flags;
static struct fsnotify_group *nfsd_file_fsnotify_group; static struct fsnotify_group *nfsd_file_fsnotify_group;
static atomic_long_t nfsd_filecache_count; static atomic_long_t nfsd_filecache_count;
static struct delayed_work nfsd_filecache_laundrette; static struct delayed_work nfsd_filecache_laundrette;
static DEFINE_SPINLOCK(laundrette_lock);
static LIST_HEAD(laundrettes);
static void nfsd_file_gc(void); static void nfsd_file_gc(void);
...@@ -367,19 +362,13 @@ nfsd_file_list_remove_disposal(struct list_head *dst, ...@@ -367,19 +362,13 @@ nfsd_file_list_remove_disposal(struct list_head *dst,
static void static void
nfsd_file_list_add_disposal(struct list_head *files, struct net *net) 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(); spin_lock(&l->lock);
list_for_each_entry_rcu(l, &laundrettes, list) { list_splice_tail_init(files, &l->freeme);
if (l->net == net) { spin_unlock(&l->lock);
spin_lock(&l->lock); queue_work(nfsd_filecache_wq, &l->work);
list_splice_tail_init(files, &l->freeme);
spin_unlock(&l->lock);
queue_work(nfsd_filecache_wq, &l->work);
break;
}
}
rcu_read_unlock();
} }
static void static void
...@@ -755,7 +744,7 @@ nfsd_file_cache_purge(struct net *net) ...@@ -755,7 +744,7 @@ nfsd_file_cache_purge(struct net *net)
} }
static struct nfsd_fcache_disposal * static struct nfsd_fcache_disposal *
nfsd_alloc_fcache_disposal(struct net *net) nfsd_alloc_fcache_disposal(void)
{ {
struct nfsd_fcache_disposal *l; struct nfsd_fcache_disposal *l;
...@@ -763,7 +752,6 @@ nfsd_alloc_fcache_disposal(struct net *net) ...@@ -763,7 +752,6 @@ nfsd_alloc_fcache_disposal(struct net *net)
if (!l) if (!l)
return NULL; return NULL;
INIT_WORK(&l->work, nfsd_file_delayed_close); INIT_WORK(&l->work, nfsd_file_delayed_close);
l->net = net;
spin_lock_init(&l->lock); spin_lock_init(&l->lock);
INIT_LIST_HEAD(&l->freeme); INIT_LIST_HEAD(&l->freeme);
return l; return l;
...@@ -772,61 +760,27 @@ nfsd_alloc_fcache_disposal(struct net *net) ...@@ -772,61 +760,27 @@ nfsd_alloc_fcache_disposal(struct net *net)
static void static void
nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l) nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l)
{ {
rcu_assign_pointer(l->net, NULL);
cancel_work_sync(&l->work); cancel_work_sync(&l->work);
nfsd_file_dispose_list(&l->freeme); nfsd_file_dispose_list(&l->freeme);
kfree_rcu(l, rcu); kfree(l);
}
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;
} }
static void static void
nfsd_free_fcache_disposal_net(struct net *net) 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(); nfsd_free_fcache_disposal(l);
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();
} }
int int
nfsd_file_cache_start_net(struct net *net) 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 void
......
...@@ -185,6 +185,8 @@ struct nfsd_net { ...@@ -185,6 +185,8 @@ struct nfsd_net {
/* utsname taken from the process that starts the server */ /* utsname taken from the process that starts the server */
char nfsd_name[UNX_MAXNODENAME+1]; char nfsd_name[UNX_MAXNODENAME+1];
struct nfsd_fcache_disposal *fcache_disposal;
}; };
/* Simple check to find out if a given net was properly initialized */ /* Simple check to find out if a given net was properly initialized */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment