diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2024-03-28 19:59:45 +0100 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2024-04-09 18:35:58 +0200 |
commit | acf1f42faf5a27913eb7b8140cc255f1b3d14e48 (patch) | |
tree | d97bfcde676deba771c9141a6ad1098bc9b33e0d /fs/gfs2 | |
parent | c9a0a4b028e4fe16c79e685b2135ce2f097d0d0e (diff) | |
download | lwn-acf1f42faf5a27913eb7b8140cc255f1b3d14e48.tar.gz lwn-acf1f42faf5a27913eb7b8140cc255f1b3d14e48.zip |
gfs2: Fix "Make glock lru list scanning safer"
Commit 228804a35caa tried to add a refcount check to
gfs2_scan_glock_lru() to make sure that glocks that are still referenced
cannot be freed. It failed to account for the bias state_change() adds
to the refcount for held glocks, so held glocks are no longer removed
from the glock cache, which can lead to out-of-memory problems. Fix
that. (The inodes those glocks are associated with do get shrunk and do
get pushed out of memory.)
In addition, use the same eligibility check in gfs2_scan_glock_lru() and
gfs2_dispose_glock_lru().
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/glock.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 2882a42e88aa..04e0a8ac61d7 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1987,6 +1987,14 @@ static int glock_cmp(void *priv, const struct list_head *a, return 0; } +static bool can_free_glock(struct gfs2_glock *gl) +{ + bool held = gl->gl_state != LM_ST_UNLOCKED; + + return !test_bit(GLF_LOCK, &gl->gl_flags) && + gl->gl_lockref.count == held; +} + /** * gfs2_dispose_glock_lru - Demote a list of glocks * @list: The list to dispose of @@ -2020,7 +2028,7 @@ add_back_to_lru: atomic_inc(&lru_count); continue; } - if (test_bit(GLF_LOCK, &gl->gl_flags)) { + if (!can_free_glock(gl)) { spin_unlock(&gl->gl_lockref.lock); goto add_back_to_lru; } @@ -2052,16 +2060,10 @@ static long gfs2_scan_glock_lru(int nr) list_for_each_entry_safe(gl, next, &lru_list, gl_lru) { if (nr-- <= 0) break; - /* Test for being demotable */ - if (!test_bit(GLF_LOCK, &gl->gl_flags)) { - if (!spin_trylock(&gl->gl_lockref.lock)) - continue; - if (!gl->gl_lockref.count) { - list_move(&gl->gl_lru, &dispose); - atomic_dec(&lru_count); - freed++; - } - spin_unlock(&gl->gl_lockref.lock); + if (can_free_glock(gl)) { + list_move(&gl->gl_lru, &dispose); + atomic_dec(&lru_count); + freed++; } } if (!list_empty(&dispose)) |