结构体struct module


结构体struct module在内核中代表一个内核模块,通过insmod(实际执行init_module系统调用)把自己编写的内核模块插入内核时,模块便与一个 struct module结构体相关联,并成为内核的一部分。下面是结构体struct module的完整定义,接下来会逐个解释:
   
[cpp]  view plain copy
  1.  struct module  
  2.     {  
  3.         enum module_state state;  
  4.         struct list_head list;  
  5.         char name[MODULE_NAME_LEN];  
  6.    
  7.         struct module_kobject mkobj;  
  8.         struct module_param_attrs *param_attrs;  
  9.         const char *version;  
  10.         const char *srcversion;  
  11.    
  12.         const struct kernel_symbol *syms;  
  13.         unsigned int num_syms;  
  14.         const unsigned long *crcs;  
  15.    
  16.         const struct kernel_symbol *gpl_syms;  
  17.         unsigned int num_gpl_syms;  
  18.         const unsigned long *gpl_crcs;  
  19.    
  20.         unsigned int num_exentries;  
  21.         const struct exception_table_entry *extable;  
  22.    
  23.         int (*init)(void);  
  24.         void *module_init;  
  25.         void *module_core;  
  26.         unsigned long init_size, core_size;  
  27.         unsigned long init_text_size, core_text_size;  
  28.         struct mod_arch_specific arch;  
  29.         int unsafe;  
  30.         int license_gplok;  
  31.    
  32. #ifdef CONFIG_MODULE_UNLOAD  
  33.         struct module_ref ref[NR_CPUS];  
  34.         struct list_head modules_which_use_me;  
  35.         struct task_struct *waiter;  
  36.         void (*exit)(void);  
  37. #endif  
  38.    
  39. #ifdef CONFIG_KALLSYMS  
  40.         Elf_Sym *symtab;  
  41.         unsigned long num_symtab;  
  42.         char *strtab;  
  43.         struct module_sect_attrs *sect_attrs;  
  44. #endif  
  45.         void *percpu;  
  46.         char *args;  
  47.     };  


    我们插入一个内核模块,一般会使用工具insmod,该工具实际上调用了系统调用init_module,在该系统调用函数中,首先调用 load_module,把用户空间传入的整个内核模块文件创建成一个内核模块,返回一个struct module结构体。内核中便以这个结构体代表这个内核模块。
    state是模块当前的状态。它是一个枚举型变量,可取的值为:MODULE_STATE_LIVE,MODULE_STATE_COMING,MODULE_STATE_GOING。
[cpp]  view plain copy
  1. enum module_state  
  2. {  
  3.     MODULE_STATE_LIVE,  //模块当前正常使用中(存活状态) 0  
  4.     MODULE_STATE_COMING, //模块当前正在被加载  1   
  5.     MODULE_STATE_GOING,  //模块当前正在被卸载  2  
  6. };  

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结构,试试下面的模块:
[cpp]  view plain copy
  1. #include <linux/module.h>  
  2.     MODULE_LICENSE("GPL");   
  3.     MODULE_AUTHOR("Jack Chen");/*作者*/  
  4.     MODULE_DESCRIPTION("HELLO");  
  5.     MODULE_VERSION("1.0");//版本号  
  6.     static int hello_init(void)  
  7.     {  
  8.         unsigned int cpu = get_cpu();  
  9.         struct module *mod;  
  10.         printk(KERN_ALERT "this module: %p==%p/n", &__this_module, THIS_MODULE );  
  11.         printk(KERN_ALERT "module state: %d/n", THIS_MODULE->state );  
  12.         printk(KERN_ALERT "module name: %s/n", THIS_MODULE->name );  
  13.               printk(KERN_ALERT"module version:%s\n",THIS_MODULE->version);    
  14.         list_for_each_entry(mod, *(&THIS_MODULE->list.prev), list )  
  15.                 printk(KERN_ALERT "module name: %s/n", mod->name );  
  16.         return 0;  
  17.     }  
  18.    
  19.     static void hello_exit(void)  
  20.     {  
  21.         printk(KERN_ALERT "module state: %d/n", THIS_MODULE->state );  
  22.         printk("find_module bye...\n");  
  23.     }  
  24.    
  25.     module_init(hello_init);  
  26.     module_exit(hello_exit);  
  27.    


