购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.6 函数:find_module()

文件包含:


#include <linux/module.h>

函数定义:

在内核源码中的位置:linux-3.19.3/kernel/module.c

函数定义格式:struct module*find_module(const char*name)

函数功能描述:

函数find_module()用来获得一个指向模块的指针。它是根据给定的模块名字查找模块链表,如果找到一个与给定的模块名字相匹配的模块,则返回该模块的指针。由于一个模块的名字是唯一的且不允许有重名的模块,因此基于模块名查找模块是可行的。

输入参数说明:

name:为字符串常量,表示所要查找的模块的名字。

返回参数说明:

返回值是一个struct module类型的指针,如果find_module()函数查找模块成功,则返回值指向查找到的名为name的模块,如果查找不成功,则返回NULL。

其中,模块结构体module在内核文件linux-3.19.3/include/linux/module.h中定义,下面对该结构体中的一部分字段进行说明:


struct module
{
     /* 模块当前的状态,state取值有四种情况:
     * MODULE_STATE_LIVE, 指示模块当前正在使用
     * MODULE_STATE_COMING, 指示模块正被加载
     * MODULE_STATE_GOING,  指示模块正被卸载
     * MODULE_STATE_UNFORMED,  指示模块未被设置,未定型
     */
    enum module_state state;
    /* 指向模块链表中的下一个模块 */
    struct list_head list;
    /* 特定的模块名称 */
    char name[MODULE_NAME_LEN];
    
   
   
    /* 向内核空间导出的符号 */
    const struct kernel_symbol *syms;     /* 指向模块的符号表,表大小为num_syms */
    const unsigned long *crcs;
    unsigned int num_syms;                /* 模块中符号的个数 */
    /* 内核参数 */
    struct kernel_param *kp;
    unsigned int num_kp;
    /* 基于GPL-only的可移出符号 */
    unsigned int num_gpl_syms;
    const struct kernel_symbol *gpl_syms;
    const unsigned long *gpl_crcs;
    
   
    /* 异常处理函数表 */
    unsigned int num_exentries;
    struct exception_table_entry *extable;
    /* 指向初始化方法的函数指针 */
    int (*init)(void);
    /* 模块初始化时函数的内存地址 */
    void *module_init;
    /* 模块的内存起始地址 */
    void *module_core;
    /* 模块目标代码的初始部分和执行部分所占内存空间大小 */
    unsigned int init_size, core_size;
    /* init  core 段中可执行代码所在内存空间的大小 */
    unsigned int init_text_size, core_text_size;
    /* 模块RO区域大小,包括text+rodata两部分区域 */
    unsigned int init_ro_size, core_ro_size;
    /* 基于特定体系结构的模块值 */
    struct mod_arch_specific arch;
    /* 标识内核是否加入了非自由软件的模块 */
    unsigned int taints;        
    
   
   
    #ifdef CONFIG_SMP
    /* CPU数据 */
    void *percpu;
    unsigned int percpu_size;
    #endif
    
   
    #ifdef CONFIG_MODULE_UNLOAD
    /* 所有依赖于该模块的模块 */
    struct list_head source_list;
    /* 所有该模块依赖的模块 */
    struct list_head target_list;
    /* 模块退出时调用的函数 */
    void (*exit)(void);
    atomic_t refcnt;                // 记录模块被引用的次数
    #endif
    #ifdef CONFIG_CONSTRUCTORS
    /* 构造函数*/
    ctor_fn_t * ctors;
    unsigned int num_ctors;        // 记录模块构造函数个数
    #endif
};

实例解析:

编写测试文件:find_module.c

头文件及全局变量声明如下:


#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL"); 
static int __init find_module_init(void); 
static void __exit find_module_exit(void);

模块初始化函数:


int __init find_module_init(void) 
{ 
    const char *name = "test_module";        // 定义待查找的模块名为“test_module
    struct module * fmodule = find_module( name );            // 调用查找模块函数
    /* 如果查找成功,则输出该模块的信息 */
    if( fmodule != NULL )
    {
        printk("fmodule->name: %s\n",fmodule->name);          // 输出模块名
        printk("fmodule->state: %d\n",fmodule->state);        // 输出模块状态
        /* 输出模块core段所占空间大小 */
        printk("fmodule->core_size: %d\n",fmodule->core_size);  
        /* 输出模块引用计数 */
        printk("module_refcount(fmodule): %d\n",module_refcount(fmodule)); 
    }
    name = "cuse";                                            // 模块名
    fmodule = find_module( name );                            // 调用查找模块函数
    /* 如果查找成功,则输出该模块的信息 */
    if( fmodule != NULL )
    {
        printk("fmodule->name: %s\n",fmodule->name);          // 输出模块名
        printk("fmodule->state: %d\n",fmodule->state);        // 输出模块状态
        /* 输出模块core段所占空间大小 */
        printk("fmodule->core_size: %d\n",fmodule->core_size);   
        /* 输出模块引用计数 */
        printk("module_refcount(fmodule): %d\n",module_refcount(fmodule));
    }
    return 0; 
}

模块退出函数:


void __exit find_module_exit(void) 
{ 
    printk("module exit ok!\n"); 
}

模块初始化及退出函数调用:


module_init(find_module_init); 
module_exit(find_module_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod find_module.ko插入模块,然后执行命令dmesg-c,会出现如图2-12所示的结果。

图2-12 插入find_module模块后系统输出信息

结果分析:

在该测试程序中,调用find_module()内核函数查找了两个内核模块。

首先查找名为“test_module”的模块,将name赋值为“test_module”,然后调用find_module()来获得与它相对应的模块的结构体描述符指针,赋值给fmodule。通过输出结构体指针fmodule的一些字段来获得模块“test_module”的一些信息,由输出信息可知:fmodule->name恰为“test_module”,fmodule->state为0(即表示该模块处于正在被使用的MODULE_STATE_LIVE状态,见下面关于枚举类型module_state的说明),fmodule->core_size恰为12950字节,然后调用module_refcount()得到该模块的引用计数为5。

同样的,再将name赋值为“cuse”,调用find_module()来获得与它相对应的模块的结构体描述符指针,赋值给fmodule。由输出信息可知:fmodule->name恰为“cuse”,fmodule->state为0(即表示该模块处于正在被使用的MODULE_STATE_LIVE状态),fmodule->core_size恰为13445,然后调用module_refcount()得到该模块的引用计数为3。

为了验证上述结果的正确性,这里截取了模块显示列表中的一些信息,如图2-13所示。

图2-13 部分模块信息

从图2-13中可以看到,系统中存在两个名为“test_module”和“cuse”的模块,它们的大小和引用计数都显示出来,与上面测试的结果是一致的。

分析中涉及枚举类型module_state,它在内核文件linux-3.19.3/include/linux/module.h中定义,该枚举类型定义了模块的四种状态,其具体定义如下: iioJ6wUPKjA0IGlRemvYt1Dub5aNhX8Z1GHoaOFE0QLmFSLzymyc5sl9SPY+vHzC


enum module_state
{
    MODULE_STATE_LIVE,            // 模块当前正在使用
    MODULE_STATE_COMING,          // 模块正被加载
    MODULE_STATE_GOING,           // 模块正被卸载
    MODULE_STATE_UNFORMED,        // 模块未被设置,未定型
};

点击中间区域
呼出菜单
上一章
目录
下一章
×