模块加载
当我们执行insmod的时候发生了什么?我们查看一下linux3.6代码在加载内核模块的时候做了什么
内核中处理模块的调用关系
include/linux/syscalls.h
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...)\
static const char *types_##sname[] = {\
__SC_STR_TDECL##x(__VA_ARGS__)\
};\
static const char *args_##sname[] = {\
__SC_STR_ADECL##x(__VA_ARGS__)\
};\
SYSCALL_METADATA(sname, x);\
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#else
#define SYSCALL_DEFINEx(x, sname, ...)\
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#endif
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
#define SYSCALL_DEFINE(name) static inline long SYSC_##name
#define __SYSCALL_DEFINEx(x, name, ...)\
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));\
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__));\
asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__))\
{\
__SC_TEST##x(__VA_ARGS__);\
return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__));\
}\
SYSCALL_ALIAS(sys##name, SyS##name);\
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))
#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
#define SYSCALL_DEFINE(name) asmlinkage long sys_##name
#define __SYSCALL_DEFINEx(x, name, ...)\
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
asmlinkage long sys_init_module(void __user *umod, unsigned long len,
const char __user *uargs);
asmlinkage long sys_delete_module(const char __user *name_user,
unsigned int flags);
调用关系
sys_init_module
|----->load_module
| |----->layout_and_allocate
| | |----->setup_load_info
| | |----->check_modinfo
| |----->find_module_sections
| |----->setup_modinfo
| |----->simplify_symbols
| ...
|----->do_one_initcall
...
setup_load_info
setup_load_info有一段代码,会查找".gnu.linkonce.this_module"这个段,如果找到后会把该段的虚拟地址给mod变量,在编译连接过程中我已知道该段存放了什么内容,主要是init和cleanup函数
info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
if (!info->index.mod) {
printk(KERN_WARNING "No module found in object\n");
return ERR_PTR(-ENOEXEC);
}
/* This is temporary: point mod into copy of data. */
mod = (void *)info->sechdrs[info->index.mod].sh_addr;
check_modinfo->set_license->add_taint_module->add_taint
这是一个对module进行license检查的过程,如果模块内没有使用license则会打印一下内核受到污染的信息
static void set_license(struct module *mod, const char *license)
{
if (!license)
license = "unspecified";
if (!license_is_gpl_compatible(license)) {
if (!test_taint(TAINT_PROPRIETARY_MODULE))
printk(KERN_WARNING "%s: module license '%s' taints "
"kernel.\n", mod->name, license);
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
}
}
void add_taint(unsigned flag)
{
/*
* Can't trust the integrity of the kernel anymore.
* We don't call directly debug_locks_off() because the issue
* is not necessarily serious enough to set oops_in_progress to 1
* Also we want to keep up lockdep for staging/out-of-tree
* development and post-warning case.
*/
switch (flag) {
case TAINT_CRAP:
case TAINT_OOT_MODULE:
case TAINT_WARN:
case TAINT_FIRMWARE_WORKAROUND:
break;
default:
if (__debug_locks_off())
printk(KERN_WARNING "Disabling lock debugging due to kernel taint\n");
}
set_bit(flag, &tainted_mask);
}
do_one_initcall
执行传入的函数指针mod->init也就是我们注册的初始化函数
模块卸载
sys_delete_module
|----->capable
|
|----->free_module
...
sys_delete_module
/* Final destruction now no one is using it. */
if (mod->exit != NULL)
mod->exit();
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
async_synchronize_full();
模块卸载相对比较简单,调用退出函数,处理一下模块未处理的任务,进行数据同步然后释放内存