首页>>科技 >>内容

Linux操作系统中LKM优缺点的研究与应用——

发布时间:2023-07-12 14:38:08编辑:温柔的背包来源:

很多朋友对Linux操作系统中LKM优缺点的研究与应用——不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。

Linux操作系统中LKM优缺点的研究与应用——

1.简介

Linux系统具有源代码开放、漏洞少的优点,面对病毒和黑客入侵,可以提供更好的安全性和稳定性。基于这些优势,近年来Linux操作系统及其相关技术的应用和研究日益增多。对Linux操作系统的功能进行扩展或裁剪,需要花费大量的时间重新编译内核。LKM机制在Linux的开发和研究中起着重要的作用,因为它大大缩短了开发和测试的时间。

LKM主要包括两个功能:加载和卸载操作系统中的内核模块。内核模块是代码块,可以在启动的操作系统的内核需要时加载到内核中执行,在不需要时由操作系统卸载。它们扩展了操作系统内核的功能,无需重新编译内核和启动系统。如果没有内核模块,就要反复编译生成操作系统的内核镜像来添加新的功能,而当附加功能很多的时候,内核就会变得臃肿。2.LKM的写作与编纂

2.1内核模块的基本结构一个内核模块至少包含两个函数,模块加载时执行的初始化函数init_module()和模块卸载时执行的结束函数cleanup_module()。在最新的稳定内核版本2.6中,有两个函数可以任意命名,分别由宏module_init()和module_exit()实现。唯一需要注意的是,函数必须在使用宏之前定义。例如:static int _ _ init hello _ init(void){ } static void _ _ exit hello _ exit(void){ }

模块_初始化(hello _ init);模块_出口(hello _ exit);这里将函数声明为static的目的是使函数在文件外部不可见。__init的作用是在初始化后回收函数占用的内存。宏__exit用于在模块编译到内核时忽略end函数。这两个宏只在模块编译到内核时使用,但对于动态加载模块无效。这是因为编译进内核的模块并不清理收尾工作,而动态加载模块需要自己完成这些任务。

2.2编译内核模块时,需要提供一个makefile,将大量复杂的操作隐藏在底层,以便用户通过make命令完成编译任务。下面是编译hello.ko的简单makefile:obj-m=hello . kok dir:=/lib/modules/$(shelluname-r)/build pwd:=$(shellpwd)default:$(make)-c $(kdir)subdirs=$(pwd)。

在内核版本2.6中。ko文件后缀被用来代替。o,不同于一般的可执行文件。3.LKM 3.1模块加载的主要功能

加载模块有两种方式。第一种方法是使用insmod命令,另一种方法是当内核发现需要加载一个模块时,请求内核后台进程kmod加载一个合适的模块。当内核需要加载一个模块时,kmod唤醒并执行modprobe,将要加载的模块的名称作为参数传递。Modprobe像insmod一样将模块加载到内核中,只是在加载模块时,会检查它是否涉及任何当前内核中未定义的符号。

如果是这样,请在当前模块路径的其他模块中查找。如果找到,它们也将被加载到内核中。但是,在这种情况下使用insmod会以“未解析符号”消息结束。

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

Insmod程序必须找到需要加载的内核模块。这些内核模块是链接的目标文件。与其他文件不同,它们被链接到可重定位的映像中,也就是说,映像不链接到特定的地址。Insmod会进行特权系统调用来查找内核的输出符号,这些符号成对存储为符号名和地址值等数值。内核输出符号表存储在内核维护的模块链表的第一模块结构中。

只添加特殊符号,这些符号是内核编译链接时确定的。Insmod将模块读入虚拟内存,并通过使用内核输出符号修改其未解析的内核函数和资源的引用地址。这些任务是由insmod程序直接将符号的地址写入模块中相应的地址来执行的。

当insmod修改模块对内核输出符号的引用时,它将再次使用特权系统调用来申请足够的空间来容纳新模块。内核会分配一个新的模块结构和足够的内核内存来保存新模块,并将其插入内核模块链表的末尾,最后将新模块标记为未初始化。Insmod将模块复制到分配的空间中,如果分配给它的内核内存用完了,它会重新申请,但是模块加载多次必须在不同的地址。

另外此重定位工作包括使用适当地址来修改模块映象。如果新模块也希望将其符号输出到系统中,insmod将为其构造输出符号映象表。每个内核模块必须包含模块初始化和结束函数,所以为了避免冲突它们的符号被设计成不输出,但是insmod必须知道这些地址,这样可以将它们传递给内核。

