fs/gfs2/glock.h | 30 ++++++++++++++++++++++++++++++ fs/gfs2/super.c | 3 +++ 2 files changed, 33 insertions(+)
Metadata glocks may have associated address spaces used as caches. Avoid
reclaiming such glocks under memory pressure while their mappings are
still populated or their state is not unlocked, as this can lead to
invalid page cache state and GLOCK_BUG_ON().
Signed-off-by: Guilherme Giacomo Simoes <trintaeoitogc@gmail.com>
---
fs/gfs2/glock.h | 30 ++++++++++++++++++++++++++++++
fs/gfs2/super.c | 3 +++
2 files changed, 33 insertions(+)
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 55d5985f32a0..12f57461f687 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -305,4 +305,34 @@ static inline bool glock_needs_demote(struct gfs2_glock *gl)
test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags));
}
+/*
+ * gfs2_glock_not_evictable - check if a glock is not evictable
+ * @gl: The glock to check
+ *
+ * Glocks which do not represent normal filesystem inodes (e.g. statfs, quota, rindex)
+ * may have associated address spaces used as metadata caches. These glocks must not
+ * be reclaimed under memory pressure while their mappings are still populated or their
+ * state is not unlocked.
+ */
+
+static inline bool gfs2_glock_not_evictable(struct gfs2_glock *gl)
+{
+ if (gl->gl_name.ln_type == LM_TYPE_INODE)
+ return false;
+
+ if (gl->gl_ops->go_flags & GLOF_ASPACE) {
+ struct gfs2_glock_aspace *gla;
+
+ gla = container_of(gl, struct gfs2_glock_aspace, glock);
+
+ if (!mapping_empty(&gla->mapping))
+ return true;
+ }
+
+ if (gl->gl_state != LM_ST_UNLOCKED)
+ return true;
+
+ return false;
+}
+
#endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index f6cd907b3ec6..86544cdafe53 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1164,6 +1164,9 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
static void gfs2_glock_put_eventually(struct gfs2_glock *gl)
{
+ if (gfs2_glock_not_evictable(gl))
+ return;
+
if (current->flags & PF_MEMALLOC)
gfs2_glock_put_async(gl);
else
--
2.34.1
Guilherme,
On Tue, Feb 3, 2026 at 11:40 AM Guilherme Giacomo Simoes
<trintaeoitogc@gmail.com> wrote:
> Metadata glocks may have associated address spaces used as caches. Avoid
> reclaiming such glocks under memory pressure while their mappings are
> still populated or their state is not unlocked, as this can lead to
> invalid page cache state and GLOCK_BUG_ON().
What invalid page cache state and GLOCK_BUG_ON() errors is this about, exactly?
> Signed-off-by: Guilherme Giacomo Simoes <trintaeoitogc@gmail.com>
> ---
> fs/gfs2/glock.h | 30 ++++++++++++++++++++++++++++++
> fs/gfs2/super.c | 3 +++
> 2 files changed, 33 insertions(+)
>
> diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
> index 55d5985f32a0..12f57461f687 100644
> --- a/fs/gfs2/glock.h
> +++ b/fs/gfs2/glock.h
> @@ -305,4 +305,34 @@ static inline bool glock_needs_demote(struct gfs2_glock *gl)
> test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags));
> }
>
> +/*
> + * gfs2_glock_not_evictable - check if a glock is not evictable
> + * @gl: The glock to check
> + *
> + * Glocks which do not represent normal filesystem inodes (e.g. statfs, quota, rindex)
> + * may have associated address spaces used as metadata caches. These glocks must not
> + * be reclaimed under memory pressure while their mappings are still populated or their
> + * state is not unlocked.
> + */
> +
> +static inline bool gfs2_glock_not_evictable(struct gfs2_glock *gl)
> +{
> + if (gl->gl_name.ln_type == LM_TYPE_INODE)
> + return false;
> +
> + if (gl->gl_ops->go_flags & GLOF_ASPACE) {
> + struct gfs2_glock_aspace *gla;
> +
> + gla = container_of(gl, struct gfs2_glock_aspace, glock);
> +
> + if (!mapping_empty(&gla->mapping))
> + return true;
> + }
> +
> + if (gl->gl_state != LM_ST_UNLOCKED)
> + return true;
> +
> + return false;
> +}
> +
> #endif /* __GLOCK_DOT_H__ */
> diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
> index f6cd907b3ec6..86544cdafe53 100644
> --- a/fs/gfs2/super.c
> +++ b/fs/gfs2/super.c
> @@ -1164,6 +1164,9 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
>
> static void gfs2_glock_put_eventually(struct gfs2_glock *gl)
> {
> + if (gfs2_glock_not_evictable(gl))
> + return;
> +
This leaks a glock reference, so it's definitely wrong.
> if (current->flags & PF_MEMALLOC)
> gfs2_glock_put_async(gl);
> else
> --
> 2.34.1
>
Thanks,
Andreas
Andreas Gruenbacher <agruenba@redhat.com> wrote: > > Metadata glocks may have associated address spaces used as caches. Avoid > > reclaiming such glocks under memory pressure while their mappings are > > still populated or their state is not unlocked, as this can lead to > > invalid page cache state and GLOCK_BUG_ON(). > > What invalid page cache state and GLOCK_BUG_ON() errors is this about, exactly? On __gfs2_glock_put() (fs/gfs2/glock.c) the GLOCK_BUG_ON() is triggered under memory pressure while the glock is still locked or the glock is populated with metadata caches. This happens because the __gfs2_glock_put() can't truncate pages with a private datas (truncate_inode_pages_final(mapping) is failed), how the metadata is a private folio, the GLOCK_BUG_ON(gl, !mapping_empty(mapping)) is trigged. > This leaks a glock reference, so it's definitely wrong. But this glock is a private folio with metadata or is still locked. I think this can't be evictable
On Tue, Feb 3, 2026 at 12:43 PM Guilherme Giacomo Simoes <trintaeoitogc@gmail.com> wrote: > Andreas Gruenbacher <agruenba@redhat.com> wrote: > > > Metadata glocks may have associated address spaces used as caches. Avoid > > > reclaiming such glocks under memory pressure while their mappings are > > > still populated or their state is not unlocked, as this can lead to > > > invalid page cache state and GLOCK_BUG_ON(). > > > > What invalid page cache state and GLOCK_BUG_ON() errors is this about, exactly? > > On __gfs2_glock_put() (fs/gfs2/glock.c) the GLOCK_BUG_ON() is triggered under > memory pressure while the glock is still locked or the glock is populated with > metadata caches. There are two GLOCK_BUG_ON() assertions in __gfs2_glock_put(). I assume you are talking about this one: GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); This should never trigger because each holder has a glock reference (see the gfs2_glock_hold() in __gfs2_holder_init()), and so gl->gl_lockref should never reach zero while there are holders. If none of the holders has the HIF_HOLDER flag set, we don't know if the glock is actually locked. > This happens because the __gfs2_glock_put() can't truncate pages with a private > datas (truncate_inode_pages_final(mapping) is failed), how the metadata is a > private folio, the GLOCK_BUG_ON(gl, !mapping_empty(mapping)) is trigged. What are the actual messages you are getting? > > This leaks a glock reference, so it's definitely wrong. > > But this glock is a private folio with metadata or is still locked. I think > this can't be evictable What even makes you think these glocks are evictable? Thanks, Andreas
Andreas Gruenbacher <agruenba@redhat.com> wrote:
> There are two GLOCK_BUG_ON() assertions in __gfs2_glock_put(). I
> assume you are talking about this one:
>
> GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
>
> This should never trigger because each holder has a glock reference
> (see the gfs2_glock_hold() in __gfs2_holder_init()), and so
> gl->gl_lockref should never reach zero while there are holders.
>
> If none of the holders has the HIF_HOLDER flag set, we don't know if
> the glock is actually locked.
Sorry, yes has two GLOCK_BUG_ON() assertions. I talk about the second
GLOCK_BUG_ON on __gfs2_glock_put():
`GLOCK_BUG_ON(gl, !mapping_empty(mapping))`.
NOT ABOUT `GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));` (the first
GLOCK_BUG_ON())
The dump_stack() indicates a memory pressure and the
gfs2_glock_put_eventually() on fs/gfs2/super.c is called.
But when the __gfs2_glock_put() was called, the glock was has a private folios.
I test by this way:
```
struct address_space *mapping = ...;
pgoff_t index;
struct folio *folio;
xa_for_each(&mapping->i_pages, index, folio) {
if (folio_test_private(folio))
pr_err("I have private folios")
}
```
And, I can see the glock is about metadata:
`gl->gl_name.ln_type != LM_TYPE_INODE`
the truncate_inode_pages_final() failed silently when the folio is private.
I guess maybe evict metadata (or locked) glock is not a good idea.
Thanks, Guilherme
© 2016 - 2026 Red Hat, Inc.