try_module_get与module_put 的引入与使用与2.6内核下的设备模型密切相关。2.6内核为不同类型的设备定义了struct module *owner 域,用来指向管理此设备的模块。如字符设备的定义:
struct cdev
{
struct kobject kobj;
struct module *owner;
struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
……
};
从设备使用的角度出发,当需要打开、开始使用某个设备时,使用 try_module_get(dev-》owner)去增加管理此设备的 owner模块的使用计数;当关闭、不再使用此设备时,使用module_put(dev-》owner)减少对管理此设备的owner模块的使用计数。这样,当设备在使用时,管理此设备的模块就不能被卸载;只有设备不再使用时模块才能被卸载。
2.6内核下,对于为具体设备写驱动的开发人员而言,基本无需使用 try_module_get与module_put,因为此时开发人员所写的驱动通常为支持某具体设备的owner模块,对此设备owner模块的计数管理由内核里更底层的代码如总线驱动或是此类设备共用的核心模块来实现,从而简化了设备驱动开发。
四、举例说明2.6内核模块使用计数的实现过程
举一个2.6内核下字符设备驱动编写的例子来说明问题。在2.6内核下编写一个设备驱动时,初始化过程中大家都会看到如下的模板:
static struct file_operations simple_remap_ops = {
.owner = THIS_MODULE,
.open = simple_open,
……
};
static void simple_setup_cdev(struct cdev *dev, int minor,