在所有这些工作完成以后,insmod将调用初始化代码并执行一个特权级系统调用将模块的初始化和结束函数地址传递给内核。当将一个新模块加载到内核中时,内核必须更新其符号表并修改那些被新模块使用的老模块。那些依赖于其他模块的模块必须在其符号表尾部维护一个引用链表并在其module数据结构中指向它。内核调用模块的初始化函数,如果成功将安装此模块。

模块的结束函数地址被存储在其module结构中,将在模块卸载时由内核调用,模块的状态最后被设置成RUNNING。

3.2 模块的卸载

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

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

内核中其他部分还在使用的模块不能被卸载。例如系统中安装了多个VFAT文件系统则不能卸载VFAT模块。执行lsmod将看到每个模块的引用计数。模块的引用计数被保存在其映象的第一个常字中,这个字还包含autoclean和visited标志。如果模块被标记成autoclean,则内核知道此模块可以自动卸载。

visited标志表示此模块正被一个或多个文件系统部分使用,只要有其他部分使用此模块则这个标志被置位。每次系统要将没有被使用的请求加载模块删除时,内核将在所有模块中扫描,但是一般只查看那些被标志为autoclean并处于running状态的模块。如果某模块的visited标记被清除则它将被删除。其他依赖于它的模块将修改各自的引用域,表示它们间的依赖关系不复存在。

此模块占有的内核内存将被回收。

4. LKM的应用

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

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

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

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

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

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

5. LKM与普通应用程序的比较

LKM与普通应用程序之间的区别主要体现在四个方面。

第一,也是最重要的区别,普通应用程序运行在用户空间,而LKM运行在内核空间。通过区分不同的运行空间,操作系统能够安全地保护操作系统中一些重要数据结构的内容不被普通应用程序所修改,达到保证操作系统正常运转的目的。

第二,普通应用程序的目标很明确,它们从头至尾都是为了完成某一项特定任务。而LKM是在内核中注册并为后续应用程序的请求提供服务的。

第三,普通应用程序可以调用并没有在其中定义的函数,但一个LKM是链接到内核上的,它所能调用的函数只有内核导出来的那些函数。

第四,普通应用程序和LKM处理错误的方式不同。当应用程序中出现错误时并不会给系统造成很大的伤害。LKM则不然,在其中出现的错误对子系统来说通常是致命的,至少对于当前正在运行的进程而言。LKM中的一个错误常常会导致整个系统崩溃。

6. 编写LKM需要注意的问题

LKM运行在内核空间,它们拥有对整个系统所有资源的访问权限,因此,编写LKM首先要注意就是安全问题,而且还应该避免将可能导致出现安全问题的代码带到LKM中。

LKM加载后是作为操作系统内核的一部分运行的,因此,在设计、编写操作系统内核过程中应该注意的问题在LKM中也应该引起足够的重视。在这里,主要指的是并发问题和指针引用问题。并发是指在同一时间有多个进程在操作系统内核中同时运行。并发结合共享资源最终会导致竞态条件,在这种情况下应该对各个并发进程访问共享资源进行严格的控制。

如果在LKM中出现指针引用错误,内核将没有办法将内存的虚拟地址映射到物理地址,从而导致出现内核中的意外,如内存访问冲突、除0以及非法操作等。

7. LKM的不足之处

LKM虽然在设备驱动程序的编写和扩充内核功能中扮演着非常重要的角色,但它仍有许多不足的地方。

第一,LKM对于内核版本的依赖性过强,每一个LKM都是靠内核提供的函数和数据结构组织起来的。当这些内核函数和数据结构因为内核版本变化而发生变动时,原先的LKM不经过修改就可能不能正常运行。

第二,虽然现在有针对内核编程调试的工具kgdb,但是在LKM编写过程中调试仍非常麻烦,而且在调试过程中,系统所能提供的出错信息极为晦涩。

创新点:针对Linux内核,利用LKM,在实现了数据的零拷贝(Zero-copy)的过程中,将LKM与普通应用程序进行比较,提出了LKM的优势和不足。

以上知识分享希望能够帮助到大家!

版权声明:本站所有作品图文均由用户自行上传分享,仅供网友学习交流。若您的权利被侵害,请联系我们

推荐阅读