On 7/23/24 11:32, Youling Tang wrote: > From: Youling Tang <tangyouling@xxxxxxxxxx> > > In theory init/exit should match their sequence, thus normally they should > look like this: > -------------------------+------------------------ > init_A(); | > init_B(); | > init_C(); | > | exit_C(); > | exit_B(); > | exit_A(); > > Providing module_subinit{_noexit} and module_subeixt helps macros ensure > that modules init/exit match their order, while also simplifying the code. > > The three macros are defined as follows: > - module_subinit(initfn, exitfn,rollback) > - module_subinit_noexit(initfn, rollback) > - module_subexit(rollback) > > `initfn` is the initialization function and `exitfn` is the corresponding > exit function. > > Signed-off-by: Youling Tang <tangyouling@xxxxxxxxxx> > --- > include/asm-generic/vmlinux.lds.h | 5 +++ > include/linux/init.h | 62 ++++++++++++++++++++++++++++++- > include/linux/module.h | 22 +++++++++++ > 3 files changed, 88 insertions(+), 1 deletion(-) > > diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h > index 677315e51e54..48ccac7c6448 100644 > --- a/include/asm-generic/vmlinux.lds.h > +++ b/include/asm-generic/vmlinux.lds.h > @@ -927,6 +927,10 @@ > INIT_CALLS_LEVEL(7) \ > __initcall_end = .; > > +#define SUBINIT_CALL \ > + *(.subinitcall.init) \ > + *(.subexitcall.exit) > + > #define CON_INITCALL \ > BOUNDED_SECTION_POST_LABEL(.con_initcall.init, __con_initcall, _start, _end) > > @@ -1155,6 +1159,7 @@ > INIT_DATA \ > INIT_SETUP(initsetup_align) \ > INIT_CALLS \ > + SUBINIT_CALL \ > CON_INITCALL \ > INIT_RAM_FS \ > } > diff --git a/include/linux/init.h b/include/linux/init.h > index ee1309473bc6..e8689ff2cb6c 100644 > --- a/include/linux/init.h > +++ b/include/linux/init.h > @@ -55,6 +55,9 @@ > #define __exitdata __section(".exit.data") > #define __exit_call __used __section(".exitcall.exit") > > +#define __subinit_call __used __section(".subinitcall.init") > +#define __subexit_call __used __section(".subexitcall.exit") > + > /* > * modpost check for section mismatches during the kernel build. > * A section mismatch happens when there are references from a > @@ -115,6 +118,9 @@ > typedef int (*initcall_t)(void); > typedef void (*exitcall_t)(void); > > +typedef int (*subinitcall_t)(void); > +typedef void (*subexitcall_t)(void); > + > #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS > typedef int initcall_entry_t; > > @@ -183,7 +189,61 @@ extern struct module __this_module; > #endif > > #endif > - > + > +#ifndef __ASSEMBLY__ > +struct subexitcall_rollback { > + /* > + * Records the address of the first sub-initialization function in the > + * ".subexitcall.exit" section > + */ > + unsigned long first_addr; > + int ncalls; > +}; > + > +static inline void __subexitcall_rollback(struct subexitcall_rollback *r) > +{ > + unsigned long addr = r->first_addr - sizeof(r->first_addr) * (r->ncalls - 1); > + > + for (; r->ncalls--; addr += sizeof(r->first_addr)) { > + unsigned long *tmp = (void *)addr; > + subexitcall_t fn = (subexitcall_t)*tmp; > + fn(); > + } > +} How does this guarantee the exit calls match sequence? Are you assuming linker puts exit functions in reverse order? --Mika