Linux 核心--13.Linux动态模块

第十二章 模块

本章主要描叙Linux核心动态加载功能模块(如文件系统)的工作原理 。

Linux核心是一种monolithic类型的内核 , 即单一的大程序 , 核心中所有的功能部件都可以对其全部内部数据结构和例程进行访问 。核心的另外一种形式是微内核结构 , 此时核心的所有功能部件都被拆成独立部分 ,  这些部分之间通过严格的通讯机制进行联系 。这样通过配置进程将新部件加入核心的方式非常耗时 。比如说我们想为一个NCR 810 SCSI卡配置SCSI驱动 , 但是核心中没有这个部分 。那么我们必须重新配置并重构核心 。Linux可以让我们可以随意动态的加载与卸载操作系统部件 。Linux模块就是这样一种可在系统启动后的任何时候动态连入核心的代码块 。当我们不再需要它时又可以将它从核心中卸载并删除 。Linux模块多指设备驱动、伪设备驱动, 如网络设备和文件系统 。

Linux为我们提供了两个命令:使用insmod来显式加载核心模块 , 使用rmmod来卸载模块 。同时核心自身也可以请求核心后台进程kerneld来加载与卸载模块 。

动态可加载代码的好处在于可以让核心保持很小的尺寸同时非常灵活 。在我的Intel系统中由于使用了模块 , 整个核心仅为406K字节长 。由于我只是偶尔使用VFAT文件系统, 所以我将Linux核心构造成当mount VFAT分区时自动加载VFAT文件系统模块 。当我卸载VFAT分区时系统将检测到我不再需要VFAT文件系统模块 , 将把它从系统中卸载 。模块同时还可以让我们无需重构核心并频繁重新启动来尝试运行新核心代码 。尽管使用模块很自由 , 但是也有可能同时带来与核心模块相关的性能与内存损失 。可加载模块的代码一般有些长并且额外的数据结构可能会占据一些内存 。同时对核心资源的间接使用可能带来一些效率问题 。

一旦Linux模块被加载则它和普通核心代码一样都是核心的一部分 。它们具有与其他核心代码相同的权限与职 责;换句话说Linux核心模块可以象所有核心代码和设备驱动一样使核心崩溃 。

模块为了使用所需核心资源所以必须能够找到它们 。例如模块需要调用核心内存分配例程kmalloc()来分配 内存 。模块在构造时并不知道kmalloc()在内存中何处 , 这样核心必须在使用这些模块前修改模块中对 kmalloc()的引用地址 。核心在其核心符号表中维护着一个核心资源链表这样当加载模块时它能够解析出模块 中对核心资源的引用 。Linux还允许存在模块堆栈 , 它在模块之间相互调用时使用 。例如VFAT文件系统模块 可能需要FAT文件系统模块的服务 , 因为VFAT文件系统多少是从FAT文件系统中扩展而来 。某个模块对其他模 块的服务或资源的需求类似于模块对核心本身资源或服务的请求 。不过此时所请求的服务是来自另外一个事先 已加载的模块 。每当加载模块时 , 核心将把新近加载模块输出的所有资源和符号添加到核心符号表中 。

当试图卸载某个模块时 , 核心需要知道此模块是否已经没有被使用 , 同时它需要有种方法来通知此将卸载模块 。模块必须能够在从核心种删除之前释放其分配的所有系统资源 , 如核心内存或中断 。当模块被卸载时 , 核心将从核心符号表中删除所有与之对应的符号 。

可加载模块具有使操作系统崩溃的能力 , 而编写较差的模块会带来另外一种问题 。当你在一个或早或迟构造的核心而不是当前你运行的核心上加载模块时将会出现什么结果?一种可能的情况是模块将调用具有错误参数的核心例程 。核心应该使用严格的版本控制来对加载模块进行检查以防止这种这些情况的发生 。

推荐阅读