Linux 模块加载学习笔记

Linux 模块加载学习笔记

Linux 3.10

sys_init_module 加载模块的系统调用

SYSCALL_DEFINE3(init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
{
	int err;
	struct load_info info = { };
	//全局变量modules_disabled决定了是否允许加载模块啊
	err = may_init_module();//检查是否具有加载模块的权限,且是否全局禁止加载模块
	if (err)
		return err;

	pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
	       umod, len, uargs);

	err = copy_module_from_user(umod, len, &info);//从用户层复制模块到内核层,并进行SElinux检查
	if (err)
		return err;
	return load_module(&info, uargs, 0);//真正的开始加载模块
}

load_module 加载,初始化模块

static int load_module(struct load_info *info, const char __user *uargs,
		       int flags)
{
	struct module *mod;
	long err;

	err = module_sig_check(info);//对内核模块签名进行检查。
	if (err)
		goto free_copy;

	err = elf_header_check(info);//检查是否为合法ELF文件
	if (err)
		goto free_copy;

	/* Figure out module layout, and allocate all the memory. */
	//使用module_alloc分配内存,即__vmalloc_node_range,分配内存的范围为VMALLOC_START-VMALLOC_END。init节在初始化完后会被释放。
	//mod = (void *)info->sechdrs[info->index.mod].sh_addr;mod对象在core的一个节中,节名为.gnu.linkonce.this_module
	//info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
	mod = layout_and_allocate(info, flags);//从新布局内核模块的地址空间,core和init。
	if (IS_ERR(mod)) {
		err = PTR_ERR(mod);
		goto free_copy;
	}

	/* Reserve our place in the list. */
	//检查是否有同名模块已加载或正在加载,如果没有同名模块,则将当前模块加到内核的模块列表modules中
	err = add_unformed_module(mod); 
	if (err)
		goto free_module;

#ifdef CONFIG_MODULE_SIG
	mod->sig_ok = info->sig_ok;
	if (!mod->sig_ok) {//模块签名失败但放过的情况
		printk_once(KERN_NOTICE
			    "%s: module verification failed: signature and/or"
			    " required key missing - tainting kernel\n",
			    mod->name);
		add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_STILL_OK);
	}
#endif

	/* Now module is in final location, initialize linked lists, etc. */
	err = module_unload_init(mod); //根据CONFIG_MODULE_UNLOAD是否定义,是否允许卸载模块
	if (err)
		goto unlink_mod;

	/* Now we've got everything in the final locations, we can
	 * find optional sections. */
	find_module_sections(mod, info);

	err = check_module_license_and_versions(mod);
	if (err)
		goto free_unload;

	/* Set up MODINFO_ATTR fields */
	setup_modinfo(mod, info); //初始化sysfs文件系统下模块的attr文件,由modinfo_attrs定义

	/* Fix up syms, so that st_value is a pointer to location. */
	err = simplify_symbols(mod, info); //模块中的未定义符号的决议(和已定义符号的地址修正)
	if (err < 0)
		goto free_modinfo;

	err = apply_relocations(mod, info); //静态链接的重定位(使用的是静态链接重定位表)
	if (err < 0)
		goto free_modinfo;

	err = post_relocation(mod, info);
	if (err < 0)
		goto free_modinfo;

	flush_module_icache(mod);

	/* Now copy in args */
	mod->args = strndup_user(uargs, ~0UL >> 1); //复制模块参数到内核空间
	if (IS_ERR(mod->args)) {
		err = PTR_ERR(mod->args);
		goto free_arch_cleanup;
	}

	dynamic_debug_setup(info->debug, info->num_debug);

	/* Finally it's fully formed, ready to start executing. */
	err = complete_formation(mod, info); //导出符号检查与RONX保护
	if (err)
		goto ddebug_cleanup;

	/* Module is ready to execute: parsing args may do that. */
	//解析模块参数,其中args是insmod传入的实参,而kp则是模块的实参类型,记录在模块的段__param中
	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
			 -32768, 32767, &ddebug_dyndbg_module_param_cb);
	if (err < 0)
		goto bug_cleanup;

	/* Link in to syfs. */
	//初始化sysfs文件系统部分,连接到sysfs文件系统书上,创建相关的节点
	err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);  
	if (err < 0)
		goto bug_cleanup;

	/* Get rid of temporary copy. */
	free_copy(info);

	/* Done! */
	trace_module_load(mod);

	return do_init_module(mod); //初始化内核模块

 bug_cleanup:
	/* module_bug_cleanup needs module_mutex protection */
	mutex_lock(&module_mutex);
	module_bug_cleanup(mod);
	mutex_unlock(&module_mutex);
 ddebug_cleanup:
	dynamic_debug_remove(info->debug);
	synchronize_sched();
	kfree(mod->args);
 free_arch_cleanup:
	module_arch_cleanup(mod);
 free_modinfo:
	free_modinfo(mod);
 free_unload:
	module_unload_free(mod);
 unlink_mod:
	mutex_lock(&module_mutex);
	/* Unlink carefully: kallsyms could be walking list. */
	list_del_rcu(&mod->list);
	wake_up_all(&module_wq);
	mutex_unlock(&module_mutex);
 free_module:
	module_deallocate(mod, info);
 free_copy:
	free_copy(info);
	return err;
}

do_init_module 初始化加载的模块

