Linux Modules
 help / color / mirror / Atom feed
* [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit()
@ 2026-10-02  8:40 Petr Pavlu
  2026-10-02  9:14 ` sashiko-bot
  2026-10-04 12:49 ` Aaron Tomlin
  0 siblings, 2 replies; 4+ messages in thread
From: Petr Pavlu @ 2026-10-02  8:40 UTC (permalink / raw)
  To: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Alexei Starovoitov, Daniel Borkmann
  Cc: Aaron Tomlin, John Fastabend, linux-modules, bpf, linux-kernel

Module-related stubs for CONFIG_MODULES=n can normally live in
linux/module.h. This works well when the stub does nothing or simply
returns a constant. However, some non-module implementations may be more
expensive, either because they have a real implementation or because they
require additional dependencies to be pulled into linux/module.h. This
header appears in roughly 15k #include directives across the kernel, so it
should avoid bringing in unnecessary definitions.

Specifically, linux/module.h defines module_put_and_kthread_exit() as an
alias for kthread_exit() when CONFIG_MODULES=n. That in turn requires
linux/kthread.h, even though linux/module.h otherwise has no need for it.
Note that linux/module.h currently doesn't include linux/kthread.h and
requires its users to pick it up through other paths, which is itself not
quite right.

Introduce kernel/module/stubs.c to hold such stubs, built only for
CONFIG_MODULES=n. This mirrors kernel/time/posix-stubs.c, which is used for
CONFIG_POSIX_TIMERS=n.

Define module_put_and_kthread_exit() in both CONFIG_MODULES configurations
to call __module_put_and_kthread_exit() and add a CONFIG_MODULES=n
implementation of that function to kernel/module/stubs.c. Since
__module_put_and_kthread_exit() is now implemented even when
CONFIG_MODULES=n, remove the corresponding '#ifdef CONFIG_MODULES' from the
noreturn_deny BPF list.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
kernel/module/stubs.c should also be used for add_taint_module() [1] in the
future.

[1] https://lore.kernel.org/linux-modules/a79a6a06-cc48-4036-882d-95e9b4cc01cf@suse.com/
---
Changes in v2:
- Remove the unnecessary include of internal.h in stubs.c.
- Remove the unnecessary EXPORT_SYMBOL(__module_put_and_kthread_exit) in
  stubs.c.
- Link to v1: https://patch.msgid.link/20260922-module-stubs-v1-1-abe465a24879@suse.com
---
 include/linux/module.h | 9 +++------
 kernel/Makefile        | 2 +-
 kernel/bpf/verifier.c  | 2 --
 kernel/module/Makefile | 4 ++++
 kernel/module/main.c   | 1 +
 kernel/module/stubs.c  | 9 +++++++++
 6 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index 96cc98568eea..4c7bd7f9f889 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -658,10 +658,6 @@ static inline bool within_module(unsigned long addr, const struct module *mod)
 /* Search for module by name: must be in a RCU critical section. */
 struct module *find_module(const char *name);
 
-extern void __noreturn __module_put_and_kthread_exit(struct module *mod,
-			long code);
-#define module_put_and_kthread_exit(code) __module_put_and_kthread_exit(THIS_MODULE, code)
-
 #ifdef CONFIG_MODULE_UNLOAD
 int module_refcount(struct module *mod);
 void __symbol_put(const char *symbol);
@@ -850,8 +846,6 @@ static inline int unregister_module_notifier(struct notifier_block *nb)
 	return 0;
 }
 
-#define module_put_and_kthread_exit(code) kthread_exit(code)
-
 static inline void print_modules(void)
 {
 }