owner是一个struct module *类型的结构体指针,现在告诉你的是每个struct module结构体在内核里都代表了一个内核模块,就像十七大里的每个代表都代表了一批人,至于代表了什么人,选他们的人才知道,同样,每个struct module结构体代表了什么模块,对它进行初始化的模块才知道。当然,初始化这个结构不是写驱动的人该做的事,是在刚才略过的那个从insmod或 modprobe到你驱动的xxx_init函数的曲折过程中做的事。insmod命令执行后,会调用kernel/module.c里的一个系统调用init_module,它会调用load_module函数,将用户空间传入的整个内核模块文件创建成一个内核模块,并返回一个struct module结构体,从此,内核中便以这个结构体代表这个内核模块。

再看看THIS_MODULE宏是什么意思

它在include/linux/module.h里的定义是
85 #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() 也是内联的,并不会增加调用的开销。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Linux 内核中,`struct file_operations` 是一个非常重要的结构,用于定义文件操作的函数指针。下面是各个成员的具定义: 1. `struct module *owner`:指向拥有这个结构的模块的指针。 2. `loff_t (*llseek) (struct file *, loff_t, int)`:定义了文件定位的函数指针,用于在文件中寻找一个指定的位置。这个函数的第一个参数是指向文件对象的指针,第二个参数是要定位的文件偏移量,第三个参数是定位的方式。 3. `ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)`:定义了文件读取的函数指针,用于从文件中读取数据。这个函数的第一个参数是指向文件对象的指针,第二个参数是指向用户空间缓冲区的指针,第三个参数是要读取的字节数,第四个参数是读取的起始位置。 4. `ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)`:定义了文件写入的函数指针,用于向文件中写入数据。这个函数的第一个参数是指向文件对象的指针,第二个参数是指向用户空间缓冲区的指针,第三个参数是要写入的字节数,第四个参数是写入的起始位置。 5. `ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t)`:定义了异步文件读取的函数指针,用于从文件中异步读取数据。这个函数的第一个参数是指向异步 I/O 控制块的指针,第二个参数是指向一个 iovec 结构数组的指针,每个结构描述了一个缓冲区,第三个参数是读取的字节数,第四个参数是读取的起始位置。 6. `ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t)`:定义了异步文件写入的函数指针,用于向文件中异步写入数据。这个函数的参数和 `aio_read` 相同。 7. `int (*readdir) (struct file *, void *, filldir_t)`:定义了目录读取的函数指针,用于读取目录中的文件列表。这个函数的第一个参数是指向目录文件对象的指针,第二个参数是指向一个目录项结构的指针,第三个参数是一个函数指针,用于填充目录项结构。 8. `unsigned int (*poll) (struct file *, struct poll_table_struct *)`:定义了文件的 poll 函数指针,用于检查文件描述符是否可以进行读取或写入操作。这个函数的第一个参数是指向文件对象的指针,第二个参数是指向 poll_table_struct 结构的指针,用于注册等待事件。 9. `long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long)`:定义了文件的非阻塞 I/O 控制函数指针,用于控制和查询设备的状态。这个函数的第一个参数是指向文件对象的指针,第二个参数是 ioctl 命令,第三个参数是 ioctl 参数。 10. `long (*compat_ioctl) (struct file *, unsigned int, unsigned long)`:定义了文件的兼容性非阻塞 I/O 控制函数指针,用于支持旧版本的 ioctl 命令。这个函数的参数和 `unlocked_ioctl` 相同。 11. `int (*mmap) (struct file *, struct vm_area_struct *)`:定义了文件的内存映射函数指针,用于将文件映射到进程的虚拟内存空间中。这个函数的第一个参数是指向文件对象的指针,第二个参数是指向 vm_area_struct 结构的指针,用于描述映射的内存区域。 12. `int (*open) (struct inode *, struct file *)`:定义了文件的打开函数指针,用于打开文件并返回文件对象。这个函数的第一个参数是指向 inode 结构的指针,第二个参数是指向文件对象的指针。 13. `int (*flush) (struct file *, fl_owner_t id)`:定义了文件的刷新函数指针,用于刷新文件的缓存数据。这个函数的第一个参数是指向文件对象的指针,第二个参数是一个所有者标识符。 14. `int (*release) (struct inode *, struct file *)`:定义了文件的释放函数指针,用于释放文件对象和相关资源。这个函数的第一个参数是指向 inode 结构的指针,第二个参数是指向文件对象的指针。 总之,`struct file_operations` 中的各个成员定义了文件操作的各种函数指针,这些函数指针实现了文件的读取、写入、定位、异步 I/O、目录读取、poll、ioctl、内存映射、打开、刷新和释放等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值