分类: LINUX
2013-01-01 20:23:38
asmlinkage unsigned long
sys_create_module(const char *name_user, size_t size)
{
char *name;
long namelen, error;
struct module *mod;
unsigned long flags;
if (!capable(CAP_SYS_MODULE))
return -EPERM;
lock_kernel();
if ((namelen = get_mod_name(name_user, &name)) < 0) {
error = namelen;
goto err0;
}
if (size < sizeof(struct module)+namelen) {
error = -EINVAL;
goto err1;
}
if (find_module(name) != NULL) {
error = -EEXIST;
goto err1;
}
if ((mod = (struct module *)module_map(size)) == NULL) {
error = -ENOMEM;}
memset(mod, 0, sizeof(*mod));
mod->size_of_struct = sizeof(*mod);
mod->name = (char *)(mod + 1);
mod->size = size;
memcpy((char*)(mod+1), name, namelen+1);
put_mod_name(name);
spin_lock_irqsave(&modlist_lock, flags);
mod->next = module_list;
module_list = mod; /* link it in */
spin_unlock_irqrestore(&modlist_lock, flags);
error = (long) mod;
goto err0;
err1:
put_mod_name(name);
err0:
unlock_kernel();
return error;
}
下面对该函数中的主要语句给予解释。
· capable(CAP_SYS_MODULE)检查当前进程是否有创建模块的特权。
· 参数size表示模块的大小,它等于module结构的大小加上模块名的大小,再加上
模块映像的大小,显然,size不能小于后两项之和。
· get_mod_name()函数获得模块名的长度。
· find_module()函数检查是否存在同名的模块,因为模块名是模块的唯一标识。
· 调用module_map()分配空间,对i386来说,就是调用vmalloc()函数从内核空
间的非连续区分配空间。
· memset()将分配给module结构的空间全部填充为0,也就是说,把通过module_map()所分配空间的开头部分给了module结构;然后(module+1)
表示从mod所指的地址加上一个module结构的大小,在此处放上模块的名字;最
后,剩余的空间给模块映像。
· 新建module结构只填充了三个值,其余值有待于从用户空间传递过来。
· put_mod_name()释放局部变量name所占的空间。
· 将新创建的模块结构链入module_list链表的首部。struct module
{
unsigned long size_of_struct; /* 模块结构的大小,即sizeof(module) */
struct module *next; /* 指向下一个模块 */
const char *name; /*模块名,最长为64个字符*/
unsigned long size; /*以页为单位的模块大小*/
union
{
atomic_t usecount; /*使用计数,对其增减是原子操作*/
long pad;
} uc; /* Needs to keep its size - so says rth */
unsigned long flags; /* 模块的标志 */
unsigned nsyms; /* 模块中符号的个数 */
unsigned ndeps; /* 模块依赖的个数 */
struct module_symbol *syms; /* 指向模块的符号表,表的大小为nsyms */
struct module_ref deps; /*指向模块引用的数组,大小为ndeps */
struct module_ref *refs;
int (*init)(void); /* 指向模块的init_module()函数 */
void (*cleanup)(void); /* 指向模块的cleanup_module()函数 */
const struct exception_table_entry *ex_table_start;
const struct exception_table_entry *ex_table_end;
/* 以下域是在以上基本域的基础上的一种扩展,因此是可选的。可以调用
mod_member_present()函数来检查以下域的存在与否。 */
const struct module_persist *persist_start; /*尚未定义*/
const struct module_persist *persist_end;
int (*can_unload)(void);
int runsize /*尚未使用*/
const char *kallsyms_start; /*用于内核调试的所有符号 */
const char *kallsyms_end;
const char *archdata_start; /* 与体系结构相关的特定数据*/const char *kernel_data; /*保留 */
};
上面给出了struct module原型,也写出来sys_create_module()函数,但
是sys_create_module函数仅仅在内核为模块开辟了一块空间,但是模块的
代码根本没有拷贝过来。实际上,模块的真正安装工作及其他的一些初始化工作由
sys_init_module()函数完成,
该函数的原型为:
asmlinkage long sys_init_module(const char *name_user, struct