commit 1fab0d6a932d000780cd232b7d10ebfbe69f477c Author: Tim Bird Date: Fri Sep 12 11:31:52 2008 -0700 Add deferred_module_init This allows statically linked modules to be initialized sometime after the initial bootstrap. To do this, change the module_init() macro to deferred_module_init(), for those init routines you want to defer. Signed-off-by: Tim Bird diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S index a9b8560..f5bdfc4 100644 --- a/arch/x86/kernel/vmlinux_32.lds.S +++ b/arch/x86/kernel/vmlinux_32.lds.S @@ -140,11 +140,21 @@ SECTIONS *(.con_initcall.init) __con_initcall_end = .; } + .deferred_initcall.init : AT(ADDR(.deferred_initcall.init) - LOAD_OFFSET) { + __def_initcall_start = .; + *(.deferred_initcall.init) + __def_initcall_end = .; + } .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { __x86_cpu_dev_start = .; *(.x86_cpu_dev.init) __x86_cpu_dev_end = .; } + .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) { + __x86cpuvendor_start = .; + *(.x86cpuvendor.init) + __x86cpuvendor_end = .; + } SECURITY_INIT . = ALIGN(4); .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 59ea42e..a247a8e 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -703,6 +703,22 @@ static int execdomains_read_proc(char *page, char **start, off_t off, return proc_calc_metrics(page, start, off, count, eof, len); } +extern void do_deferred_initcalls(void); + +static int deferred_initcalls_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + static int deferred_initcalls_done = 0; + int len; + + len = sprintf(page, "%d\n", deferred_initcalls_done); + if (! deferred_initcalls_done) { + do_deferred_initcalls(); + deferred_initcalls_done = 1; + } + return proc_calc_metrics(page, start, off, count, eof, len); +} + #ifdef CONFIG_PROC_PAGE_MONITOR #define KPMSIZE sizeof(u64) #define KPMMASK (KPMSIZE - 1) @@ -855,6 +871,7 @@ void __init proc_misc_init(void) {"filesystems", filesystems_read_proc}, {"cmdline", cmdline_read_proc}, {"execdomains", execdomains_read_proc}, + {"deferred_initcalls", deferred_initcalls_read_proc}, {NULL,} }; for (p = simple_ones; p->name; p++) diff --git a/include/linux/init.h b/include/linux/init.h index ad63824..ef61767 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -200,6 +200,7 @@ extern void (*late_time_init)(void); #define device_initcall_sync(fn) __define_initcall("6s",fn,6s) #define late_initcall(fn) __define_initcall("7",fn,7) #define late_initcall_sync(fn) __define_initcall("7s",fn,7s) +//#define deferred_initcall(fn) __define_initcall("8",fn,8) #define __initcall(fn) device_initcall(fn) @@ -214,6 +215,10 @@ extern void (*late_time_init)(void); static initcall_t __initcall_##fn \ __used __section(.security_initcall.init) = fn +#define deferred_initcall(fn) \ + static initcall_t __initcall_##fn \ + __used __section(.deferred_initcall.init) = fn + struct obs_kernel_param { const char *str; int (*setup_func)(char *); @@ -254,6 +259,7 @@ void __init parse_early_param(void); * be one per module. */ #define module_init(x) __initcall(x); +#define deferred_module_init(x) deferred_initcall(x); /** * module_exit() - driver exit entry point diff --git a/init/main.c b/init/main.c index 27f6bf6..e4bbdb2 100644 --- a/init/main.c +++ b/init/main.c @@ -789,12 +789,40 @@ static void run_init_process(char *init_filename) kernel_execve(init_filename, argv_init, envp_init); } +extern initcall_t __def_initcall_start[], __def_initcall_end[]; + +/* call deferred init routines */ +void do_deferred_initcalls(void) +{ + initcall_t *call; + static int already_run=0; + + if (already_run) { + printk("do_deferred_initcalls() has already run\n"); + return; + } + + already_run=1; + + printk("Running do_deferred_initcalls()\n"); + + lock_kernel(); /* make environment similar to early boot */ + + for(call = __def_initcall_start; call < __def_initcall_end; call++) + do_one_initcall(*call); + + flush_scheduled_work(); + + free_initmem(); + unlock_kernel(); +} + /* This is a non __init function. Force it to be noinline otherwise gcc * makes it inline to init() and it becomes part of init.text section */ static int noinline init_post(void) { - free_initmem(); + //free_initmem(); unlock_kernel(); mark_rodata_ro(); system_state = SYSTEM_RUNNING;