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:

committed by
Greg Kroah-Hartman

parent
677fd67d8b
commit
e8f923e1e9
@@ -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;
|
|||||||
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);
|
||||||
|
|
||||||
@@ -366,19 +361,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
|
||||||
@@ -754,7 +743,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;
|
||||||
|
|
||||||
@@ -762,7 +751,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;
|
||||||
@@ -771,61 +759,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 {
|
|||||||
|
|
||||||
/* 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 */
|
||||||
|
Reference in New Issue
Block a user