【摘要】本文详细解释了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 stateenum module_state{MODULE_STATE_LIVE, //模块当前正常使用中(存活状态) MODULE_STATE_COMING, //模块当前正在被加载MODULE_STATE_GOING, //模块当前正在被卸载};load_module函数:完成模块的部分创建工作后,把状态置为 MODULE_STATE_COMINGsys_init_module函数:完成模块的全部初始化工作后,把模块加入全局的模块列表,调用模块本身的初始化函数),把模块状态置为MODULE_STATE_LIVE使用rmmod工具卸载模块时,会调用系统调用delete_module,会把模块的状态置为MODULE_STATE_GOING*/enum module_state state;/*2. struct list_head listlist是作为一个列表的成员,所有的内核模块都被维护在一个全局链表中,链表头是一个全局变量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_UNLOADstruct module_ref ref[NR_CPUS];struct list_head modules_which_use_me;struct task_struct *waiter;void (*exit)(void); #endif#ifdef CONFIG_KALLSYMSElf_Sym *symtab;unsigned long num_symtab;char *strtab;struct module_sect_attrs *sect_attrs; #endifvoid *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是modulestruct 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实例。明白了模块间的依赖关系在数据结构上的表现,可以很容易地枚举出所有模块的依赖关系。