/* This is where the real work happens */
static int do_init_module(struct module *mod)
{
	int ret = 0;

	/*
	 * We want to find out whether @mod uses async during init.  Clear
	 * PF_USED_ASYNC.  async_schedule*() will set it.
	 */
	current->flags &= ~PF_USED_ASYNC;

	blocking_notifier_call_chain(&module_notify_list,
			MODULE_STATE_COMING, mod);  // 通知模块通知链,模块加载

	/* Set RO and NX regions for core */
	set_section_ro_nx(mod->module_core,
				mod->core_text_size,
				mod->core_ro_size,
				mod->core_size);

	/* Set RO and NX regions for init */
	set_section_ro_nx(mod->module_init,
				mod->init_text_size,
				mod->init_ro_size,
				mod->init_size);

	do_mod_ctors(mod);
	/* Start the module */
	if (mod->init != NULL)
		ret = do_one_initcall(mod->init);  //调用模块的初始化函数
	if (ret < 0) {		//初始化函数失败
		/* Init routine failed: abort.  Try to protect us from
                   buggy refcounters. */
		mod->state = MODULE_STATE_GOING;
		synchronize_sched();
		module_put(mod);
		blocking_notifier_call_chain(&module_notify_list,
					     MODULE_STATE_GOING, mod); //通知模块通知链,模块卸载
		free_module(mod);
		wake_up_all(&module_wq);
		return ret;
	}
	if (ret > 0) {
		printk(KERN_WARNING
"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
"%s: loading module anyway...\n",
		       __func__, mod->name, ret,
		       __func__);
		dump_stack();
	}

	/* Now it's a first class citizen! */
	mod->state = MODULE_STATE_LIVE;
	blocking_notifier_call_chain(&module_notify_list,
				     MODULE_STATE_LIVE, mod); 通知模块通知链,模块运行

	/*
	 * We need to finish all async code before the module init sequence
	 * is done.  This has potential to deadlock.  For example, a newly
	 * detected block device can trigger request_module() of the
	 * default iosched from async probing task.  Once userland helper
	 * reaches here, async_synchronize_full() will wait on the async
	 * task waiting on request_module() and deadlock.
	 *
	 * This deadlock is avoided by perfomring async_synchronize_full()
	 * iff module init queued any async jobs.  This isn't a full
	 * solution as it will deadlock the same if module loading from
	 * async jobs nests more than once; however, due to the various
	 * constraints, this hack seems to be the best option for now.
	 * Please refer to the following thread for details.
	 *
	 * http://thread.gmane.org/gmane.linux.kernel/1420814
	 */
	if (current->flags & PF_USED_ASYNC)
		async_synchronize_full();

	mutex_lock(&module_mutex);
	/* Drop initial reference. */
	module_put(mod);
	trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
	mod->num_symtab = mod->core_num_syms;
	mod->symtab = mod->core_symtab;
	mod->strtab = mod->core_strtab;
#endif
	unset_module_init_ro_nx(mod);
	module_free(mod, mod->module_init); //  释放模块的init节
	mod->module_init = NULL;
	mod->init_size = 0;
	mod->init_ro_size = 0;
	mod->init_text_size = 0;
	mutex_unlock(&module_mutex);
	wake_up_all(&module_wq);

	return 0;
}

mod_sysfs_setup 初始化模块的sysfs部分

static int mod_sysfs_setup(struct module *mod,
			   const struct load_info *info,
			   struct kernel_param *kparam,
			   unsigned int num_params)
{
	int err;
	//将模块添加到sysfs树上,初始化/sys/module/[mod->name]节点,所属kset为module_kset,ktype为module_ktype
	err = mod_sysfs_init(mod);
	if (err)
		goto out;

	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
	if (!mod->holders_dir) {
		err = -ENOMEM;
		goto out_unreg;
	}
	//在/sys/module/[mod->name]/parameters/目录下添加模块参数文件
	err = module_param_sysfs_setup(mod, kparam, num_params);
	if (err)
		goto out_unreg_holders;
	//添加modinfo_attrs里定义的文件,
	//uevent,version,srcversion,initstate,coresize,initsize,taint
	err = module_add_modinfo_attrs(mod);
	if (err)
		goto out_unreg_param;
	//在该模块所依赖的模块的holders目录下添加指向该模块的软连接
	add_usage_links(mod);
	//通过sysfs_create_group创建各节区的属性文件
	add_sect_attrs(mod, info);
	//在notes目录下通过sysfs_create_bin_file创建SHT_NOTE类型节的文件
	// /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
	add_notes_attrs(mod, info);
	//产生一个add 事件
	kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
	return 0;

out_unreg_param:
	module_param_sysfs_remove(mod);
out_unreg_holders:
	kobject_put(mod->holders_dir);
out_unreg:
	kobject_put(&mod->mkobj.kobj);
out:
	return err;
}

static struct module_attribute *modinfo_attrs[] = {
	&module_uevent,
	&modinfo_version,
	&modinfo_srcversion,
	&modinfo_initstate,
	&modinfo_coresize,
	&modinfo_initsize,
	&modinfo_taint,
#ifdef CONFIG_MODULE_UNLOAD
	&modinfo_refcnt,
#endif
	NULL,
};
//以modinfo_initstate为例
//文件名为initstate,访问权限为0444,show函数为show_initstate,store函数为空
static struct module_attribute modinfo_initstate =
	__ATTR(initstate, 0444, show_initstate, NULL);

static ssize_t show_initstate(struct module_attribute *mattr,
			      struct module_kobject *mk, char *buffer)
{
	const char *state = "unknown";

	switch (mk->mod->state) {
	case MODULE_STATE_LIVE:
		state = "live";
		break;
	case MODULE_STATE_COMING:
		state = "coming";
		break;
	case MODULE_STATE_GOING:
		state = "going";
		break;
	default:
		BUG();
	}
	return sprintf(buffer, "%s\n", state);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极光1234

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值