diff mbox series

[4/4] nfsd: filecache: change garbage collection to a timer.

Message ID 20250122035615.2893754-5-neilb@suse.de (mailing list archive)
State New
Delegated to: Chuck Lever
Headers show
Series nfsd: filecache: change garbage collect lists | expand

Commit Message

NeilBrown Jan. 22, 2025, 3:54 a.m. UTC
garbage collection never sleeps and no longer walks a list so it runs
quickly only requiring a spinlock.

This means we don't need to use a workqueue, we can use a simple timer
instead.  This means it can run in "bh" context so we need to use "_bh"
locking.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 fs/nfsd/filecache.c | 51 +++++++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 23 deletions(-)
diff mbox series

Patch

diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 552feba94f09..ebde4e86cdee 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -66,7 +66,7 @@  struct nfsd_fcache_disposal {
 	struct list_head older;	/* haven't been used in last 0-2 seconds */
 	struct list_head freeme; /* ready to be discarded */
 	unsigned long num_gc; /* Approximate size of recent plus older */
-	struct delayed_work filecache_laundrette;
+	struct timer_list timer;
 	struct shrinker *file_shrinker;
 	struct nfsd_net *nn;
 };
@@ -115,8 +115,8 @@  static const struct rhashtable_params nfsd_file_rhash_params = {
 static void
 nfsd_file_schedule_laundrette(struct nfsd_fcache_disposal *l)
 {
-	queue_delayed_work(system_unbound_wq, &l->filecache_laundrette,
-			   NFSD_LAUNDRETTE_DELAY);
+	if (!timer_pending(&l->timer))
+		mod_timer(&l->timer, jiffies + NFSD_LAUNDRETTE_DELAY);
 }
 
 static void
@@ -333,16 +333,16 @@  static bool nfsd_file_lru_add(struct nfsd_file *nf)
 	struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
 	struct nfsd_fcache_disposal *l = nn->fcache_disposal;
 
-	spin_lock(&l->lock);
+	spin_lock_bh(&l->lock);
 	if (list_empty(&nf->nf_lru)) {
 		list_add_tail(&nf->nf_lru, &l->recent);
 		l->num_gc += 1;
 		atomic_long_inc(&nfsd_lru_total);
 		trace_nfsd_file_lru_add(nf);
-		spin_unlock(&l->lock);
+		spin_unlock_bh(&l->lock);
 		return true;
 	}
-	spin_unlock(&l->lock);
+	spin_unlock_bh(&l->lock);
 	return false;
 }
 
@@ -351,17 +351,17 @@  static bool nfsd_file_lru_remove(struct nfsd_file *nf)
 	struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
 	struct nfsd_fcache_disposal *l = nn->fcache_disposal;
 
-	spin_lock(&l->lock);
+	spin_lock_bh(&l->lock);
 	if (!list_empty(&nf->nf_lru)) {
 		list_del_init(&nf->nf_lru);
 		atomic_long_dec(&nfsd_lru_total);
 		if (l->num_gc > 0)
 			l->num_gc -= 1;
 		trace_nfsd_file_lru_del(nf);
-		spin_unlock(&l->lock);
+		spin_unlock_bh(&l->lock);
 		return true;
 	}
-	spin_unlock(&l->lock);
+	spin_unlock_bh(&l->lock);
 	return false;
 }
 
@@ -487,9 +487,9 @@  nfsd_file_dispose_list_delayed(struct list_head *dispose)
 		struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
 		struct nfsd_fcache_disposal *l = nn->fcache_disposal;
 
-		spin_lock(&l->lock);
+		spin_lock_bh(&l->lock);
 		list_move_tail(&nf->nf_lru, &l->freeme);
-		spin_unlock(&l->lock);
+		spin_unlock_bh(&l->lock);
 		svc_wake_up(nn->nfsd_serv);
 	}
 }
@@ -511,7 +511,7 @@  void nfsd_file_net_dispose(struct nfsd_net *nn)
 		LIST_HEAD(dispose);
 		int i;
 
