[PATCH 4/4] gfs2: Remove the glock lru list and shrinker
Andreas Gruenbacher <[email protected]> Tue, 28 Jul 2026 18:41:24 +0200
| Newsgroups | dev.linux.lists.gfs2 |
|---|---|
| Message-ID | <[email protected]> |
We are no longer keeping unreferences glocks around, so remove the now-obsolete glock lru list and shrinker. Signed-off-by: Andreas Gruenbacher <[email protected]> --- fs/gfs2/glock.c | 201 ++----------------------------------------- fs/gfs2/glock.h | 2 +- fs/gfs2/incore.h | 6 +- fs/gfs2/main.c | 1 - fs/gfs2/ops_fstype.c | 3 +- fs/gfs2/super.c | 2 +- fs/gfs2/trace_gfs2.h | 1 - 7 files changed, 15 insertions(+), 201 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index eee1f31a41f0..558c8c660a3d 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -66,9 +66,6 @@ static void request_demote(struct gfs2_glock *gl, unsigned int state, unsigned long delay, bool remote); static struct dentry *gfs2_root; -static LIST_HEAD(lru_list); -static atomic_t lru_count = ATOMIC_INIT(0); -static DEFINE_SPINLOCK(lru_lock); #define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE BIT(GFS2_GL_HASH_SHIFT) @@ -158,9 +155,9 @@ void gfs2_glock_free(struct gfs2_glock *gl) { void gfs2_glock_free_later(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = glock_sbd(gl); - spin_lock(&lru_lock); - list_add(&gl->gl_lru, &sdp->sd_dead_glocks); - spin_unlock(&lru_lock); + spin_lock(&sdp->sd_dead_lock); + list_add(&gl->gl_dead, &sdp->sd_dead_glocks); + spin_unlock(&sdp->sd_dead_lock); if (atomic_dec_and_test(&sdp->sd_glock_disposal)) wake_up(&sdp->sd_kill_wait); } @@ -172,8 +169,8 @@ static void gfs2_free_dead_glocks(struct gfs2_sbd *sdp) while(!list_empty(list)) { struct gfs2_glock *gl; - gl = list_first_entry(list, struct gfs2_glock, gl_lru); - list_del_init(&gl->gl_lru); + gl = list_first_entry(list, struct gfs2_glock, gl_dead); + list_del(&gl->gl_dead); __gfs2_glock_free(gl); } } @@ -191,30 +188,6 @@ struct gfs2_glock *gfs2_glock_hold(struct gfs2_glock *gl) return gl; } -static void gfs2_glock_add_to_lru(struct gfs2_glock *gl) -{ - spin_lock(&lru_lock); - list_move_tail(&gl->gl_lru, &lru_list); - - if (!test_bit(GLF_LRU, &gl->gl_flags)) { - set_bit(GLF_LRU, &gl->gl_flags); - atomic_inc(&lru_count); - } - - spin_unlock(&lru_lock); -} - -static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) -{ - spin_lock(&lru_lock); - if (test_bit(GLF_LRU, &gl->gl_flags)) { - list_del_init(&gl->gl_lru); - atomic_dec(&lru_count); - clear_bit(GLF_LRU, &gl->gl_flags); - } - spin_unlock(&lru_lock); -} - /* * Enqueue the glock on the work queue. Passes one glock reference on to the * work queue. @@ -241,7 +214,6 @@ static void __gfs2_glock_put(struct gfs2_glock *gl) lockref_mark_dead(&gl->gl_lockref); spin_unlock(&gl->gl_lockref.lock); - gfs2_glock_remove_from_lru(gl); GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); if (mapping) { truncate_inode_pages_final(mapping); @@ -1065,8 +1037,6 @@ static struct gfs2_glock *find_insert_glock(struct lm_lockname *name, out: rcu_read_unlock(); finish_wait(wq, &wait.wait); - if (gl) - gfs2_glock_remove_from_lru(gl); return gl; } @@ -1879,125 +1849,6 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) spin_unlock(&gl->gl_lockref.lock); } -static int glock_cmp(void *priv, const struct list_head *a, - const struct list_head *b) -{ - struct gfs2_glock *gla, *glb; - - gla = list_entry(a, struct gfs2_glock, gl_lru); - glb = list_entry(b, struct gfs2_glock, gl_lru); - - if (glock_number(gla) > glock_number(glb)) - return 1; - if (glock_number(gla) < glock_number(glb)) - return -1; - - return 0; -} - -static bool can_free_glock(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = glock_sbd(gl); - - return !test_bit(GLF_LOCK, &gl->gl_flags) && - !gl->gl_lockref.count && - (!test_bit(GLF_LFLUSH, &gl->gl_flags) || - test_bit(SDF_KILL, &sdp->sd_flags)); -} - -/** - * gfs2_dispose_glock_lru - Demote a list of glocks - * @list: The list to dispose of - * - * Disposing of glocks may involve disk accesses, so that here we sort - * the glocks by number (i.e. disk location of the inodes) so that if - * there are any such accesses, they'll be sent in order (mostly). - * - * Must be called under the lru_lock, but may drop and retake this - * lock. While the lru_lock is dropped, entries may vanish from the - * list, but no new entries will appear on the list (since it is - * private) - */ - -static unsigned long gfs2_dispose_glock_lru(struct list_head *list) -__releases(&lru_lock) -__acquires(&lru_lock) -{ - struct gfs2_glock *gl; - unsigned long freed = 0; - - list_sort(NULL, list, glock_cmp); - - while(!list_empty(list)) { - gl = list_first_entry(list, struct gfs2_glock, gl_lru); - if (!spin_trylock(&gl->gl_lockref.lock)) { -add_back_to_lru: - list_move(&gl->gl_lru, &lru_list); - continue; - } - if (!can_free_glock(gl)) { - spin_unlock(&gl->gl_lockref.lock); - goto add_back_to_lru; - } - list_del_init(&gl->gl_lru); - atomic_dec(&lru_count); - clear_bit(GLF_LRU, &gl->gl_flags); - freed++; - gl->gl_lockref.count++; - if (gl->gl_state != LM_ST_UNLOCKED) - request_demote(gl, LM_ST_UNLOCKED, 0, false); - gfs2_glock_queue_work(gl, 0); - spin_unlock(&gl->gl_lockref.lock); - cond_resched_lock(&lru_lock); - } - return freed; -} - -/** - * gfs2_scan_glock_lru - Scan the LRU looking for locks to demote - * @nr: The number of entries to scan - * - * This function selects the entries on the LRU which are able to - * be demoted, and then kicks off the process by calling - * gfs2_dispose_glock_lru() above. - */ - -static unsigned long gfs2_scan_glock_lru(unsigned long nr) -{ - struct gfs2_glock *gl, *next; - LIST_HEAD(dispose); - unsigned long freed = 0; - - spin_lock(&lru_lock); - list_for_each_entry_safe(gl, next, &lru_list, gl_lru) { - if (!nr--) - break; - if (can_free_glock(gl)) - list_move(&gl->gl_lru, &dispose); - } - if (!list_empty(&dispose)) - freed = gfs2_dispose_glock_lru(&dispose); - spin_unlock(&lru_lock); - - return freed; -} - -static unsigned long gfs2_glock_shrink_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - if (!(sc->gfp_mask & __GFP_FS)) - return SHRINK_STOP; - return gfs2_scan_glock_lru(sc->nr_to_scan); -} - -static unsigned long gfs2_glock_shrink_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - return vfs_pressure_ratio(atomic_read(&lru_count)); -} - -static struct shrinker *glock_shrinker; - /** * glock_hash_walk - Call a function for glock in a hash bucket * @examiner: the function @@ -2068,33 +1919,12 @@ static void thaw_glock(struct gfs2_glock *gl) if (!lockref_get_not_dead(&gl->gl_lockref)) return; - gfs2_glock_remove_from_lru(gl); spin_lock(&gl->gl_lockref.lock); set_bit(GLF_HAVE_REPLY, &gl->gl_flags); gfs2_glock_queue_work(gl, 0); spin_unlock(&gl->gl_lockref.lock); } -/** - * clear_glock - look at a glock and see if we can free it from glock cache - * @gl: the glock to look at - * - */ - -static void clear_glock(struct gfs2_glock *gl) -{ - gfs2_glock_remove_from_lru(gl); - - spin_lock(&gl->gl_lockref.lock); - if (!__lockref_is_dead(&gl->gl_lockref)) { - gl->gl_lockref.count++; - if (gl->gl_state != LM_ST_UNLOCKED) - request_demote(gl, LM_ST_UNLOCKED, 0, false); - gfs2_glock_queue_work(gl, 0); - } - spin_unlock(&gl->gl_lockref.lock); -} - /** * gfs2_glock_thaw - Thaw any frozen glocks * @sdp: The super block @@ -2141,20 +1971,17 @@ void gfs2_withdraw_glocks(struct gfs2_sbd *sdp) } /** - * gfs2_gl_hash_clear - Empty out the glock hash table + * gfs2_wait_glocks - Wait for the remaining glocks to go away * @sdp: the filesystem * * Called when unmounting the filesystem. */ -void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) +void gfs2_wait_glocks(struct gfs2_sbd *sdp) { unsigned long start = jiffies; bool timed_out = false; - glock_hash_walk(clear_glock, sdp); - flush_workqueue(sdp->sd_glock_wq); - while (!timed_out) { wait_event_timeout(sdp->sd_kill_wait, !atomic_read(&sdp->sd_glock_disposal), @@ -2277,8 +2104,6 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl) *p++ = 'F'; if (!list_empty(&gl->gl_holders)) *p++ = 'q'; - if (test_bit(GLF_LRU, gflags)) - *p++ = 'L'; if (gl->gl_object) *p++ = 'o'; if (test_bit(GLF_BLOCKING, gflags)) @@ -2438,17 +2263,6 @@ int __init gfs2_glock_init(void) if (ret < 0) return ret; - glock_shrinker = shrinker_alloc(0, "gfs2-glock"); - if (!glock_shrinker) { - rhashtable_destroy(&gl_hash_table); - return -ENOMEM; - } - - glock_shrinker->count_objects = gfs2_glock_shrink_count; - glock_shrinker->scan_objects = gfs2_glock_shrink_scan; - - shrinker_register(glock_shrinker); - for (i = 0; i < GLOCK_WAIT_TABLE_SIZE; i++) init_waitqueue_head(glock_wait_table + i); @@ -2457,7 +2271,6 @@ int __init gfs2_glock_init(void) void gfs2_glock_exit(void) { - shrinker_free(glock_shrinker); rhashtable_destroy(&gl_hash_table); } diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 6341ac9b863f..8b9e22befefb 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -263,7 +263,7 @@ bool gfs2_queue_try_to_evict(struct gfs2_glock *gl); bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later); void gfs2_cancel_delete_work(struct gfs2_glock *gl); void gfs2_flush_delete_work(struct gfs2_sbd *sdp); -void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); +void gfs2_wait_glocks(struct gfs2_sbd *sdp); void gfs2_withdraw_glocks(struct gfs2_sbd *sdp); void gfs2_glock_thaw(struct gfs2_sbd *sdp); void gfs2_glock_free(struct gfs2_glock *gl); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 6098447866d9..dadb4d3c9d3d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -321,7 +321,6 @@ enum { GLF_INITIAL = 10, GLF_HAVE_FROZEN_REPLY = 11, GLF_INSTANTIATE_IN_PROG = 12, /* instantiate happening now */ - GLF_LRU = 13, GLF_OBJECT = 14, /* Used only for tracing */ GLF_BLOCKING = 15, GLF_TRY_TO_EVICT = 17, /* iopen glocks only */ @@ -355,7 +354,7 @@ struct gfs2_glock { unsigned long gl_tchange; void *gl_object; - struct list_head gl_lru; + struct list_head gl_dead; struct list_head gl_ail_list; atomic_t gl_ail_count; atomic_t gl_revokes; @@ -833,6 +832,9 @@ struct gfs2_sbd { struct list_head sd_ail1_list; struct list_head sd_ail2_list; + /* glocks */ + spinlock_t sd_dead_lock; + /* For quiescing the filesystem */ struct gfs2_holder sd_freeze_gh; struct mutex sd_freeze_mutex; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 9d65719353fa..36c9c06e91ac 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -52,7 +52,6 @@ static void gfs2_init_glock_once(void *foo) struct gfs2_glock *gl = foo; INIT_LIST_HEAD(&gl->gl_holders); - INIT_LIST_HEAD(&gl->gl_lru); INIT_LIST_HEAD(&gl->gl_ail_list); atomic_set(&gl->gl_ail_count, 0); atomic_set(&gl->gl_revokes, 0); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 71e9dedd8b88..718e0da7dfce 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -123,6 +123,8 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_ail1_list); INIT_LIST_HEAD(&sdp->sd_ail2_list); + spin_lock_init(&sdp->sd_dead_lock); + init_rwsem(&sdp->sd_log_flush_lock); atomic_set(&sdp->sd_log_in_flight, 0); init_waitqueue_head(&sdp->sd_log_flush_wait); @@ -1300,7 +1302,6 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc) init_locking(sdp, &mount_gh, UNDO); fail_lm: complete_all(&sdp->sd_journal_ready); - gfs2_gl_hash_clear(sdp); gfs2_lm_unmount(sdp); fail_debug: gfs2_delete_debugfs_file(sdp); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 4d854556b529..06302c29340f 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -638,7 +638,7 @@ static void gfs2_put_super(struct super_block *sb) gfs2_clear_rgrpd(sdp); gfs2_jindex_free(sdp); /* Take apart glock structures and buffer lists */ - gfs2_gl_hash_clear(sdp); + gfs2_wait_glocks(sdp); iput(sdp->sd_inode); gfs2_delete_debugfs_file(sdp); diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index 6fd39fcdd00e..bc40320ef239 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -56,7 +56,6 @@ {(1UL << GLF_HAVE_REPLY), "r" }, \ {(1UL << GLF_INITIAL), "a" }, \ {(1UL << GLF_HAVE_FROZEN_REPLY), "F" }, \ - {(1UL << GLF_LRU), "L" }, \ {(1UL << GLF_OBJECT), "o" }, \ {(1UL << GLF_BLOCKING), "b" }, \ {(1UL << GLF_INSTANTIATE_NEEDED), "n" }, \ -- 2.55.0