slab: reset obj_ext when it is not actually valid during freeing
Subsystems (2)
PATCH v5 1/1 slab: reset obj_ext when it is not actually valid during freeing
From: Hao Ge <[email protected]>
If obj_exts allocation failed, slab->obj_exts is set to OBJEXTS_ALLOC_FAIL, But we did 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 it was mistakenly assumed that a valid folio->memcg_data was not cleared before freeing the folio.
When freeing a slab, we clear slab->obj_exts and reset it to 0 if the obj_ext array has been successfully allocated. So let's reset slab->obj_exts to 0 when freeing a slab if the obj_ext array allocated fail to allow them to be returned to the buddy system more smoothly.
---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to him
--- mm/slub.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
mm/slub.c +9 -1
@@ -2170,8 +2170,16 @@ 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 will end up here. +* Therefore, we should clear the OBJEXTS_ALLOC_FAIL flag first when freeing a slab. +* Then let's set it to 0 as below. +*/ + slab->obj_exts =0 ;return ; + }/* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its
Signature · 1 line
2.25.1
Quoted 33 lines · Hao Ge
From: Hao Ge <[email protected]>
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we did not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.When freeing a slab, we clear
slab->obj_extsand reset it to 0 if theobj_extarray has been successfully allocated. So let's resetslab->obj_extsto 0 when freeing a slab if theobj_extarray allocated fail to allow them to be returned to the buddy system more smoothly.Signed-off-by Hao Ge <[email protected]>---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to him--- mm/slub.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)mm/slub.c +0
-1@@ -2170,8 +2170,16 @@ static inline void free_slab_obj_exts(struct slab *slab)struct slabobj_ext *obj_exts; obj_exts =slab_obj_exts (slab); -if (!obj_exts)
mm/slub.c static inline void free_slab_obj_exts(struct slab *slab) · line 2182
Quoted 10 lines
mm/slub.c +9
-0+if (!obj_exts) { +/* +* If obj_exts allocation failed, slab->obj_exts is set to OBJEXTS_ALLOC_FAIL, +* In this case, we will end up here. +* Therefore, we should clear the OBJEXTS_ALLOC_FAIL flag first when freeing a slab. +* Then let's set it to 0 as below. +*/ + slab->obj_exts =0 ;return ; + }
How about this instead:
static inline void free_slab_obj_exts(struct slab *slab)
{
struct slabobj_ext *obj_exts;
obj_exts = slab_obj_exts(slab);
+ /*
+ * Reset obj_exts to ensure all bits including OBJEXTS_ALLOC_FAIL
+ * are always cleared.
+ */
+ slab->obj_exts = 0;
if (!obj_exts)
return;
/*
* obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its
* corresponding extension will be NULL. alloc_tag_sub() will throw a
* warning if slab has extensions but the extension of an object is
* NULL, therefore replace NULL with CODETAG_EMPTY to indicate that
* the extension for obj_exts is expected to be NULL.
*/
mark_objexts_empty(obj_exts);
kfree(obj_exts);- slab->obj_exts = 0;
}
Quoted 6 lines
mm/slub.c +0
-1/* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its -- 2.25.1
Quoted 60 lines · Suren Baghdasaryan
Quoted 33 lines · Hao Ge
From: Hao Ge <[email protected]>
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we did not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.When freeing a slab, we clear
slab->obj_extsand reset it to 0 if theobj_extarray has been successfully allocated. So let's resetslab->obj_extsto 0 when freeing a slab if theobj_extarray allocated fail to allow them to be returned to the buddy system more smoothly.Signed-off-by Hao Ge <[email protected]>---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to him--- mm/slub.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)mm/slub.c +0
-1@@ -2170,8 +2170,16 @@ static inline void free_slab_obj_exts(struct slab *slab)struct slabobj_ext *obj_exts; obj_exts =slab_obj_exts (slab); -if (!obj_exts)mm/slub.c static inline void free_slab_obj_exts(struct slab *slab) · line 2182
Quoted 10 lines
mm/slub.c +9
-0+if (!obj_exts) { +/* +* If obj_exts allocation failed, slab->obj_exts is set to OBJEXTS_ALLOC_FAIL, +* In this case, we will end up here. +* Therefore, we should clear the OBJEXTS_ALLOC_FAIL flag first when freeing a slab. +* Then let's set it to 0 as below. +*/ + slab->obj_exts =0 ;return ; + }How about this instead:
static inline void
free_slab_obj_exts(struct slab *slab){ struct slabobj_ext *obj_exts; obj_exts = slab_obj_exts(slab);(quoted diff) +5
-0+ /* + * Reset obj_exts to ensure all bits including OBJEXTS_ALLOC_FAIL + * are always cleared. + */ + slab->obj_exts = 0; if (!obj_exts) return;
Review
Quoted 10 lines
(quoted diff) +0
-1/* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its * corresponding extension will be NULL. alloc_tag_sub() will throw a * warning if slab has extensions but the extension of an object is * NULL, therefore replace NULL with CODETAG_EMPTY to indicate that * the extension for obj_exts is expected to be NULL. */ mark_objexts_empty(obj_exts); kfree(obj_exts); - slab->obj_exts = 0;
You have an older base, check current mainline, we evaluate slab->obj_exts later in the function
Quoted 8 lines
}
Quoted 6 lines
mm/slub.c +0
-1/* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its -- 2.25.1
Quoted 73 lines · Vlastimil Babka
Quoted 60 lines · Suren Baghdasaryan
Quoted 33 lines · Hao Ge
From: Hao Ge <[email protected]>
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we did not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.When freeing a slab, we clear
slab->obj_extsand reset it to 0 if theobj_extarray has been successfully allocated. So let's resetslab->obj_extsto 0 when freeing a slab if theobj_extarray allocated fail to allow them to be returned to the buddy system more smoothly.Signed-off-by Hao Ge <[email protected]>---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to him--- mm/slub.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)mm/slub.c +0
-1@@ -2170,8 +2170,16 @@ static inline void free_slab_obj_exts(struct slab *slab)struct slabobj_ext *obj_exts; obj_exts =slab_obj_exts (slab); -if (!obj_exts)mm/slub.c static inline void free_slab_obj_exts(struct slab *slab) · line 2182
Quoted 10 lines
mm/slub.c +9
-0+if (!obj_exts) { +/* +* If obj_exts allocation failed, slab->obj_exts is set to OBJEXTS_ALLOC_FAIL, +* In this case, we will end up here. +* Therefore, we should clear the OBJEXTS_ALLOC_FAIL flag first when freeing a slab. +* Then let's set it to 0 as below. +*/ + slab->obj_exts =0 ;return ; + }How about this instead:
static inline void
free_slab_obj_exts(struct slab *slab){ struct slabobj_ext *obj_exts; obj_exts = slab_obj_exts(slab);(quoted diff) +5
-0+ /* + * Reset obj_exts to ensure all bits including OBJEXTS_ALLOC_FAIL + * are always cleared. + */ + slab->obj_exts = 0; if (!obj_exts) return;Review
Quoted 10 lines
(quoted diff) +0
-1/* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its * corresponding extension will be NULL. alloc_tag_sub() will throw a * warning if slab has extensions but the extension of an object is * NULL, therefore replace NULL with CODETAG_EMPTY to indicate that * the extension for obj_exts is expected to be NULL. */ mark_objexts_empty(obj_exts); kfree(obj_exts); - slab->obj_exts = 0;
Quoted 2 lines
You have an older base, check current mainline, we evaluate
slab->obj_extslater in the function
Ah, sorry about that. Yeah, then this looks good.
Quoted 10 lines
Quoted 9 lines
}
Quoted 6 lines
mm/slub.c +0
-1/* * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its -- 2.25.1
Quoted 17 lines · Suren Baghdasaryan
Quoted 16 lines · Hao Ge
From: Hao Ge <[email protected]>
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we did not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.When freeing a slab, we clear
slab->obj_extsand reset it to 0 if theobj_extarray has been successfully allocated. So let's resetslab->obj_extsto 0 when freeing a slab if theobj_extarray allocated fail to allow them to be returned to the buddy system more smoothly.
Quoted 4 lines
Quoted 4 lines
Signed-off-by Hao Ge <[email protected]>---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to him
I've massaged the commit log and comments a bit and also realized that AFAICS we're actually fixing an issue that predates 7612833192d5 ("slab:
Reuse first bit for OBJEXTS_ALLOC_FAIL"). Am I wrong?
----8<----
From 8151384e5baf34db5812ed51e2e463796ab6e973 Mon Sep 17 00:00:00 2001
From: Hao Ge <[email protected]>
Date: Wed, 15 Oct 2025 22:16:42 +0800
Subject: [PATCH] slab: reset slab->obj_ext when freeing and it is
OBJEXTS_ALLOC_FAIL
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 it was mistakenly assumed that a valid folio->memcg_data was not cleared before freeing the folio.
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.
--- mm/slub.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
mm/slub.c +8 -1
@@ -2170,8 +2170,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
Signature · 1 line
2.51.0
Suren Baghdasaryan
Reviewed-byQuoted 51 lines · Vlastimil Babka
Quoted 17 lines · Suren Baghdasaryan
Quoted 16 lines · Hao Ge
From: Hao Ge <[email protected]>
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we did not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.When freeing a slab, we clear
slab->obj_extsand reset it to 0 if theobj_extarray has been successfully allocated. So let's resetslab->obj_extsto 0 when freeing a slab if theobj_extarray allocated fail to allow them to be returned to the buddy system more smoothly.Quoted 4 lines
Quoted 4 lines
Signed-off-by Hao Ge <[email protected]>---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to himI've massaged the commit log and comments a bit and also realized that AFAICS we're actually fixing an issue that predates
7612833192d5("slab:
Reuse first bit forOBJEXTS_ALLOC_FAIL"). Am I wrong?----8<----
From8151384e5baf34db5812ed51e2e463796ab6e973Mon Sep 17 00:00:00 2001
From: Hao Ge <[email protected]>
Date: Wed, 15 Oct 2025 22:16:42 +0800
Subject: [PATCH] slab: resetslab->obj_extwhen freeing and it is
OBJEXTS_ALLOC_FAILIf
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we do not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.Another problem that predates sharing the
OBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTSbits is that on configurations withis_check_pages_enabled(), the non-cleared bit inpage->memcg_datawill trigger afree_page_is_bad()failure "page still charged to cgroup"When freeing a slab, we clear
slab->obj_extsif theobj_extarray has been successfully allocated. So let's clear it also when the allocation has failed.
Quoted 5 lines
Fixes 09c46563ff6d ("codetag: debug: introduce OBJEXTS_ALLOC_FAIL to mark failed slab_ext allocations")Cc <[email protected]>Signed-off-by Hao Ge <[email protected]>Signed-off-by Vlastimil Babka <[email protected]>
Quoted 29 lines
--- mm/slub.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)mm/slub.c +8
-2@@ -2170,8 +2170,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 -- 2.51.0
Harry Yoo
Reviewed-byQuoted 18 lines · Vlastimil Babka
Quoted 17 lines · Suren Baghdasaryan
Quoted 16 lines · Hao Ge
From: Hao Ge <[email protected]>
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we did not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio, aVM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.When freeing a slab, we clear
slab->obj_extsand reset it to 0 if theobj_extarray has been successfully allocated. So let's resetslab->obj_extsto 0 when freeing a slab if theobj_extarray allocated fail to allow them to be returned to the buddy system more smoothly.
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Signed-off-by Hao Ge <[email protected]>---
v5: Adopt the simpler solution proposed by Vlastimil;
Many thanks to himI've massaged the commit log and comments a bit and also realized that AFAICS we're actually fixing an issue that predates
7612833192d5("slab:
Reuse first bit forOBJEXTS_ALLOC_FAIL"). Am I wrong?
You're not wrong!
Quoted 7 lines
----8<----
From8151384e5baf34db5812ed51e2e463796ab6e973Mon Sep 17 00:00:00 2001
From: Hao Ge <[email protected]>
Date: Wed, 15 Oct 2025 22:16:42 +0800
Subject: [PATCH] slab: resetslab->obj_extwhen freeing and it is
OBJEXTS_ALLOC_FAIL
Quoted 8 lines
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we do not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio,a
VM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.
nit: maybe this can be massaged as "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."
Quoted 9 lines
Another problem that predates sharing the
OBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTSbits is that on configurations withis_check_pages_enabled(), the non-cleared bit inpage->memcg_datawill trigger afree_page_is_bad()failure "page still charged to cgroup"When freeing a slab, we clear
slab->obj_extsif theobj_extarray has been successfully allocated. So let's clear it also when the allocation has failed.
Quoted 6 lines
Fixes 09c46563ff6d ("codetag: debug: introduce OBJEXTS_ALLOC_FAIL to mark failed slab_ext allocations")Cc <[email protected]>Signed-off-by Hao Ge <[email protected]>Signed-off-by Vlastimil Babka <[email protected]>---
Looks good to me,
Signature · 2 lines
Cheers, Harry / Hyeonggon
Quoted 26 lines
mm/slub.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)mm/slub.c +8
-1@@ -2170,8 +2170,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 Signature · 1 line
2.51.0
Vlastimil Babka
AppliedQuoted 16 lines · Harry Yoo
Quoted 7 lines
----8<----
From8151384e5baf34db5812ed51e2e463796ab6e973Mon Sep 17 00:00:00 2001
From: Hao Ge <[email protected]>
Date: Wed, 15 Oct 2025 22:16:42 +0800
Subject: [PATCH] slab: resetslab->obj_extwhen freeing and it is
OBJEXTS_ALLOC_FAILQuoted 8 lines
If
obj_extsallocation failed,slab->obj_extsis set toOBJEXTS_ALLOC_FAIL, But we do not clear it when freeing the slab. SinceOBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTScurrently share the same bit position, during the release of the associated folio,a
VM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because it was mistakenly assumed that a validfolio->memcg_datawas not cleared before freeing the folio.
Quoted 5 lines
nit: maybe this can be massaged as "a
VM_BUG_ON_FOLIO()check infolio_memcg_kmem()is triggered because theOBJEXTS_ALLOC_FAILflag was not cleared, causing it to be interpreted as a kmem folio (non-slab) withMEMCG_OBJEXTS_DATAflag set, which is invalid becauseMEMCG_OBJEXTS_DATAis supposed to be set only on slabs."
Thanks, applied
Quoted 16 lines
Quoted 9 lines
Another problem that predates sharing the
OBJEXTS_ALLOC_FAILandMEMCG_DATA_OBJEXTSbits is that on configurations withis_check_pages_enabled(), the non-cleared bit inpage->memcg_datawill trigger afree_page_is_bad()failure "page still charged to cgroup"When freeing a slab, we clear
slab->obj_extsif theobj_extarray has been successfully allocated. So let's clear it also when the allocation has failed.Quoted 6 lines
Fixes 09c46563ff6d ("codetag: debug: introduce OBJEXTS_ALLOC_FAIL to mark failed slab_ext allocations")Cc <[email protected]>Signed-off-by Hao Ge <[email protected]>Signed-off-by Vlastimil Babka <[email protected]>---
Quoted 2 lines
Looks good to me,
Reviewed-by Harry Yoo <[email protected]>
and this too.