Chinaunix首页 | 论坛 | 博客
  • 博客访问: 377125
  • 博文数量: 82
  • 博客积分: 1104
  • 博客等级: 少尉
  • 技术积分: 926
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-16 15:14
文章分类
文章存档

2012年(82)

分类: LINUX

2012-05-17 16:58:47

    结构体struct module在内核中代表一个内核模块,通过insmod(实际执行init_module系统调用)把自己编写的内核模块插入内核时,模块便与一个 struct module结构体相关联,并成为内核的一部分。下面是结构体struct module的完整定义,接下来会逐个解释:

点击(此处)折叠或打开

  1. struct module
  2.     {
  3.         enum module_state state;
  4.         struct list_head list;
  5.         char name[MODULE_NAME_LEN];

  6.         struct module_kobject mkobj;
  7.         struct module_param_attrs *param_attrs;
  8.         const char *version;
  9.         const char *srcversion;

  10.         const struct kernel_symbol *syms;
  11.         unsigned int num_syms;
  12.         const unsigned long *crcs;

  13.         const struct kernel_symbol *gpl_syms;
  14.         unsigned int num_gpl_syms;
  15.         const unsigned long *gpl_crcs;

  16.         unsigned int num_exentries;
  17.         const struct exception_table_entry *extable;

  18.         int (*init)(void);
  19.         void *module_init;
  20.         void *module_core;
  21.         unsigned long init_size, core_size;
  22.         unsigned long init_text_size, core_text_size;
  23.         struct mod_arch_specific arch;
  24.         int unsafe;
  25.         int license_gplok;

  26. #ifdef CONFIG_MODULE_UNLOAD
  27.         struct module_ref ref[NR_CPUS];
  28.         struct list_head modules_which_use_me;
  29.         struct task_struct *waiter;
  30.         void (*exit)(void);
  31. #endif

  32. #ifdef CONFIG_KALLSYMS
  33.         Elf_Sym *symtab;
  34.         unsigned long num_symtab;
  35.         char *strtab;
  36.         struct module_sect_attrs *sect_attrs;
  37. #endif
  38.         void *percpu;
  39.         char *args;
  40.     };
    我们插入一个内核模块,一般会使用工具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结构,试试下面的模块:

点击(此处)折叠或打开

  1. #include <linux/module.h>

  2.     MODULE_LICENSE("Dual BSD/GPL");

  3.     static int hello_init(void)
  4.     {
  5.         unsigned int cpu = get_cpu();
  6.         struct module *mod;
  7.         printk(KERN_ALERT "this module: %p==%p/n", &__this_module, THIS_MODULE );
  8.         printk(KERN_ALERT "module state: %d/n", THIS_MODULE->state );
  9.         printk(KERN_ALERT "module name: %s/n", THIS_MODULE->name );
  10.         list_for_each_entry(mod, *(&THIS_MODULE->list.prev), list )
  11.                 printk(KERN_ALERT "module name: %s/n", mod->name );
  12.         return 0;
  13.     }

  14.     static void hello_exit(void)
  15.     {
  16.         printk(KERN_ALERT "module state: %d/n", THIS_MODULE->state );
  17.     }

  18.     module_init(hello_init);
  19.     module_exit(hello_exit);
 测试输出:

点击(此处)折叠或打开

  1. [28684.859780] this module: f9b0b120==f9b0b120
  2. [28684.859782] module state: 1
  3. [28684.859783] module name: test
  4. [28684.859784] module name: test
  5. [28684.859785] module name: scull
  6. [28684.859786] module name: vboxnetadp
  7. [28684.859786] module name: vboxnetflt
  8. [28684.859787] module name: vboxdrv
    owner是一个struct module *类型的结构体指针,现在告诉你的是每个struct module结构体在内核里都代表了一个内核模块,就像十七大里的每个代表都代表了一批人,至于代表了什么人,选他们的人才知道,同样,每个struct module结构体代表了什么模块,对它进行初始化的模块才知道。当然,初始化这个结构不是写驱动的人该做的事,是在刚才略过的那个从insmod或 modprobe到你驱动的xxx_init函数的曲折过程中做的事。insmod命令执行后,会调用kernel/module.c里的一个系统调用 sys_init_module,它会调用load_module函数,将用户空间传入的整个内核模块文件创建成一个内核模块,并返回一个struct module结构体,从此,内核中便以这个结构体代表这个内核模块。
     再看看THIS_MODULE宏是什么意思,它在include/linux/module.h里的定义是
     #define THIS_MODULE (&__this_module)
     是 一个struct module变量,代表当前模块,与那个著名的current有几分相似,可以通过THIS_MODULE宏来引用模块的struct module结构,比如使用THIS_MODULE->state可以获得当前模块的状态。现在你应该明白为啥在那个岁月里,你需要毫不犹豫毫不迟 疑的将struct usb_driver结构里的owner设置为THIS_MODULE了吧,这个owner指针指向的就是你的模块自己。那现在owner咋就说没就没了 那?这个说来可就话长了,咱就长话短说吧。不知道那个时候你有没有忘记过初始化owner,反正是很多人都会忘记,大家都把注意力集中到probe、 disconnect等等需要动脑子的角色上面了,这个不需要动脑子,只需要花个几秒钟指定一下的owner反倒常常被忽视,这个就是容易得到的往往不去 珍惜,不容易得到的往往日日思量着去争取。于是在2006年的春节前夕,在咱们都无心工作无心学习等着过春节的时候,Greg坚守一线,去掉了 owner,于是千千万万个写usb驱动的人再也不用去时刻谨记初始化owner了。咱们是不用设置owner了,可core里不能不设置,struct usb_driver结构里不是没有owner了么,可它里面嵌的那个struct device_driver结构里还有啊,设置了它就可以了。于是Greg同时又增加了usb_register_driver()这么一 层,usb_register()可以通过将参数指定为THIS_MODULE去调用它,所有的事情都挪到它里面去做。反正usb_register() 也是内联的,并不会增加调用的开销。
阅读(1467) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~