结构体struct
module在内核中代表一个内核模块,通过insmod(实际执行init_module系统调用)把自己编写的内核模块插入内核时,模块便与一个
struct module结构体相关联,并成为内核的一部分。下面是结构体struct module的完整定义,接下来会逐个解释:
struct module
{
enum module_state state;
struct list_head list;
char name[MODULE_NAME_LEN];
struct module_kobject mkobj;
struct module_param_attrs *param_attrs;
const char *version;
const char *srcversion;
const struct kernel_symbol *syms;
unsigned int num_syms;
const unsigned long *crcs;
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;
};
我们插入一个内核模块,一般会使用工具insmod,该工具实际上调用了系统调用init_module,在该系统调用函数中,首先调用
load_module,把用户空间传入的整个内核模块文件创建成一个内核模块,返回一个struct
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。这是模块内部维护的一个状态。
list是作为一个列表的成员,所有的内核模块都被维护在一个全局链表中,链表头是一个全局变量struct module *modules。任何一个新创建的模块,都会被加入到这个链表的头部,通过modules->next即可引用到。
name是模块的名字,一般会拿模块文件的文件名作为模块名。它是这个模块的一个标识。
另外,还要介绍一下宏THIS_MODULE,它的定义如下是#define THIS_MODULE
(&__this_module),__this_module是一个struct
module变量,代表当前模块,跟current有几分相似。可以通过THIS_MODULE宏来引用模块的struct
module结构,试试下面的模块:
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
struct module *mod;
printk(KERN_ALERT "this module: %p==%p\n", &__this_module, THIS_MODULE );
printk(KERN_ALERT "module state: %d\n", THIS_MODULE->state );
printk(KERN_ALERT "module name: %s\n", THIS_MODULE->name );
list_for_each_entry(mod, *(&THIS_MODULE->list.prev), list )
printk(KERN_ALERT "module name: %s\n", mod->name );
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "module state: %d\n", THIS_MODULE->state );
}
module_init(hello_init);
module_exit(hello_exit);
接下来介绍struct module结构体的成员struct module_kobject mkobj,该成员是一个结构体类型,结构体的定义如下:
struct module_kobject{
struct kobject kobj;
struct module *mod;
};
mod指向包容它的struct module成员,kobj是一个struct
kobjecy结构体,kobject是组成设备模型的基本结构。设备模型是在2.6内核中出现的新的概念,因为随着拓扑结构越来越复杂,以及要支持诸如
电源管理等新特性的要求,向新版本的内核明确提出了这样的要求:需要有一个对系统的一般性抽象描述。设备模型提供了这样的抽象。
设备模型是一个较为复杂的概念,首先来理解kobject。kobject最初只是被理解为一个简单的引用计数,但现在也有了很多成员,它所能处理的任务
以及它所支持的代码包括:对象的引用计数;sysfs表述;结构关联;热插拔事件处理。下面是kobject结构的定义:
struct kobject {
const char *k_name;
char name[KOBJ_NAME_LEN];
struct kref kref;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct dentry *dentry;
};
k_name和name都是该内核对象的名称,在内核模块的内嵌kobject中,名称即为内核模块的名称。
kref是该kobject的引用计数,新创建的kobject被加入到kset时(调用kobject_init),引用计数被加1,然后kobject跟它的parent建立关联时,引用计数被加1,所以一个新创建的kobject,其引用计数总是为2。
entry是作为链表的节点,所有同一子系统下的所有相同类型的kobject被链接成一个链表组织在一起,成员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;
};
成员list就是kobject集合的链表。subsys表示子系统,所有的内核模块都属于module子系统,具体的sysfs下的表现形式是所有的module都在/sys/module目录下有一个子目录。
parent指向该kobject所属分层结构中的上一层节点,所有内核模块的parent是module。
ktype则是模块的属性,这些属性都会在kobject的sysfs目录中显示。
dentry则是文件系统相关的一个节点,这里不作介绍。
最后还要介绍的是关于子系统,每一个子系统在/sys/文件系统中对应一个顶层目录,内核模块子系统对应的目录是module,在内核中用全局变量module_subsys表示。
试试下面的代码:
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello2_init(void)
{
struct kobject *kobj;
struct kset* top_kset = THIS_MODULE->mkobj.kobj.kset;
printk(KERN_ALERT "top_kset: %p\n", top_kset);
list_for_each_entry(kobj, &(top_kset->list), entry )
printk(KERN_ALERT "kobj name: %s, parent: %p, %s\n",
kobj->k_name, kobj->parent, kobj->parent->k_name );
printk(KERN_ALERT "this kobject name: %s, %s\n",
THIS_MODULE->mkobj.kobj.k_name, THIS_MODULE->mkobj.kobj.name );
printk(KERN_ALERT "this kobject ref: %d\n",
atomic_read(&THIS_MODULE->mkobj.kobj.kref.refcount) );
return 0;
}
static void hello2_exit(void)
{
printk(KERN_ALERT "module state: %d\n", THIS_MODULE->state );
}
module_init(hello2_init);
module_exit(hello2_exit);
阅读(798) | 评论(0) | 转发(0) |