NFSD: simplify per-net file cache management
[ Upstream commit 1463b38e7cf34d4cc60f41daff459ad807b2e408 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
677fd67d8b
commit
e8f923e1e9
@ -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);
|
||||
|
||||
@ -366,19 +361,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
|
||||
@ -754,7 +743,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;
|
||||
|
||||
@ -762,7 +751,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;
|
||||
@ -771,61 +759,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
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user