diff mbox

[v3,05/20] nfsd: add a shrinker to the nfsd_file cache

Message ID 1440069440-27454-6-git-send-email-jeff.layton@primarydata.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jeff Layton Aug. 20, 2015, 11:17 a.m. UTC
Signed-off-by: Jeff Layton <jeff.layton@primarydata.com>
---
 fs/nfsd/filecache.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)
diff mbox

Patch

diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 63b24419c674..669e62f6f4f6 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -118,6 +118,46 @@  nfsd_file_dispose_list(struct list_head *dispose)
 	}
 }
 
+static enum lru_status
+nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
+		 spinlock_t *lock, void *arg)
+	__releases(lock)
+	__acquires(lock)
+{
+	struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru);
+	bool unhashed;
+
+	if (atomic_read(&nf->nf_ref) > 1)
+		return LRU_SKIP;
+
+	spin_unlock(lock);
+	spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
+	unhashed = nfsd_file_unhash(nf);
+	spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock);
+	if (unhashed)
+		nfsd_file_put(nf);
+	spin_lock(lock);
+	return unhashed ? LRU_REMOVED_RETRY : LRU_RETRY;
+}
+
+static unsigned long
+nfsd_file_lru_count(struct shrinker *s, struct shrink_control *sc)
+{
+	return list_lru_count(&nfsd_file_lru);
+}
+
+static unsigned long
+nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
+{
+	return list_lru_shrink_walk(&nfsd_file_lru, sc, nfsd_file_lru_cb, NULL);
+}
+
+static struct shrinker	nfsd_file_shrinker = {
+	.scan_objects = nfsd_file_lru_scan,
+	.count_objects = nfsd_file_lru_count,
+	.seeks = 1,
+};
+
 int
 nfsd_file_cache_init(void)
 {
@@ -140,12 +180,20 @@  nfsd_file_cache_init(void)
 		goto out_err;
 	}
 
+	ret = register_shrinker(&nfsd_file_shrinker);
+	if (ret) {
+		pr_err("nfsd: failed to register nfsd_file_shrinker: %d\n", ret);
+		goto out_lru;
+	}
+
 	for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
 		INIT_HLIST_HEAD(&nfsd_file_hashtbl[i].nfb_head);
 		spin_lock_init(&nfsd_file_hashtbl[i].nfb_lock);
 	}
 out:
 	return ret;
+out_lru:
+	list_lru_destroy(&nfsd_file_lru);
 out_err:
 	kfree(nfsd_file_hashtbl);
 	nfsd_file_hashtbl = NULL;
@@ -159,6 +207,7 @@  nfsd_file_cache_shutdown(void)
 	struct nfsd_file	*nf;
 	LIST_HEAD(dispose);
 
+	unregister_shrinker(&nfsd_file_shrinker);
 	for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) {
 		spin_lock(&nfsd_file_hashtbl[i].nfb_lock);
 		while(!hlist_empty(&nfsd_file_hashtbl[i].nfb_head)) {