@@ -879,6 +873,9 @@ static inline void module_for_each_mod(int(*func)(struct module *mod, void *data
 }
 #endif /* CONFIG_MODULES */
 
+void __noreturn __module_put_and_kthread_exit(struct module *mod, long code);
+#define module_put_and_kthread_exit(code) __module_put_and_kthread_exit(THIS_MODULE, code)
+
 #ifdef CONFIG_SYSFS
 extern struct kset *module_kset;
 extern const struct kobj_type module_ktype;
diff --git a/kernel/Makefile b/kernel/Makefile
index 1e1a31673577..08a94594975d 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -58,7 +58,7 @@ obj-y += liveupdate/
 obj-y += dma/
 obj-y += entry/
 obj-y += unwind/
-obj-$(CONFIG_MODULES) += module/
+obj-y += module/
 
 obj-$(CONFIG_KCMP) += kcmp.o
 obj-$(CONFIG_FREEZER) += freezer.o
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 72a3f5998dd2..be70f10e4968 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -20417,9 +20417,7 @@ BTF_ID(func, __ia32_sys_exit_group)
 BTF_ID(func, __kunit_abort)
 BTF_ID(func, kunit_try_catch_throw)
 #endif
-#ifdef CONFIG_MODULES
 BTF_ID(func, __module_put_and_kthread_exit)
-#endif
 #ifdef CONFIG_X86_64
 BTF_ID(func, __x64_sys_exit)
 BTF_ID(func, __x64_sys_exit_group)
diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index 50ffcc413b54..72fd2972eacf 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -7,6 +7,7 @@
 # and produce insane amounts of uninteresting coverage.
 KCOV_INSTRUMENT_main.o := n
 
+ifeq ($(CONFIG_MODULES),y)
 obj-y += main.o
 obj-y += strict_rwx.o
 obj-y += kmod.o
@@ -23,3 +24,6 @@ obj-$(CONFIG_KGDB_KDB) += kdb.o
 obj-$(CONFIG_MODVERSIONS) += version.o
 obj-$(CONFIG_MODULE_UNLOAD_TAINT_TRACKING) += tracking.o
 obj-$(CONFIG_MODULE_STATS) += stats.o
+else
+obj-y += stubs.o
+endif
diff --git a/kernel/module/main.c b/kernel/module/main.c
index d0e1e0bd2ad0..a8bf803afa81 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -60,6 +60,7 @@
 #include <linux/codetag.h>
 #include <linux/debugfs.h>
 #include <linux/execmem.h>
+#include <linux/kthread.h>
 #include <uapi/linux/module.h>
 #include "internal.h"
 
diff --git a/kernel/module/stubs.c b/kernel/module/stubs.c
new file mode 100644
index 000000000000..1385c87e8169
--- /dev/null
+++ b/kernel/module/stubs.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+
+void __noreturn __module_put_and_kthread_exit(struct module *mod, long code)
+{
+	kthread_exit(code);
+}

---
base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20260918-module-stubs-dccefe41dace

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit()
  2026-10-02  8:40 [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit() Petr Pavlu
@ 2026-10-02  9:14 ` sashiko-bot
  2026-10-02 11:58   ` Petr Pavlu
  2026-10-04 12:49 ` Aaron Tomlin
  1 sibling, 1 reply; 4+ messages in thread
From: sashiko-bot @ 2026-10-02  9:14 UTC (permalink / raw)
  To: Petr Pavlu; +Cc: bpf, linux-modules, Petr Pavlu

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] bpf: resolve_btfids build failure with CONFIG_MODULES=n and LTO/GC
--

commit caaeb9d0651743944c690c066494bb16509c01e9
Author: Petr Pavlu <petr.pavlu@suse.com>

module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit()

This commit introduces kernel/module/stubs.c to hold stub functions when
CONFIG_MODULES is disabled. It moves the stub implementation for
__module_put_and_kthread_exit() to this new file and removes the
corresponding #ifdef from the BPF verifier's noreturn list.

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 72a3f5998dd27..be70f10e49682 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -20417,9 +20417,7 @@ BTF_ID(func, __ia32_sys_exit_group)
>  BTF_ID(func, __kunit_abort)
>  BTF_ID(func, kunit_try_catch_throw)
>  #endif
> -#ifdef CONFIG_MODULES
>  BTF_ID(func, __module_put_and_kthread_exit)

[Severity: Low]
If CONFIG_MODULES=n and dead-code elimination (like CONFIG_LTO_CLANG or
CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) is enabled, will this cause 
resolve_btfids to fail?

Because the #ifdef is removed, this unconditionally requires the function to
be present in the BTF. If there are no callers in the kernel, the linker 
might discard the stub function, causing a missing BTF ID and a fatal build 
error under CONFIG_WERROR.

> -#endif
>  #ifdef CONFIG_X86_64
>  BTF_ID(func, __x64_sys_exit)
>  BTF_ID(func, __x64_sys_exit_group)

[ ... ]

> diff --git a/kernel/module/stubs.c b/kernel/module/stubs.c
> new file mode 100644
> index 0000000000000..1385c87e81695
> --- /dev/null
> +++ b/kernel/module/stubs.c
> @@ -0,0 +1,9 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +
> +void __noreturn __module_put_and_kthread_exit(struct module *mod, long code)
> +{

[Severity: Low]
Does this stub need a __used attribute to prevent the linker from discarding 
it?

If no code references module_put_and_kthread_exit() when CONFIG_MODULES=n, 
this function is silently discarded by the linker during dead code 
elimination, which leads to the resolve_btfids build failure mentioned above.

> +	kthread_exit(code);
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261002-module-stubs-v2-1-a0d8c6ad1738@suse.com?part=1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit()
  2026-10-02  9:14 ` sashiko-bot
@ 2026-10-02 11:58   ` Petr Pavlu
  0 siblings, 0 replies; 4+ messages in thread
From: Petr Pavlu @ 2026-10-02 11:58 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: bpf, linux-modules

On 10/2/26 11:14 AM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Low] bpf: resolve_btfids build failure with CONFIG_MODULES=n and LTO/GC
> --
> 
> commit caaeb9d0651743944c690c066494bb16509c01e9
> Author: Petr Pavlu <petr.pavlu@suse.com>
> 
> module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit()
> 
> This commit introduces kernel/module/stubs.c to hold stub functions when
> CONFIG_MODULES is disabled. It moves the stub implementation for
> __module_put_and_kthread_exit() to this new file and removes the
> corresponding #ifdef from the BPF verifier's noreturn list.
> 
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 72a3f5998dd27..be70f10e49682 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -20417,9 +20417,7 @@ BTF_ID(func, __ia32_sys_exit_group)
>>  BTF_ID(func, __kunit_abort)
>>  BTF_ID(func, kunit_try_catch_throw)
>>  #endif
>> -#ifdef CONFIG_MODULES
>>  BTF_ID(func, __module_put_and_kthread_exit)
> 
> [Severity: Low]
> If CONFIG_MODULES=n and dead-code elimination (like CONFIG_LTO_CLANG or
> CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) is enabled, will this cause 
> resolve_btfids to fail?
> 
> Because the #ifdef is removed, this unconditionally requires the function to
> be present in the BTF. If there are no callers in the kernel, the linker 
> might discard the stub function, causing a missing BTF ID and a fatal build 
> error under CONFIG_WERROR.

This is a valid issue. I think a simple solution would be to mark
__module_put_and_kthread_exit() as __retain.

-- Petr

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit()
  2026-10-02  8:40 [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit() Petr Pavlu
  2026-10-02  9:14 ` sashiko-bot
@ 2026-10-04 12:49 ` Aaron Tomlin
  1 sibling, 0 replies; 4+ messages in thread
From: Aaron Tomlin @ 2026-10-04 12:49 UTC (permalink / raw)
  To: Petr Pavlu
  Cc: Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Alexei Starovoitov,
	Daniel Borkmann, John Fastabend, linux-modules, bpf, linux-kernel

On Fri, Oct 02, 2026 at 10:40:38AM +0200, Petr Pavlu wrote:
> Module-related stubs for CONFIG_MODULES=n can normally live in
> linux/module.h. This works well when the stub does nothing or simply
> returns a constant. However, some non-module implementations may be more
> expensive, either because they have a real implementation or because they
> require additional dependencies to be pulled into linux/module.h. This
> header appears in roughly 15k #include directives across the kernel, so it
> should avoid bringing in unnecessary definitions.
> 
> Specifically, linux/module.h defines module_put_and_kthread_exit() as an
> alias for kthread_exit() when CONFIG_MODULES=n. That in turn requires
> linux/kthread.h, even though linux/module.h otherwise has no need for it.
> Note that linux/module.h currently doesn't include linux/kthread.h and
> requires its users to pick it up through other paths, which is itself not
> quite right.
> 
> Introduce kernel/module/stubs.c to hold such stubs, built only for
> CONFIG_MODULES=n. This mirrors kernel/time/posix-stubs.c, which is used for
> CONFIG_POSIX_TIMERS=n.
> 
> Define module_put_and_kthread_exit() in both CONFIG_MODULES configurations
> to call __module_put_and_kthread_exit() and add a CONFIG_MODULES=n
> implementation of that function to kernel/module/stubs.c. Since
> __module_put_and_kthread_exit() is now implemented even when
> CONFIG_MODULES=n, remove the corresponding '#ifdef CONFIG_MODULES' from the
> noreturn_deny BPF list.
> 
> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
> ---
> kernel/module/stubs.c should also be used for add_taint_module() [1] in the
> future.
> 
> [1] https://lore.kernel.org/linux-modules/a79a6a06-cc48-4036-882d-95e9b4cc01cf@suse.com/
> ---
> Changes in v2:
> - Remove the unnecessary include of internal.h in stubs.c.
> - Remove the unnecessary EXPORT_SYMBOL(__module_put_and_kthread_exit) in
>   stubs.c.
> - Link to v1: https://patch.msgid.link/20260922-module-stubs-v1-1-abe465a24879@suse.com
> ---
>  include/linux/module.h | 9 +++------
>  kernel/Makefile        | 2 +-
>  kernel/bpf/verifier.c  | 2 --
>  kernel/module/Makefile | 4 ++++
>  kernel/module/main.c   | 1 +
>  kernel/module/stubs.c  | 9 +++++++++
>  6 files changed, 18 insertions(+), 9 deletions(-)
> 
> diff --git a/include/linux/module.h b/include/linux/module.h
> index 96cc98568eea..4c7bd7f9f889 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -658,10 +658,6 @@ static inline bool within_module(unsigned long addr, const struct module *mod)
>  /* Search for module by name: must be in a RCU critical section. */
>  struct module *find_module(const char *name);
>  
> -extern void __noreturn __module_put_and_kthread_exit(struct module *mod,
> -			long code);
> -#define module_put_and_kthread_exit(code) __module_put_and_kthread_exit(THIS_MODULE, code)
> -
>  #ifdef CONFIG_MODULE_UNLOAD
>  int module_refcount(struct module *mod);
>  void __symbol_put(const char *symbol);
> @@ -850,8 +846,6 @@ static inline int unregister_module_notifier(struct notifier_block *nb)
>  	return 0;
>  }
>  
> -#define module_put_and_kthread_exit(code) kthread_exit(code)
> -
>  static inline void print_modules(void)
>  {
>  }
> @@ -879,6 +873,9 @@ static inline void module_for_each_mod(int(*func)(struct module *mod, void *data
>  }
>  #endif /* CONFIG_MODULES */
>  
> +void __noreturn __module_put_and_kthread_exit(struct module *mod, long code);
> +#define module_put_and_kthread_exit(code) __module_put_and_kthread_exit(THIS_MODULE, code)
> +
>  #ifdef CONFIG_SYSFS
>  extern struct kset *module_kset;
>  extern const struct kobj_type module_ktype;
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 1e1a31673577..08a94594975d 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -58,7 +58,7 @@ obj-y += liveupdate/
>  obj-y += dma/
>  obj-y += entry/
>  obj-y += unwind/
> -obj-$(CONFIG_MODULES) += module/
> +obj-y += module/
>  
>  obj-$(CONFIG_KCMP) += kcmp.o
>  obj-$(CONFIG_FREEZER) += freezer.o
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 72a3f5998dd2..be70f10e4968 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -20417,9 +20417,7 @@ BTF_ID(func, __ia32_sys_exit_group)
>  BTF_ID(func, __kunit_abort)
>  BTF_ID(func, kunit_try_catch_throw)
>  #endif
> -#ifdef CONFIG_MODULES
>  BTF_ID(func, __module_put_and_kthread_exit)
> -#endif
>  #ifdef CONFIG_X86_64
>  BTF_ID(func, __x64_sys_exit)
>  BTF_ID(func, __x64_sys_exit_group)
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 50ffcc413b54..72fd2972eacf 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -7,6 +7,7 @@
>  # and produce insane amounts of uninteresting coverage.
>  KCOV_INSTRUMENT_main.o := n
>  
> +ifeq ($(CONFIG_MODULES),y)
>  obj-y += main.o
>  obj-y += strict_rwx.o
>  obj-y += kmod.o
> @@ -23,3 +24,6 @@ obj-$(CONFIG_KGDB_KDB) += kdb.o
>  obj-$(CONFIG_MODVERSIONS) += version.o
>  obj-$(CONFIG_MODULE_UNLOAD_TAINT_TRACKING) += tracking.o
>  obj-$(CONFIG_MODULE_STATS) += stats.o
> +else
> +obj-y += stubs.o
> +endif
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index d0e1e0bd2ad0..a8bf803afa81 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -60,6 +60,7 @@
>  #include <linux/codetag.h>
>  #include <linux/debugfs.h>
>  #include <linux/execmem.h>
> +#include <linux/kthread.h>
>  #include <uapi/linux/module.h>
>  #include "internal.h"
>  
> diff --git a/kernel/module/stubs.c b/kernel/module/stubs.c
> new file mode 100644
> index 000000000000..1385c87e8169
> --- /dev/null
> +++ b/kernel/module/stubs.c
> @@ -0,0 +1,9 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +
> +void __noreturn __module_put_and_kthread_exit(struct module *mod, long code)
> +{
> +	kthread_exit(code);
> +}
> 
> ---
> base-commit: 93f51579e7df248780214094418f205253383cc5
> change-id: 20260918-module-stubs-dccefe41dace

Hi Petr,

I noticed your response to Sashiko [1].

I agree. Marking the stub function with "__used __retain" in
kernel/module/stubs.c (e.g. as per "#define __bpf_kfunc __used __retain
__noclone noinline") should be sufficient. Thank you.

Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>

[1]: https://lore.kernel.org/sashiko-reviews/c166a29c-14f4-44ee-81ac-d79c82175fc8@suse.com/

Kind regards,
-- 
Aaron Tomlin

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-04 12:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-02  8:40 [PATCH v2] module: Add stubs.c for CONFIG_MODULES=n module_put_and_kthread_exit() Petr Pavlu
2026-10-02  9:14 ` sashiko-bot
2026-10-02 11:58   ` Petr Pavlu
2026-10-04 12:49 ` Aaron Tomlin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox