* [RFC PATCH 0/3] alloc_tag: fix races and a leak around shutdown_mem_profiling()
@ 2026-08-13 9:34 Hao Ge
2026-08-13 9:34 ` [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled Hao Ge
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Hao Ge @ 2026-08-13 9:34 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Aaron Tomlin
Cc: linux-modules, linux-kernel, linux-mm, Hao Ge
Three fixes for races and a leak in how allocation profiling meets the
module loader, reported by sashiko.
1. percpu counter leak on modules loaded after profiling is disabled.
2. layout/move TOCTOU that can silently overwrite module memory when
profiling disabled between layout_sections() and move_module().
Additionally, the retry logic here depends on [1].
3. AB-BA deadlock between module load and /proc/allocinfo readers.
Patch 1 adds CODETAG_MODULE_EXCLUDED so profiling-disabled modules are
dropped from the tag list instead of half-registered, and frees the
section reservation unconditionally on unload. Patch 2 makes
layout_sections() the sole authority for codetag placement. Patch 3
defers remove_proc_entry() to a workqueue.
Feedback and suggestions are warmly welcomed; I would greatly appreciate
any input.
Remaining sashiko-reported bugs will be fixed in follow-up patches.
[1]: https://lore.kernel.org/all/20260812054105.102637-3-hao.ge@linux.dev/
Hao Ge (3):
alloc_tag: skip percpu counter allocation when profiling is disabled
module: move codetag section placement decision to layout_sections()
alloc_tag: remove /proc/allocinfo outside of mod_lock
include/linux/codetag.h | 4 ++++
include/linux/module.h | 11 +++++++++++
kernel/module/main.c | 17 ++++++-----------
lib/codetag.c | 8 +++++---
mm/alloc_tag.c | 25 ++++++++++++++++++++++---
5 files changed, 48 insertions(+), 17 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled 2026-08-13 9:34 [RFC PATCH 0/3] alloc_tag: fix races and a leak around shutdown_mem_profiling() Hao Ge @ 2026-08-13 9:34 ` Hao Ge 2026-08-15 6:15 ` Suren Baghdasaryan 2026-08-13 9:34 ` [RFC PATCH 2/3] module: move codetag section placement decision to layout_sections() Hao Ge 2026-08-13 9:34 ` [RFC PATCH 3/3] alloc_tag: remove /proc/allocinfo outside of mod_lock Hao Ge 2 siblings, 1 reply; 7+ messages in thread From: Hao Ge @ 2026-08-13 9:34 UTC (permalink / raw) To: Suren Baghdasaryan, Andrew Morton, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin Cc: linux-modules, linux-kernel, linux-mm, Hao Ge After shutdown_mem_profiling() clears mem_profiling_support, needs_section_mem() returns false, so later modules have their codetag section placed as regular data and never enter the alloc_tag maple tree. codetag_load_module() still called load_module(), which allocated a percpu counter for every tag; release_module_tags() could not find these modules on unload, so the counters leaked. Return CODETAG_MODULE_EXCLUDED from load_module() when profiling is off: codetag_module_init() drops the module's cmod and no counters are allocated. codetag_unload_module() now always calls free_section_mem(), since an excluded module may still hold a reserved section. Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") Signed-off-by: Hao Ge <hao.ge@linux.dev> --- include/linux/codetag.h | 4 ++++ lib/codetag.c | 8 +++++--- mm/alloc_tag.c | 8 ++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/linux/codetag.h b/include/linux/codetag.h index a25a085c2df1..88081c618673 100644 --- a/include/linux/codetag.h +++ b/include/linux/codetag.h @@ -52,6 +52,10 @@ struct codetag_type_desc { #endif }; +/* module_load() return values */ +#define CODETAG_MODULE_LOAD 0 /* module loads with its tags */ +#define CODETAG_MODULE_EXCLUDED 1 /* module loads without its tags */ + struct codetag_iterator { struct codetag_type *cttype; struct codetag_module *cmod; diff --git a/lib/codetag.c b/lib/codetag.c index a9cda4c962a3..8506ecab9ea7 100644 --- a/lib/codetag.c +++ b/lib/codetag.c @@ -238,9 +238,10 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod) } up_write(&cttype->mod_lock); - if (err < 0) { + if (err) { + /* Error or excluded: cmod is dropped, free it. */ kfree(cmod); - return err; + return err < 0 ? err : 0; } return 0; @@ -388,7 +389,8 @@ void codetag_unload_module(struct module *mod) ++cttype->content_id; } up_write(&cttype->mod_lock); - if (found && cttype->desc.free_section_mem) + /* an excluded module may still hold section memory */ + if (cttype->desc.free_section_mem) cttype->desc.free_section_mem(mod, true); } mutex_unlock(&codetag_lock); diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c index 0a7b657fe2de..461fa87fbb0b 100644 --- a/mm/alloc_tag.c +++ b/mm/alloc_tag.c @@ -977,9 +977,13 @@ static int load_module(struct module *mod, struct codetag *start, struct codetag struct alloc_tag *stop_tag; struct alloc_tag *tag; + /* Profiling disabled: load the module but exclude its tags. */ + if (!mem_profiling_support) + return CODETAG_MODULE_EXCLUDED; + /* percpu counters for core allocations are already statically allocated */ if (!mod) - return 0; + return CODETAG_MODULE_LOAD; start_tag = ct_to_alloc_tag(start); stop_tag = ct_to_alloc_tag(stop); @@ -1002,7 +1006,7 @@ static int load_module(struct module *mod, struct codetag *start, struct codetag */ kmemleak_ignore_percpu(tag->counters); } - return 0; + return CODETAG_MODULE_LOAD; } static void replace_module(struct module *mod, struct module *new_mod) -- 2.25.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled 2026-08-13 9:34 ` [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled Hao Ge @ 2026-08-15 6:15 ` Suren Baghdasaryan 0 siblings, 0 replies; 7+ messages in thread From: Suren Baghdasaryan @ 2026-08-15 6:15 UTC (permalink / raw) To: Hao Ge Cc: Andrew Morton, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin, linux-modules, linux-kernel, linux-mm On Thu, Aug 13, 2026 at 2:34 AM Hao Ge <hao.ge@linux.dev> wrote: > > After shutdown_mem_profiling() clears mem_profiling_support, > needs_section_mem() returns false, so later modules have their codetag > section placed as regular data and never enter the alloc_tag maple tree. > codetag_load_module() still called load_module(), which allocated a percpu > counter for every tag; release_module_tags() could not find these modules > on unload, so the counters leaked. > > Return CODETAG_MODULE_EXCLUDED from load_module() when profiling is off: > codetag_module_init() drops the module's cmod and no counters are > allocated. codetag_unload_module() now always calls free_section_mem(), > since an excluded module may still hold a reserved section. > > Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") > Signed-off-by: Hao Ge <hao.ge@linux.dev> Thanks for the fix. I think it could be done simpler, see below. > --- > include/linux/codetag.h | 4 ++++ > lib/codetag.c | 8 +++++--- > mm/alloc_tag.c | 8 ++++++-- > 3 files changed, 15 insertions(+), 5 deletions(-) > > diff --git a/include/linux/codetag.h b/include/linux/codetag.h > index a25a085c2df1..88081c618673 100644 > --- a/include/linux/codetag.h > +++ b/include/linux/codetag.h > @@ -52,6 +52,10 @@ struct codetag_type_desc { > #endif > }; > > +/* module_load() return values */ > +#define CODETAG_MODULE_LOAD 0 /* module loads with its tags */ > +#define CODETAG_MODULE_EXCLUDED 1 /* module loads without its tags */ I see no reason for adding these special values. You could simply return -ENOTSUP when profiling is disabled. > + > struct codetag_iterator { > struct codetag_type *cttype; > struct codetag_module *cmod; > diff --git a/lib/codetag.c b/lib/codetag.c > index a9cda4c962a3..8506ecab9ea7 100644 > --- a/lib/codetag.c > +++ b/lib/codetag.c > @@ -238,9 +238,10 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod) > } > up_write(&cttype->mod_lock); > > - if (err < 0) { > + if (err) { > + /* Error or excluded: cmod is dropped, free it. */ IIUC here you want to call kfree() if profiling got disabled. If you return -ENOTSUP instead of CODETAG_MODULE_EXCLUDED then this condition does not need to change. > kfree(cmod); > - return err; > + return err < 0 ? err : 0; Here you can do: if (err && err != -ENOTSUP) return err; return 0; > } > > return 0; > @@ -388,7 +389,8 @@ void codetag_unload_module(struct module *mod) > ++cttype->content_id; > } > up_write(&cttype->mod_lock); > - if (found && cttype->desc.free_section_mem) > + /* an excluded module may still hold section memory */ > + if (cttype->desc.free_section_mem) > cttype->desc.free_section_mem(mod, true); > } > mutex_unlock(&codetag_lock); > diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c > index 0a7b657fe2de..461fa87fbb0b 100644 > --- a/mm/alloc_tag.c > +++ b/mm/alloc_tag.c > @@ -977,9 +977,13 @@ static int load_module(struct module *mod, struct codetag *start, struct codetag > struct alloc_tag *stop_tag; > struct alloc_tag *tag; > > + /* Profiling disabled: load the module but exclude its tags. */ > + if (!mem_profiling_support) > + return CODETAG_MODULE_EXCLUDED; Return -ENOTSUP here. > + > /* percpu counters for core allocations are already statically allocated */ > if (!mod) > - return 0; > + return CODETAG_MODULE_LOAD; > > start_tag = ct_to_alloc_tag(start); > stop_tag = ct_to_alloc_tag(stop); > @@ -1002,7 +1006,7 @@ static int load_module(struct module *mod, struct codetag *start, struct codetag > */ > kmemleak_ignore_percpu(tag->counters); > } > - return 0; > + return CODETAG_MODULE_LOAD; > } > > static void replace_module(struct module *mod, struct module *new_mod) > -- > 2.25.1 > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 2/3] module: move codetag section placement decision to layout_sections() 2026-08-13 9:34 [RFC PATCH 0/3] alloc_tag: fix races and a leak around shutdown_mem_profiling() Hao Ge 2026-08-13 9:34 ` [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled Hao Ge @ 2026-08-13 9:34 ` Hao Ge 2026-08-15 6:21 ` Suren Baghdasaryan 2026-08-13 9:34 ` [RFC PATCH 3/3] alloc_tag: remove /proc/allocinfo outside of mod_lock Hao Ge 2 siblings, 1 reply; 7+ messages in thread From: Hao Ge @ 2026-08-13 9:34 UTC (permalink / raw) To: Suren Baghdasaryan, Andrew Morton, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin Cc: linux-modules, linux-kernel, linux-mm, Hao Ge codetag_needs_module_section() is called twice per codetag section, once in layout_sections() and once in move_module(), and both depend on mem_profiling_support, which changes without a lock. If profiling is disabled between the two calls, layout excludes the section (offset 0) while move copies it as normal memory to offset 0: CPU0 (insmod A) CPU1 (insmod B) ---------------- ---------------- layout_sections() needs_section_mem() == true sh_entsize: type, offset = 0 reserve_module_tags() overflows shutdown_mem_profiling() mem_profiling_support = false move_module() needs_section_mem() == false offset = sh_entsize & MASK = 0 memcpy(mod->mem[type].base + 0, ...) -> overwrites the first section there Record the decision in layout_sections() in sh_entsize using a MOD_MEM_CODETAG type, and have move_module() use that instead of asking again. reserve_module_tags() returns -EAGAIN if profiling was disabled after layout, so the loader retries and places the section as normal memory. Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") Signed-off-by: Hao Ge <hao.ge@linux.dev> --- include/linux/module.h | 11 +++++++++++ kernel/module/main.c | 17 ++++++----------- mm/alloc_tag.c | 8 ++++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 7566815fabbe..a02016528e1d 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -328,6 +328,17 @@ enum mod_mem_type { MOD_INVALID = -1, }; +/* + * If CONFIG_CODE_TAGGING is on, modules get a .codetag section. + * codetag_needs_module_section() says where it goes: the usual + * mod->mem[], or off to the codetag region. + * + * Mark the codetag-region ones with MOD_MEM_NUM_TYPES. + * It's just past the real types, so it doesn't index into mod->mem[] + * and for_each_mod_mem_type() skips it. + */ +#define MOD_MEM_CODETAG MOD_MEM_NUM_TYPES + #define mod_mem_type_is_init(type) \ ((type) == MOD_INIT_TEXT || \ (type) == MOD_INIT_DATA || \ diff --git a/kernel/module/main.c b/kernel/module/main.c index ed26f167be84..2337bf604f58 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1728,11 +1728,8 @@ static void __layout_sections(struct module *mod, struct load_info *info, bool i * preallocated contiguous memory. */ if (codetag_needs_module_section(mod, sname, s->sh_size)) { - /* - * s->sh_entsize won't be used but populate the - * type field to avoid confusion. - */ - s->sh_entsize = ((unsigned long)(type) & SH_ENTSIZE_TYPE_MASK) + s->sh_entsize = ((unsigned long)MOD_MEM_CODETAG + & SH_ENTSIZE_TYPE_MASK) << SH_ENTSIZE_TYPE_SHIFT; continue; } @@ -2815,11 +2812,10 @@ static int move_module(struct module *mod, struct load_info *info) continue; sname = info->secstrings + shdr->sh_name; - /* - * Load codetag sections separately as they might still be used - * after module unload. - */ - if (codetag_needs_module_section(mod, sname, shdr->sh_size)) { + + enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT; + + if (type == MOD_MEM_CODETAG) { dest = codetag_alloc_module_section(mod, sname, shdr->sh_size, arch_mod_section_prepend(mod, i), shdr->sh_addralign); if (WARN_ON(!dest)) { @@ -2832,7 +2828,6 @@ static int move_module(struct module *mod, struct load_info *info) } codetag_section_found = true; } else { - enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT; unsigned long offset = shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK; dest = mod->mem[type].base + offset; diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c index 461fa87fbb0b..7481180dadd2 100644 --- a/mm/alloc_tag.c +++ b/mm/alloc_tag.c @@ -893,6 +893,14 @@ static void *reserve_module_tags(struct module *mod, unsigned long size, if (size < sizeof(struct alloc_tag)) return ERR_PTR(-EINVAL); + /* + * Profiling may have been disabled by a concurrent module load. + * Return -EAGAIN so the loader retries with profiling off, laying + * the section out as ordinary module memory. + */ + if (!mem_profiling_support) + return ERR_PTR(-EAGAIN); + /* * align is always power of 2, so we can use IS_ALIGNED and ALIGN. * align 0 or 1 means no alignment, to simplify set to 1. -- 2.25.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 2/3] module: move codetag section placement decision to layout_sections() 2026-08-13 9:34 ` [RFC PATCH 2/3] module: move codetag section placement decision to layout_sections() Hao Ge @ 2026-08-15 6:21 ` Suren Baghdasaryan 0 siblings, 0 replies; 7+ messages in thread From: Suren Baghdasaryan @ 2026-08-15 6:21 UTC (permalink / raw) To: Hao Ge Cc: Andrew Morton, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin, linux-modules, linux-kernel, linux-mm On Thu, Aug 13, 2026 at 2:34 AM Hao Ge <hao.ge@linux.dev> wrote: > > codetag_needs_module_section() is called twice per codetag section, once > in layout_sections() and once in move_module(), and both depend on > mem_profiling_support, which changes without a lock. If profiling is > disabled between the two calls, layout excludes the section (offset 0) > while move copies it as normal memory to offset 0: > > CPU0 (insmod A) CPU1 (insmod B) > ---------------- ---------------- > layout_sections() > needs_section_mem() == true > sh_entsize: type, offset = 0 > reserve_module_tags() overflows > shutdown_mem_profiling() > mem_profiling_support = false > move_module() > needs_section_mem() == false > offset = sh_entsize & MASK = 0 > memcpy(mod->mem[type].base + 0, ...) > -> overwrites the first section there > > Record the decision in layout_sections() in sh_entsize using a > MOD_MEM_CODETAG type, and have move_module() use that instead of asking > again. > > reserve_module_tags() returns -EAGAIN if profiling was disabled after > layout, so the loader retries and places the section as normal memory. > > Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") > Signed-off-by: Hao Ge <hao.ge@linux.dev> > --- > include/linux/module.h | 11 +++++++++++ > kernel/module/main.c | 17 ++++++----------- > mm/alloc_tag.c | 8 ++++++++ > 3 files changed, 25 insertions(+), 11 deletions(-) > > diff --git a/include/linux/module.h b/include/linux/module.h > index 7566815fabbe..a02016528e1d 100644 > --- a/include/linux/module.h > +++ b/include/linux/module.h > @@ -328,6 +328,17 @@ enum mod_mem_type { > MOD_INVALID = -1, > }; > > +/* > + * If CONFIG_CODE_TAGGING is on, modules get a .codetag section. > + * codetag_needs_module_section() says where it goes: the usual > + * mod->mem[], or off to the codetag region. > + * > + * Mark the codetag-region ones with MOD_MEM_NUM_TYPES. > + * It's just past the real types, so it doesn't index into mod->mem[] > + * and for_each_mod_mem_type() skips it. > + */ > +#define MOD_MEM_CODETAG MOD_MEM_NUM_TYPES Ok, it feels a bit hacky but it's probably the simplest way to mark codetag regions. > + > #define mod_mem_type_is_init(type) \ > ((type) == MOD_INIT_TEXT || \ > (type) == MOD_INIT_DATA || \ > diff --git a/kernel/module/main.c b/kernel/module/main.c > index ed26f167be84..2337bf604f58 100644 > --- a/kernel/module/main.c > +++ b/kernel/module/main.c > @@ -1728,11 +1728,8 @@ static void __layout_sections(struct module *mod, struct load_info *info, bool i > * preallocated contiguous memory. > */ > if (codetag_needs_module_section(mod, sname, s->sh_size)) { > - /* > - * s->sh_entsize won't be used but populate the > - * type field to avoid confusion. > - */ > - s->sh_entsize = ((unsigned long)(type) & SH_ENTSIZE_TYPE_MASK) > + s->sh_entsize = ((unsigned long)MOD_MEM_CODETAG > + & SH_ENTSIZE_TYPE_MASK) > << SH_ENTSIZE_TYPE_SHIFT; > continue; > } > @@ -2815,11 +2812,10 @@ static int move_module(struct module *mod, struct load_info *info) > continue; > > sname = info->secstrings + shdr->sh_name; > - /* > - * Load codetag sections separately as they might still be used > - * after module unload. > - */ > - if (codetag_needs_module_section(mod, sname, shdr->sh_size)) { > + > + enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT; > + > + if (type == MOD_MEM_CODETAG) { > dest = codetag_alloc_module_section(mod, sname, shdr->sh_size, > arch_mod_section_prepend(mod, i), shdr->sh_addralign); > if (WARN_ON(!dest)) { > @@ -2832,7 +2828,6 @@ static int move_module(struct module *mod, struct load_info *info) > } > codetag_section_found = true; > } else { > - enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT; > unsigned long offset = shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK; > > dest = mod->mem[type].base + offset; > diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c > index 461fa87fbb0b..7481180dadd2 100644 > --- a/mm/alloc_tag.c > +++ b/mm/alloc_tag.c > @@ -893,6 +893,14 @@ static void *reserve_module_tags(struct module *mod, unsigned long size, > if (size < sizeof(struct alloc_tag)) > return ERR_PTR(-EINVAL); > > + /* > + * Profiling may have been disabled by a concurrent module load. > + * Return -EAGAIN so the loader retries with profiling off, laying > + * the section out as ordinary module memory. > + */ > + if (!mem_profiling_support) > + return ERR_PTR(-EAGAIN); I think this requires your patch [1] from another patchset to work correctly, correct? If so, I would suggest sending this patch as part of that patchset since there is a dependency. [1] https://lore.kernel.org/all/20260812054105.102637-3-hao.ge@linux.dev/ > + > /* > * align is always power of 2, so we can use IS_ALIGNED and ALIGN. > * align 0 or 1 means no alignment, to simplify set to 1. > -- > 2.25.1 > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 3/3] alloc_tag: remove /proc/allocinfo outside of mod_lock 2026-08-13 9:34 [RFC PATCH 0/3] alloc_tag: fix races and a leak around shutdown_mem_profiling() Hao Ge 2026-08-13 9:34 ` [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled Hao Ge 2026-08-13 9:34 ` [RFC PATCH 2/3] module: move codetag section placement decision to layout_sections() Hao Ge @ 2026-08-13 9:34 ` Hao Ge 2026-08-15 6:51 ` Suren Baghdasaryan 2 siblings, 1 reply; 7+ messages in thread From: Hao Ge @ 2026-08-13 9:34 UTC (permalink / raw) To: Suren Baghdasaryan, Andrew Morton, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin Cc: linux-modules, linux-kernel, linux-mm, Hao Ge shutdown_mem_profiling() calls remove_proc_entry() from reserve_module_tags(), which runs under mod_lock held for write. remove_proc_entry() waits for readers, and a reader takes mod_lock for read in allocinfo_start(): CPU0 (insmod) CPU1 (read /proc/allocinfo) ---------------- ---------------------------- reserve_module_tags() down_write(&mod_lock) [held] use_pde() [in_use++] allocinfo_start() down_read(&mod_lock) <- blocks shutdown_mem_profiling() remove_proc_entry() wait for in_use == 0 <- blocks Move remove_proc_entry() to a workqueue. Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") Signed-off-by: Hao Ge <hao.ge@linux.dev> --- mm/alloc_tag.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c index 7481180dadd2..b80f5a151f28 100644 --- a/mm/alloc_tag.c +++ b/mm/alloc_tag.c @@ -591,6 +591,13 @@ void pgalloc_tag_swap(struct folio *new, struct folio *old) put_page_tag_ref(handle_new); } +static void remove_allocinfo_file(struct work_struct *work) +{ + remove_proc_entry(ALLOCINFO_FILE_NAME, NULL); +} + +static DECLARE_WORK(remove_allocinfo_work, remove_allocinfo_file); + static void shutdown_mem_profiling(bool remove_file) { if (mem_alloc_profiling_enabled()) @@ -600,7 +607,7 @@ static void shutdown_mem_profiling(bool remove_file) return; if (remove_file) - remove_proc_entry(ALLOCINFO_FILE_NAME, NULL); + schedule_work(&remove_allocinfo_work); mem_profiling_support = false; } -- 2.25.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 3/3] alloc_tag: remove /proc/allocinfo outside of mod_lock 2026-08-13 9:34 ` [RFC PATCH 3/3] alloc_tag: remove /proc/allocinfo outside of mod_lock Hao Ge @ 2026-08-15 6:51 ` Suren Baghdasaryan 0 siblings, 0 replies; 7+ messages in thread From: Suren Baghdasaryan @ 2026-08-15 6:51 UTC (permalink / raw) To: Hao Ge Cc: Andrew Morton, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin, linux-modules, linux-kernel, linux-mm On Thu, Aug 13, 2026 at 2:34 AM Hao Ge <hao.ge@linux.dev> wrote: > > shutdown_mem_profiling() calls remove_proc_entry() from > reserve_module_tags(), which runs under mod_lock held for write. > remove_proc_entry() waits for readers, and a reader takes mod_lock for > read in allocinfo_start(): > > CPU0 (insmod) CPU1 (read /proc/allocinfo) > ---------------- ---------------------------- > reserve_module_tags() > down_write(&mod_lock) [held] > use_pde() [in_use++] > allocinfo_start() > down_read(&mod_lock) <- blocks > shutdown_mem_profiling() > remove_proc_entry() > wait for in_use == 0 <- blocks Yes, this is indeed a possible race. > > Move remove_proc_entry() to a workqueue. > > Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") I think all these issues were reported by Sashiko, so you should add a Reported-by tag. > Signed-off-by: Hao Ge <hao.ge@linux.dev> LGTM > --- > mm/alloc_tag.c | 9 ++++++++- > 1 file changed, 8 insertions(+), 1 deletion(-) > > diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c > index 7481180dadd2..b80f5a151f28 100644 > --- a/mm/alloc_tag.c > +++ b/mm/alloc_tag.c > @@ -591,6 +591,13 @@ void pgalloc_tag_swap(struct folio *new, struct folio *old) > put_page_tag_ref(handle_new); > } > > +static void remove_allocinfo_file(struct work_struct *work) > +{ > + remove_proc_entry(ALLOCINFO_FILE_NAME, NULL); > +} > + > +static DECLARE_WORK(remove_allocinfo_work, remove_allocinfo_file); > + > static void shutdown_mem_profiling(bool remove_file) > { > if (mem_alloc_profiling_enabled()) > @@ -600,7 +607,7 @@ static void shutdown_mem_profiling(bool remove_file) > return; > > if (remove_file) > - remove_proc_entry(ALLOCINFO_FILE_NAME, NULL); > + schedule_work(&remove_allocinfo_work); > mem_profiling_support = false; > } > > -- > 2.25.1 > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-15 6:51 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-08-13 9:34 [RFC PATCH 0/3] alloc_tag: fix races and a leak around shutdown_mem_profiling() Hao Ge 2026-08-13 9:34 ` [RFC PATCH 1/3] alloc_tag: skip percpu counter allocation when profiling is disabled Hao Ge 2026-08-15 6:15 ` Suren Baghdasaryan 2026-08-13 9:34 ` [RFC PATCH 2/3] module: move codetag section placement decision to layout_sections() Hao Ge 2026-08-15 6:21 ` Suren Baghdasaryan 2026-08-13 9:34 ` [RFC PATCH 3/3] alloc_tag: remove /proc/allocinfo outside of mod_lock Hao Ge 2026-08-15 6:51 ` Suren Baghdasaryan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®