文件操作结构体file_operations的完整定义见博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/144905840
嵌入式驱动编程中结构体file_operations的第一个成员 struct module *owner 通常被赋值为 THIS_MODULE 这是怎么回事儿?
比如下面的代码:
static const struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
};
我们在Linux的源码中(include\linux\export.h)可以查到THIS_MODULE是一个宏定义,具体如下:
#ifdef MODULE
extern struct module __this_module;
#define THIS_MODULE (&__this_module)
#else
#define THIS_MODULE ((struct module *)0)
#endif
把这段代码理解了,基本上就理解了,下面是详细讲解。
在 Linux 内核中,THIS_MODULE 是一个宏,用于指向当前驱动模块的 struct module 实例。它的作用是为模块提供元信息和生命周期管理支持。
THIS_MODULE 的定义解读
#ifdef MODULE
extern struct module __this_module;
#define THIS_MODULE (&__this_module)
#else
#define THIS_MODULE ((struct module *)0)
#endif
-
MODULE宏:MODULE是一个条件编译宏,当编译成模块(.ko文件)时,编译器会定义MODULE。- 如果模块被静态编译进内核(而不是动态加载的模块),
MODULE不会被定义。
-
__this_module:- 如果
MODULE被定义,THIS_MODULE会展开为&__this_module,即当前模块的struct module实例。 __this_module是一个由内核自动生成的全局变量,包含模块的相关信息,如模块名、引用计数等。
- 如果
-
静态内核情况:
- 如果模块被静态编译进内核,
MODULE未定义,此时THIS_MODULE被设置为NULL,因为静态内核中的模块不需要动态管理。
- 如果模块被静态编译进内核,
THIS_MODULE 在驱动中的用途
THIS_MODULE 被赋值给 struct file_operations 的 owner 成员,主要用于模块的引用计数管理:
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
-
模块引用计数:
- 当设备文件被打开时(调用
open函数),内核会增加模块的引用计数,防止模块在使用过程中被卸载。 - 当设备文件被关闭时(调用
release函数),内核会减少引用计数。
- 当设备文件被打开时(调用
-
避免非法卸载:
- 如果模块的引用计数大于 0,
rmmod命令无法卸载该模块,从而防止非法卸载可能导致的系统崩溃。
- 如果模块的引用计数大于 0,
-
动态模块管理:
- 通过
THIS_MODULE,内核可以准确管理模块的生命周期,包括加载、使用和卸载。
- 通过
struct module 的结构
struct module 定义在 <linux/module.h> 中,主要包含以下信息:
struct module {
const char *name; // 模块名称
struct list_head list; // 模块链表
struct module_kobject mkobj; // 模块的 kobject
struct module_param_attrs *param_attrs; // 模块参数的 sysfs 接口
struct list_head source_list; // 源文件相关信息
unsigned int taints; // 模块的 taints 标志
struct mutex mutex; // 模块互斥锁
unsigned long state; // 模块的状态
...
unsigned int refcnt; // 引用计数
...
};
name: 模块名称。refcnt: 引用计数,记录模块被使用的次数。state: 模块状态,例如正在初始化、已加载等。
在动态加载和静态内核中的差异
-
动态加载模块:
- 使用
THIS_MODULE,owner会指向&__this_module,从而实现引用计数管理。
- 使用
-
静态编译进内核:
THIS_MODULE为NULL,因为静态模块不会被卸载,也不需要引用计数管理。
一个示例:模块的引用计数管理
假设一个设备驱动模块如下:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
static int dev_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device opened\n");
return 0;
}
static int dev_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device released\n");
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = dev_open,
.release = dev_release,
};
static int __init mod_init(void) {
int major = register_chrdev(0, "my_device", &fops);
printk(KERN_INFO "Module loaded, major number %d\n", major);
return 0;
}
static void __exit mod_exit(void) {
unregister_chrdev(0, "my_device");
printk(KERN_INFO "Module unloaded\n");
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_LICENSE("GPL");
-
当设备文件
/dev/my_device被打开时:- 内核通过
THIS_MODULE增加引用计数,防止模块被卸载。 - 调用
dev_open函数。
- 内核通过
-
当设备文件被关闭时:
- 内核通过
THIS_MODULE减少引用计数。 - 调用
dev_release函数。
- 内核通过
总结
THIS_MODULE 是一个宏,用于引用当前模块的 struct module 实例【注意:当前模块的 struct module 的实例是由系统自动生成的】,主要作用是管理模块的引用计数,防止模块在使用过程中被非法卸载。它的工作机制依赖于内核的模块管理框架,与设备驱动的生命周期紧密相关。
由于我们编写的驱动程序本质上也是一个模块,所以我们需要用到宏THIS_MODULE 。

871

被折叠的 条评论
为什么被折叠?



