Linux内核module依赖关系和引用

·

如果模块B使用了模块A提供的函数,那么可以用以下两种方式看待模块A和模块B之间的关系。

  1. 模块B依赖模块A。除非模块A已经驻留在内核内存,否则模块B无法装载。
  2. 模块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);
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注