五,源码分析
1,应用层
busybox中的insmod源码:
if ((fd = open(filename, O_RDONLY, 0)) < 0) {
bb_perror_msg_and_die("cannot open module `%s'", filename);
}
fstat(fd, &st);
len = st.st_size;
map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
bb_perror_msg_and_die("cannot mmap `%s'", filename);
}
ret = syscall(__NR_init_module, map, len, options);
if (ret != 0) {
bb_perror_msg_and_die("cannot insert `%s': %s (%li)",
filename, moderror(errno), ret);
}
上面的代码其功能就是将.ko映射到内存,以供sys_init_module使用。
2,内核层
syscall(__NR_init_module, map, len, options)会调用sys_init_module函数
/kernel/module.c中:
asmlinkage long
sys_init_module(void __user *umod,
unsigned long len,
const char __user *uargs)
{
struct module *mod;
int ret = 0;
/* Must have permission */
if (!capable(CAP_SYS_MODULE))
return -EPERM;
如果没有权限,那么会返回一个ERROR NOT PERMISSION,没有权限,不然大家都可以insmod,那天下岂不乱套。
/* Only one module load at a time, please */
if (mutex_lock_interruptible(&module_mutex) != 0)
return -EINTR;
保证每次这有一个驱动被加载,这样可以简化程序的设计。
在Linux内核中,有不少设计被做简化了,如内核任务退出,如果你在内核任务退出时调用kthread_stop,那末就会造成死锁。
/* Do all the hard work */
mod = load_module(umod, len, uargs);
if (IS_ERR(mod)) {
mutex_unlock(&module_mutex);
return PTR_ERR(mod);
}
load_module应该做了绝大部分的工作,将驱动拷贝到内核,重定位等等,具体后面会分析。
/* Now sew it into the lists. They won't access us, since
strong_try_module_get() will fail. */
stop_machine_run(__link_module, mod, NR_CPUS);
/* Drop lock so they can recurse */
mutex_unlock(&module_mutex);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_COMING, mod);
/* Start the module */
MODULE_INIT()就是在这里开始运行的:)
if (mod->init != NULL)
ret = mod->init();
如果失败了,就是MODULE_INIT()返回值不为0,那么,不用说,释放资源~~
if (ret < 0) {
/* Init routine failed: abort. Try to protect us from
buggy refcounters. */
mod->state = MODULE_STATE_GOING;
synchronize_sched();
if (mod->unsafe)
printk(KERN_ERR "%s: module is now stuck!\n",
mod->name);
else {
module_put(mod);
mutex_lock(&module_mutex);
free_module(mod);
mutex_unlock(&module_mutex);
}
return ret;
}
/* Now it's a first class citizen! */
mutex_lock(&module_mutex);
mod->state = MODULE_STATE_LIVE;
/* Drop initial reference. */
module_put(mod);
unwind_remove_table(mod->unwind_info, 1);
module_free(mod, mod->module_init);
上面的代码是释放__init段的内存,如果你的函数有__init的属性,那么,此时会被释放掉,节约内存。
mod->module_init = NULL;
mod->init_size = 0;
mod->init_text_size = 0;
mutex_unlock(&module_mutex);
return 0;
OK,驱动加载完成。
}
当然,mod = load_module(umod, len, uargs)才是重点。
后面会对它进行详细的分析。