【摘要】本文详细解释了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之间就存在关系,可以从两个方面来看这种关系:
- 模块B依赖模块A——除非模块A已经驻留在内核内存,否则模块B无法装载。
- 模块B引用模块A——除非模块B已经移除,否则模块A无法从内核移除,在内核中,这种关系称之为"模块B使用模块A"。
- 对每个使用了模块A中函数的模块B,都会创建一个module_use结构体实例,该实例将被添加到模块A(被依赖的模块)的module实例中的modules_which_use_me链表中,modules_which_use_me指向模块B的module实例。明白了模块间的依赖关系在数据结构上的表现,可以很容易地枚举出所有模块的依赖关系。