Linux中与“内核模块”相关的数据结构

【摘要】本文详细解释了linux中与模块相关的内核数据结构,便于大家在学习理解内核源码或驱动编程中理解相应代码和思想。

三、内核模块相关的数据结构

目录

  • THIS_MODULE宏
  • module结构体
  • module_use

3.1 THIS_MODULE宏

  • 和CURRENT宏有几分相似,可以通过THIS_MODULE宏来引用模块的struct module结构指针。

  • 位于\linux-2.6.32.63\include\linux\module.h

    #ifdef MODULE
        #define MODULE_GENERIC_TABLE(gtype,name)            \
        extern const struct gtype##_id __mod_##gtype##_table        \
          __attribute__ ((unused, alias(__stringify(name))))
        
        extern struct module __this_module;
        #define THIS_MODULE (&__this_module)
    #else  /* !MODULE */
        #define MODULE_GENERIC_TABLE(gtype,name)
        #define THIS_MODULE ((struct module *)0)
    #endif
    
  • __this_module这个符号是在加载到内核后才产生的。insmod命令执行后,会调用kernel/module.c里的一个系统调用sys_init_module,它会调用load_module函数,将用户空间传入的整个内核模块文件创建成一个内核模块,并返回一个struct module结构体,从此,内核中便以这个结构体代表这个内核模块。THIS_MODULE类似进程的CURRENT。

  • 关于sys_init_module、load_module的系统调用内核代码原理分析,请参阅http://www.cnblogs.com/LittleHann/p/3920387.html

