最近再看一些涉及内核模块的常用API,学习的过程记录下来。
函数find_module( )用来获得一个指向模块的指针。它是根据给定的模块名字查找模块链表,如果找到一个与给定的模块名字相匹配的模块,则返回该模块的指针。由于一个模块的名字是唯一的且不允许有重名的模块,因此基于模块名查找模块是可行的。
// linux-3.10/include/linux/module.h
enum module_state {
MODULE_STATE_LIVE, /* Normal state. */
MODULE_STATE_COMING, /* Full formed, running module_init. */
MODULE_STATE_GOING, /* Going away. */
MODULE_STATE_UNFORMED, /* Still setting it up. */
};
MODULE_STATE_LIVE表示模块在正常运行中,已经完成初始化任务之后。
MODULE_STATE_COMING表示在加载模块期间。
MODULE_STATE_GOING表示模块在卸载期间。
// linux-3.10/kernel/module.c
/* Search for module by name: must hold module_mutex. */
static struct module *find_module_all(const char *name,
bool even_unformed)
{
struct module *mod;
//遍历模块双向链表
list_for_each_entry(mod, &modules, list) {
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
continue;
if (strcmp(mod->name, name) == 0)
return mod;
}
return NULL;
}
struct module *find_module(const char *name)
{
return find_module_all(name, false);
}
EXPORT_SYMBOL_GPL(find_module);
// linux-3.10/include/linux/list.h
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
find_module实现逻辑很简单,遍历内核全局双向链表modules,比较链表上模块的名字与传入的参数名字是否相等,相等则表示找到。
注意调用该函数时要加锁访问:
/*
* Mutex protects:
* 1) List of modules (also safely readable with preempt_disable),
* 2) module_use links,
* 3) module_addr_min/module_addr_max.
* (delete uses stop_machine/add uses RCU list operations). */
DEFINE_MUTEX(module_mutex);
EXPORT_SYMBOL_GPL(module_mutex);
static LIST_HEAD(modules);
mutex_lock(&module_mutex);
find_module(mod_name);
mutex_unlock(&module_mutex);
# include
# include
# include
#define MODULE_NAME "nf_conntrack"
static int __init lkm_init(void)
{
struct module *mod;
mutex_lock(&module_mutex);
mod = find_module(MODULE_NAME);
mutex_unlock(&module_mutex);
if(mod){
printk("module name = %s\n", mod->name);
printk("module core_size = %d\n", mod->core_size);
printk("module refcount = %ld\n", module_refcount(mod));
}
return -1;
}
module_init(lkm_init);
MODULE_LICENSE("GPL");
通过字符串"nf_conntrack"找到nf_conntrack模块:

Linux 3.10.0