网络模块初始化
网络模块的初始化顺序
系统启动初始化时,一旦进入start_kernel,则说明低级初始化已经完成,接下来是对各种设备和子系统的初始化,网络模块初始化流程的调用关系如下图(图片来自:《Linux内核源码剖析-tcp/ip实现》):
在内核初始化过程中,初始化了很多模块,如图中的中断模块(init_irq)等。最后会启动init内核线程继续执行初始化,完成初始化之后,init内核现成将蜕变成用户进程。有关网络的初始化过程主要由sysctl_init和do_initcalls完成,前者主要完成对sysctl的初始化注册过程,后者的功能相对复杂,不只是对网络模块的初始化,只要运用了initcall技术的模块都会被初始化;
内核模块代码可以静态地连接到内核映像文件中,也可以动态的加载到内核空间中,通常,设备驱动程序和功能扩展模块都是在需要时动态加载的,有些协议族也作为内核模块动态加载,如ipv6、unix协议族等,而作为基本内核模块的ipv4则不能动态加载。
优化基于宏的标记
以e100为例,通过宏展开得到以下内容:
module_init(e100_init_module) –>__initcall(e100_init_module)–>device_initcall(e100_init_module)–>__define_initcall(e100_init_module, 6)–>static initcall_t __initcall_e100_init_module6 __used __attribute__((__section__(“.initcall6.init”))) = e100_init_module
1 /* 2 * initcalls are now grouped by functionality into separate 3 * subsections. Ordering inside the subsections is determined 4 * by link order. 5 * For backwards compatibility, initcall() puts the call in 6 * the device init subsection. 7 * 8 * The `id' arg to __define_initcall() is needed so that multiple initcalls 9 * can point at the same handler without causing duplicate-symbol build errors. 10 * 11 * Initcalls are run by placing pointers in initcall sections that the 12 * kernel iterates at runtime. The linker can do dead code / data elimination 13 * and remove that completely, so the initcall sections have to be marked 14 * as KEEP() in the linker script. 15 */ 16 17 #define __define_initcall(fn, id) \ 18 static initcall_t __initcall_##fn##id __used \ 19 __attribute__((__section__(".initcall" #id ".init"))) = fn; 20 21 /* 22 * Early initcalls run before initializing SMP. 23 * 24 * Only for built-in code, not modules. 25 */ 26 #define early_initcall(fn) __define_initcall(fn, early) 27 28 /* 29 * A "pure" initcall has no dependencies on anything else, and purely 30 * initializes variables that couldn't be statically initialized. 31 * 32 * This only exists for built-in code, not for modules. 33 * Keep main.c:initcall_level_names[] in sync. 34 */ 35 #define pure_initcall(fn) __define_initcall(fn, 0) 36 37 #define core_initcall(fn) __define_initcall(fn, 1) 38 #define core_initcall_sync(fn) __define_initcall(fn, 1s) 39 #define postcore_initcall(fn) __define_initcall(fn, 2) 40 #define postcore_initcall_sync(fn) __define_initcall(fn, 2s) 41 #define arch_initcall(fn) __define_initcall(fn, 3) 42 #define arch_initcall_sync(fn) __define_initcall(fn, 3s) 43 #define subsys_initcall(fn) __define_initcall(fn, 4) 44 #define subsys_initcall_sync(fn) __define_initcall(fn, 4s) 45 #define fs_initcall(fn) __define_initcall(fn, 5) 46 #define fs_initcall_sync(fn) __define_initcall(fn, 5s) 47 #define rootfs_initcall(fn) __define_initcall(fn, rootfs) 48 #define device_initcall(fn) __define_initcall(fn, 6) 49 #define device_initcall_sync(fn) __define_initcall(fn, 6s) 50 #define late_initcall(fn) __define_initcall(fn, 7) 51 #define late_initcall_sync(fn) __define_initcall(fn, 7s) 52 53 #define __initcall(fn) device_initcall(fn) 54 55 #define __exitcall(fn) \ 56 static exitcall_t __exitcall_##fn __exit_call = fn 57 58 #define console_initcall(fn) \ 59 static initcall_t __initcall_##fn \ 60 __used __section(.con_initcall.init) = fn 61 62 #define security_initcall(fn) \ 63 static initcall_t __initcall_##fn \ 64 __used __section(.security_initcall.init) = fn 65 66 67 /** 68 * module_init() - driver initialization entry point 69 * @x: function to be run at kernel boot time or module insertion 70 * 71 * module_init() will either be called during do_initcalls() (if 72 * builtin) or at module insertion time (if a module). There can only 73 * be one per module. 74 */ 75 #define module_init(x) __initcall(x); 76 77 /** 78 * module_exit() - driver exit entry point 79 * @x: function to be run when driver is removed 80 * 81 * module_exit() will wrap the driver clean-up code 82 * with cleanup_module() when used with rmmod when 83 * the driver is a module. If the driver is statically 84 * compiled into the kernel, module_exit() has no effect. 85 * There can only be one per module. 86 */ 87 #define module_exit(x) __exitcall(x);
各个段空间对应的宏:
如图(图片来自:《Linux内核源码剖析-tcp/ip实现》):
通过下面的do_init_calls循环调用执行各个段的初始化函数:
1 int __init_or_module do_one_initcall(initcall_t fn) 2 { 3 int count = preempt_count(); 4 int ret; 5 char msgbuf[64]; 6 7 if (initcall_blacklisted(fn)) 8 return -EPERM; 9 10 if (initcall_debug) 11 ret = do_one_initcall_debug(fn); 12 else 13 ret = fn(); 14 15 msgbuf[0] = 0; 16 17 if (preempt_count() != count) { 18 sprintf(msgbuf, "preemption imbalance "); 19 preempt_count_set(count); 20 } 21 if (irqs_disabled()) { 22 strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf)); 23 local_irq_enable(); 24 } 25 WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); 26 27 add_latent_entropy(); 28 return ret; 29 } 30 31 32 extern initcall_t __initcall_start[]; 33 extern initcall_t __initcall0_start[]; 34 extern initcall_t __initcall1_start[]; 35 extern initcall_t __initcall2_start[]; 36 extern initcall_t __initcall3_start[]; 37 extern initcall_t __initcall4_start[]; 38 extern initcall_t __initcall5_start[]; 39 extern initcall_t __initcall6_start[]; 40 extern initcall_t __initcall7_start[]; 41 extern initcall_t __initcall_end[]; 42 43 static initcall_t *initcall_levels[] __initdata = { 44 __initcall0_start, 45 __initcall1_start, 46 __initcall2_start, 47 __initcall3_start, 48 __initcall4_start, 49 __initcall5_start, 50 __initcall6_start, 51 __initcall7_start, 52 __initcall_end, 53 }; 54 55 /* Keep these in sync with initcalls in include/linux/init.h */ 56 static char *initcall_level_names[] __initdata = { 57 "early", 58 "core", 59 "postcore", 60 "arch", 61 "subsys", 62 "fs", 63 "device", 64 "late", 65 }; 66 67 static void __init do_initcall_level(int level) 68 { 69 initcall_t *fn; 70 71 strcpy(initcall_command_line, saved_command_line); 72 parse_args(initcall_level_names[level], 73 initcall_command_line, __start___param, 74 __stop___param - __start___param, 75 level, level, 76 NULL, &repair_env_string); 77 78 for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) 79 do_one_initcall(*fn); 80 } 81 82 static void __init do_initcalls(void) 83 { 84 int level; 85 86 for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) 87 do_initcall_level(level); 88 }
注:本文中部分内容引用自《Linux内核源码剖析-tcp/ip实现》