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

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
Loading
Loading
Loading
Loading
+15 −61
Original line number Diff line number Diff line
@@ -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();
}

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();
}

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
+2 −0
Original line number Diff line number Diff line
@@ -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 */