-		spin_lock(&l->lock);
+		spin_lock_bh(&l->lock);
 		for (i = 0; i < 8 && !list_empty(&l->freeme); i++) {
 			struct nfsd_file *nf = list_first_entry(
 				&l->freeme, struct nfsd_file, nf_lru);
@@ -531,7 +531,7 @@  void nfsd_file_net_dispose(struct nfsd_net *nn)
 				this_cpu_inc(nfsd_file_evictions);
 			}
 		}
-		spin_unlock(&l->lock);
+		spin_unlock_bh(&l->lock);
 		if (!list_empty(&l->freeme))
 			/* Wake up another thread to share the work
 			 * *before* doing any actual disposing.
@@ -542,12 +542,12 @@  void nfsd_file_net_dispose(struct nfsd_net *nn)
 }
 
 static void
-nfsd_file_gc_worker(struct work_struct *work)
+nfsd_file_gc_worker(struct timer_list *t)
 {
 	struct nfsd_fcache_disposal *l = container_of(
-		work, struct nfsd_fcache_disposal, filecache_laundrette.work);
+		t, struct nfsd_fcache_disposal, timer);
 
-	spin_lock(&l->lock);
+	spin_lock_bh(&l->lock);
 	list_splice_init(&l->older, &l->freeme);
 	list_splice_init(&l->recent, &l->older);
 	/* We don't know how many were moved to 'freeme' and don't want
@@ -557,9 +557,8 @@  nfsd_file_gc_worker(struct work_struct *work)
 	if (!list_empty(&l->freeme))
 		svc_wake_up(l->nn->nfsd_serv);
 	if (!list_empty(&l->older) || !list_empty(&l->recent))
-		nfsd_file_schedule_laundrette(l);
-	spin_unlock(&l->lock);
-
+		mod_timer(t, jiffies + NFSD_LAUNDRETTE_DELAY);
+	spin_unlock_bh(&l->lock);
 }
 
 static unsigned long
@@ -577,7 +576,7 @@  nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
 	struct nfsd_file *nf;
 	int scanned = 0;
 
-	spin_lock(&l->lock);
+	spin_lock_bh(&l->lock);
 	while (scanned < sc->nr_to_scan &&
 	       (nf = list_first_entry_or_null(&l->older,
 					      struct nfsd_file, nf_lru)) != NULL) {
@@ -599,7 +598,9 @@  nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
 		list_add_tail(&nf->nf_lru, &l->older);
 		scanned += 1;
 	}
-	spin_unlock(&l->lock);
+	spin_unlock_bh(&l->lock);
+
+	trace_nfsd_file_shrinker_removed(scanned, l->num_gc);
 	return scanned;
 }
 
@@ -854,7 +855,9 @@  nfsd_alloc_fcache_disposal(void)
 	if (!l)
 		return NULL;
 	spin_lock_init(&l->lock);
-	INIT_DELAYED_WORK(&l->filecache_laundrette, nfsd_file_gc_worker);
+	timer_setup(&l->timer, nfsd_file_gc_worker, 0);
+	INIT_LIST_HEAD(&l->recent);
+	INIT_LIST_HEAD(&l->older);
 	INIT_LIST_HEAD(&l->recent);
 	INIT_LIST_HEAD(&l->older);
 	INIT_LIST_HEAD(&l->freeme);
@@ -871,13 +874,15 @@  nfsd_alloc_fcache_disposal(void)
 	l->file_shrinker->private_data = l;
 
 	shrinker_register(l->file_shrinker);
+
 	return l;
 }
 
 static void
 nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l)
 {
-	cancel_delayed_work_sync(&l->filecache_laundrette);
+	shrinker_free(l->file_shrinker);
+	del_timer_sync(&l->timer);
 	shrinker_free(l->file_shrinker);
 	nfsd_file_release_list(&l->recent);
 	WARN_ON_ONCE(!list_empty(&l->recent));