3.2 module结构体

  • struct module在内核中代表一个内核模块,通过insmod(实际执行sys_init_module系统调用)把自己编写的内核模块插入内核时,模块便与一个 struct module结构体相关联,并成为内核的一部分,也就是说在内核中,以module这个结构体代表一个内核模块(和windows下kprocess、kthread的概念很类似)。

    struct module
    {
        /*
        1. enum module_state state
        enum module_state
        {
            MODULE_STATE_LIVE,    	//模块当前正常使用中(存活状态) 
            MODULE_STATE_COMING,    //模块当前正在被加载
            MODULE_STATE_GOING,    	//模块当前正在被卸载
        };
        load_module函数:完成模块的部分创建工作后,把状态置为 MODULE_STATE_COMING
        sys_init_module函数:完成模块的全部初始化工作后,把模块加入全局的模块列表,
        					调用模块本身的初始化函数),把模块状态置为MODULE_STATE_LIVE
        使用rmmod工具卸载模块时,会调用系统调用delete_module,会把模块的状态置为MODULE_STATE_GOING
        */
        enum module_state state;
    
        /*
        2. struct list_head list
        list是作为一个列表的成员,所有的内核模块都被维护在一个全局链表中,
        链表头是一个全局变量struct module *modules。任何一个新创建的模块,都会被加入到这个链表的头部
        */
        struct list_head list;
        
        /*
        3. char name[MODULE_NAME_LEN]
        name是模块的名字,一般会拿模块文件的文件名作为模块名。它是这个模块的一个标识
        */
        char name[MODULE_NAME_LEN];
    
        struct module_kobject mkobj;	//见下文注释
     
        struct module_param_attrs *param_attrs;
        const char *version;
        const char *srcversion;
        
        /* Exported symbols */
        const struct kernel_symbol *syms;
        unsigned int num_syms;
        const unsigned long *crcs;
    
        /* GPL-only exported symbols. */
        const struct kernel_symbol *gpl_syms;
        unsigned int num_gpl_syms;
        const unsigned long *gpl_crcs;
    
        unsigned int num_exentries;
        const struct exception_table_entry *extable;
    
        int (*init)(void);
        /*
        初始化相关
        */
        void *module_init;
        void *module_core;
        unsigned long init_size, core_size;
        unsigned long init_text_size, core_text_size;
        struct mod_arch_specific arch;
        int unsafe;
        int license_gplok;
    
    #ifdef CONFIG_MODULE_UNLOAD
        struct module_ref ref[NR_CPUS];
        struct list_head modules_which_use_me;
        struct task_struct *waiter;
        void (*exit)(void);
    #endif
    
    #ifdef CONFIG_KALLSYMS
        Elf_Sym *symtab;
        unsigned long num_symtab;
        char *strtab;
        struct module_sect_attrs *sect_attrs;
    #endif
        void *percpu;
        char *args;
    };
    
  • 关于struct module_kobject mkobj

    • 该成员是一个结构体类型,结构体的定义如下:

      struct module_kobject
      {
          struct kobject kobj;
          struct module *mod;	//指向包容它的struct module成员 
      }; 
      
    • module_kobject结构体中的kobject是组成设备模型的基本结构。设备模型是在2.6内核中出现的新的概念,实现对系统的一般性抽象描述。它最初只是被理解为一个简单的引用计数,但现在也有了很多成员,
      它所能处理的任务以及它所支持的代码包括:对象的引用计数;sysfs表述;结构关联;热插拔事件处理。下面是kobject结构的定义:

      struct kobject
      {            
            //k_name和name都是该内核对象的名称,在内核模块的内嵌kobject中,名称即为内核模块的名称 
            const char      *k_name;
            char            name[KOBJ_NAME_LEN];
          
            /*
             *kref是该kobject的引用计数,新创建的kobject被加入到kset时(调用kobject_init),
             *引用计数被加1,然后kobject跟它的parent建立关联时,引用计数被加1,所以一个新创建的
             *kobject,其引用计数总是为2
             */
            struct kref     kref; 
      
            //entry是作为链表的节点,所有同一子系统下的所有相同类型的kobject被链接成一个链表 
            struct list_head    entry; 
      
            //parent指向该kobject所属分层结构中的上一层节点,所有内核模块的parent是module
            struct kobject      *parent;
      
           /*
            * 成员kset就是嵌入相同类型结构的kobject集合。下面是struct kset结构体的定义:
                struct kset 
                {
                    struct subsystem    *subsys;
                    struct kobj_type    *ktype;
                    struct list_head    list;
                    spinlock_t          list_lock;
                    struct kobject      kobj;
                    struct kset_uevent_ops  * uevent_ops;
                };
            */
            struct kset         *kset; 
      
            //ktype则是模块的属性,这些属性都会在kobject的sysfs目录中显示
            struct kobj_type    *ktype;
      
            //dentry则是文件系统相关的一个节点
            struct dentry       *dentry;
      };
      
  • 从struct module结构体可以看出,在内核态,我们如果要引用当前内核模块的链表,可以使用以下三个中的任意一个:

    • struct module->list
    • struct module->mkobj->kobj->entry
    • struct module->mkobj->kobj->kset
  • 拓展链接

    • http://lxr.free-electrons.com/source/include/linux/module.h
    • http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/module.h
    • http://blog.chinaunix.net/uid-9525959-id-2001630.html
    • http://blog.csdn.net/linweig/article/details/5044722

3.3 module_use

/*
 *source/include/linux/module.h
 */

/* modules using other modules: kdb wants to see this. */
struct module_use 
{
    struct list_head source_list;
    struct list_head target_list;
    struct module *source, *target;
};
  • "struct module_use"和"struct module->module_which_use_me"这两个结果共同组合和保证了内核模块中的依赖关系。
  • 如果模块B使用了模块A提供的函数,那么模块A和模块B之间就存在关系,可以从两个方面来看这种关系:
    1. 模块B依赖模块A——除非模块A已经驻留在内核内存,否则模块B无法装载。
    2. 模块B引用模块A——除非模块B已经移除,否则模块A无法从内核移除,在内核中,这种关系称之为"模块B使用模块A"。
  • 对每个使用了模块A中函数的模块B,都会创建一个module_use结构体实例,该实例将被添加到模块A(被依赖的模块)的module实例中的modules_which_use_me链表中,modules_which_use_me指向模块B的module实例。明白了模块间的依赖关系在数据结构上的表现,可以很容易地枚举出所有模块的依赖关系。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leon_George

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值