新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > Linux可加载内核模块机制的研究与应用

Linux可加载内核模块机制的研究与应用

作者:时间:2012-03-31来源:网络收藏

关于模块加载,可以用图3.1来简要描述:

图3.1 模块的装入

insmod程序必须找到要求加载的内核模块,这些内核模块是已链接的目标文件,与其他文件不同的是,它们被链接成可重定位映象即映象没有被链接到特定地址上。insmod将执行一个特权级系统调用来查找内核的输出符号,这些符号都以符号名和数值形式如地址值成对保存。内核输出符号表被保存在内核维护的模块链表的第一个module结构中。只有特殊符号才被添加,它们在内核编译与链接时确定。insmod将模块读入虚拟内存并通过使用内核输出符号来修改其未解析的内核函数和资源的引用地址。这些工作采取由insmod程序直接将符号的地址写入模块中相应地址来进行。

当insmod修改完模块对内核输出符号的引用后,它将再次使用特权级系统调用申请足够的空间容纳新模块。内核将为其分配一个新的module结构以及足够的内核内存来保存新模块,并将其插入到内核模块链表的尾部,最后将新模块标志为UNINITIALIZED。insmod将模块拷贝到已分配空间中,如果为它分配的内核内存已用完,将再次申请,但模块被多次加载必然处于不同的地址。另外此重定位工作包括使用适当地址来修改模块映象[5]。如果新模块也希望将其符号输出到系统中,insmod将为其构造输出符号映象表。每个内核模块必须包含模块初始化和结束函数,所以为了避免冲突它们的符号被设计成不输出,但是insmod必须知道这些地址,这样可以将它们传递给内核。在所有这些工作完成以后,insmod将调用初始化代码并执行一个特权级系统调用将模块的初始化和结束函数地址传递给内核。当将一个新模块加载到内核中时,内核必须更新其符号表并修改那些被新模块使用的老模块[6]。那些依赖于其他模块的模块必须在其符号表尾部维护一个引用链表并在其module数据结构中指向它。内核调用模块的初始化函数,如果成功将安装此模块。模块的结束函数地址被存储在其module结构中,将在模块卸载时由内核调用,模块的状态最后被设置成RUNNING。

3.2 模块的卸载

模块可以使用rmmod命令删除,但是请求加载模块在其使用计数为0时,自动被系统删除。kmod在其每次idle定时器到期时都执行一个系统调用,将系统中所有不再使用的请求加载模块删除。

关于模块卸载,可以用图3.2来描述:

内核中其他部分还在使用的模块不能被卸载。例如系统中安装了多个VFAT文件系统则不能卸载VFAT模块。执行lsmod将看到每个模块的引用计数。模块的引用计数被保存在其映象的第一个常字中,这个字还包含autoclean和visited标志。如果模块被标记成autoclean,则内核知道此模块可以自动卸载。visited标志表示此模块正被一个或多个文件系统部分使用,只要有其他部分使用此模块则这个标志被置位。每次系统要将没有被使用的请求加载模块删除时,内核将在所有模块中扫描,但是一般只查看那些被标志为autoclean并处于running状态的模块。如果某模块的 visited标记被清除则它将被删除。其他依赖于它的模块将修改各自的引用域,表示它们间的依赖关系不复存在。此模块占有的内核内存将被回收。

4. 的应用

基本思想是:数据分组从网络设备到用户程序空间传递的过程中,减少数据拷贝次数,减少系统调用,实现CPU的零参与,彻底消除CPU在这方面的负载。的实现分为实现DMA数据传输和地址映射两个部分。其中DMA数据传输与本文关系不大,就不详细叙述了,这里主要介绍应用机制实现的地址映射。

地址映射的基本原理是在内核空间申请内存,通过proc文件系统和mmap函数将其映射到用户空间来允许应用程序访问,这样就消除了内核空间到应用程序空间的数据拷贝。地址映射部分的实现主要分为以下三步:

第一,建立LKM的基本结构,包括编写初始化和结束函数等。

第二,声明完成映射功能所需要的函数,主要有分配和初始化内核内存函数init_mem(),释放内核内存函数del_mem(),向内核内存输入内容的函数put_mem()等。

第三,在初始化函数中应用第二步建立的函数分配一块内存空间、输入内容、建立proc文件系统入口。在结束函数中释放已分配的内核内存,删除proc文件系统入口。

编写应用程序测试该LKM,发现已经达到了映射内核内存到应用程序空间的目的。在实现的过程中采用LKM机制不但便于调试而且大大减少了开发时间。

linux操作系统文章专题:linux操作系统详解(linux不再难懂)


关键词: LKM Linux 零拷贝

评论


相关推荐

技术专区

关闭