• 网络模块初始化


    网络模块的初始化顺序

    系统启动初始化时,一旦进入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
    ", 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实现》

  • 相关阅读:
    makefile基本操作
    Visual Studio Code 的 launch.json 解析
    Manjaro 安装与配置
    Manjaro 系统添加国内源和安装搜狗输入法
    ununtu 18.04 163 mirror
    How to Use GNOME Shell Extensions
    Ubuntu: repository/PPA 源
    什么是线程阻塞?为什么会出现线程阻塞?
    Java锁的种类
    java8流式编程(一)
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7534952.html
Copyright © 2020-2023  润新知