diff options
| author | Hao Ge <gehao@kylinos.cn> | 2025-10-15 22:16:42 +0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-10-23 16:24:21 +0200 |
| commit | 8f4c0c2fa3e3dbf0b20f6dba1f47ddfd6f83184c (patch) | |
| tree | f7f859780e9dc7a94f751f9f6bb3b173334df170 /mm | |
| parent | 6b3c15cf967bdeed91c5f2c251c4b783e1a0e9f1 (diff) | |
| download | linux-8f4c0c2fa3e3dbf0b20f6dba1f47ddfd6f83184c.tar.gz linux-8f4c0c2fa3e3dbf0b20f6dba1f47ddfd6f83184c.tar.bz2 linux-8f4c0c2fa3e3dbf0b20f6dba1f47ddfd6f83184c.zip | |
slab: reset slab->obj_ext when freeing and it is OBJEXTS_ALLOC_FAIL
commit 86f54f9b6c17d6567c69e3a6fed52fdf5d7dbe93 upstream.
If obj_exts allocation failed, slab->obj_exts is set to OBJEXTS_ALLOC_FAIL,
But we do not clear it when freeing the slab. Since OBJEXTS_ALLOC_FAIL and
MEMCG_DATA_OBJEXTS currently share the same bit position, during the
release of the associated folio, a VM_BUG_ON_FOLIO() check in
folio_memcg_kmem() is triggered because the OBJEXTS_ALLOC_FAIL flag was
not cleared, causing it to be interpreted as a kmem folio (non-slab)
with MEMCG_OBJEXTS_DATA flag set, which is invalid because
MEMCG_OBJEXTS_DATA is supposed to be set only on slabs.
Another problem that predates sharing the OBJEXTS_ALLOC_FAIL and
MEMCG_DATA_OBJEXTS bits is that on configurations with
is_check_pages_enabled(), the non-cleared bit in page->memcg_data will
trigger a free_page_is_bad() failure "page still charged to cgroup"
When freeing a slab, we clear slab->obj_exts if the obj_ext array has
been successfully allocated. So let's clear it also when the allocation
has failed.
Fixes: 09c46563ff6d ("codetag: debug: introduce OBJEXTS_ALLOC_FAIL to mark failed slab_ext allocations")
Fixes: 7612833192d5 ("slab: Reuse first bit for OBJEXTS_ALLOC_FAIL")
Link: https://lore.kernel.org/all/20251015141642.700170-1-hao.ge@linux.dev/
Cc: <stable@vger.kernel.org>
Signed-off-by: Hao Ge <gehao@kylinos.cn>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/slub.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/mm/slub.c b/mm/slub.c index 9bdadf9909e0..16b5e221c94d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2073,8 +2073,15 @@ static inline void free_slab_obj_exts(struct slab *slab) struct slabobj_ext *obj_exts; obj_exts = slab_obj_exts(slab); - if (!obj_exts) + if (!obj_exts) { + /* + * If obj_exts allocation failed, slab->obj_exts is set to + * OBJEXTS_ALLOC_FAIL. In this case, we end up here and should + * clear the flag. + */ + slab->obj_exts = 0; return; + } /* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its |
