如果模块B使用了模块A提供的函数,那么可以用以下两种方式看待模块A和模块B之间的关系。
- 模块B依赖模块A。除非模块A已经驻留在内核内存,否则模块B无法装载。
- 模块B引用模块A。除非模块B已经从内核移除,否则模块A无法从内核移除。更准确的说法是,所有引用模块A的模块都已经从内核移除,才能将模块A从内核移除。
内核使用一种数据结构管理这种依赖关系。
//kernel 2.6.34-
//kernel/modules.c
struct module_use
{
struct list_head list;
struct module *module_which_uses;
};
//kernel 2.6.35+
struct module_use {
struct list_head source_list;
struct list_head target_list;
struct module *source, *target;
};
依赖关系的网络通过module_use和module数据结构的modules_which_use_me成员共同建立起来。对每个使用了模块A中函数的模块B,都会创建一个module_use的新实例。该实例将添加到模块A的module实例中的modules_which_use_me链表。module_which_uses指向模块B的module实例。根据这些信息,内核很容易计算出使用特定模块的其他内核模块。
内核提供了already_uses函数用于判断模块A是否需要模块B。另一个函数add_module_usage用于建立模块A和模块B的关系,模块A需要模块B才能正确运行。
/* Does a already use b? */
static int already_uses(struct module *a, struct module *b)
{
struct module_use *use;
list_for_each_entry(use, &b->source_list, source_list) {
if (use->source == a) {
pr_debug("%s uses %s!\n", a->name, b->name);
return 1;
}
}
pr_debug("%s does not use %s!\n", a->name, b->name);
return 0;
}
/*
* Module a uses b
* - we add 'a' as a "source", 'b' as a "target" of module use
* - the module_use is added to the list of 'b' sources (so
* 'b' can walk the list to see who sourced them), and of 'a'
* targets (so 'a' can see what modules it targets).
*/
static int add_module_usage(struct module *a, struct module *b)
{
struct module_use *use;
pr_debug("Allocating new usage for %s.\n", a->name);
use = kmalloc(sizeof(*use), GFP_ATOMIC);
if (!use)
return -ENOMEM;
use->source = a;
use->target = b;
list_add(&use->source_list, &b->source_list);
list_add(&use->target_list, &a->target_list);
return 0;
}
/* Module a uses b: caller needs module_mutex() */
int ref_module(struct module *a, struct module *b)
{
int err;
if (b == NULL || already_uses(a, b))
return 0;
/* If module isn't available, we fail. */
err = strong_try_module_get(b);
if (err)
return err;
err = add_module_usage(a, b);
if (err) {
module_put(b);
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(ref_module);
/* Clear the unload stuff of the module. */
static void module_unload_free(struct module *mod)
{
struct module_use *use, *tmp;
mutex_lock(&module_mutex);
list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
struct module *i = use->target;
pr_debug("%s unusing %s\n", mod->name, i->name);
module_put(i);
list_del(&use->source_list);
list_del(&use->target_list);
kfree(use);
}
mutex_unlock(&module_mutex);
}
发表回复