分享
 
 
 

LinuxKernel核心中文手册(12)

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

Modules

本章描述 Linux 核心如何只在需要的时候才动态加载函数,例如文件系统。

Linux 是一个完整的核心,就是说,它是一个单一的巨大的程序,核心的功能组件可以访问它的所有的内部数据结构以及例程。另一种方法是使用一个微内核的结构,核心的功能片被分成独立的单元,互相之间有严格的通讯机制。这样通过配置进程向核心增加新的组件不花多少时间。比如你希望增加一个 NCR 810 SCSI 卡的 SCSI 驱动程序,你不需要把它连接到核心。否则你不得不配置并建立一个新的核心才能使用这个 NCR 810 。作为一种变通, Linux 允许在你需要的时候动态地加载和卸载操作系统的组件。 Linux 的模块是可以在系统启动之后任何时候动态连接到核心的代码块。它们可以在不被需要的时候从核心删除并卸载。大多数 Linux 核心模块是设备驱动程序,伪设备驱动程序比如网络驱动程序或文件系统。

你可以使用 insmod 和 rmmod 命令明确地加载和卸载 Linux 核心模块,或者在需要这些模块的时候由核心自己要求核心守护进程( kerneld )加载和卸载这些模块。在需要的时候动态地加载代码相当有吸引力,因为它让核心可以保持最小而且核心非常灵活。我当前的 Intel 核心大量使用模块,它只有 406K 大小。我通常只适用 VFAT 文件系统,所以我建立我的 Linux 核心,当我安装一个 VFAT 分区的时候自动加载 VFAT 文件系统。当我卸载 VFAT 文件系统的时候,系统探测到我不再需要 VFAT 文件系统模块,把它从系统中删除。模块也可以用来尝试新的核心代码而不需要每次都创建和重启动核心。但是,没有这么好的事情,使用核心模块通常伴随轻微的性能和内存开支。一个可加载模块必须提供更多的代码,这种代码和额外的数据结构会占用更多一点的内存。另外因为间接访问核心资源也让模块的效率轻微降低。

一旦 Linux 核心加载,它就和普通核心代码一样成为核心的一部分。它和任何核心代码拥有相同的权利和义务:换句话说, Linux 核心模块和所有的核心代码或设备驱动程序一样可能让核心崩溃。

既然模块在需要的时候可以使用核心资源,它们必须能够找到这些资源。比如一个模块需要调用 kmalloc() ,核心内存分配例程。当建立的时候( build ),模块不知道内存中 kmalloc() 在哪里,所以当这个模块加载的时候,在模块能够工作之前,核心必须整理模块对于 kmmalloc() 的所有的引用。核心在核心符号表中保存了所有核心资源的列表,所以当模块加载的时候它可以解析模块中对于这些资源的引用。 Linux 允许模块堆栈(堆砌),就是一个模块需要另一个模块的服务。例如 VFAT 文件系统模块需要 FAT 文件系统模块的服务,因为 VFAT 文件系统或多或少是 FAT 文件系统上的扩展。一个模块需要另一个模块的服务或资源的情况和一个模块需要核心自己的服务和资源的情况非常相似,只不过这时请求的服务在另一个,此前已经加载的模块钟。当每一个模块加载的时候,核心修改它的符号表,把这个新加载的模块的所有输出的资源或符号加到核心符号表中。这意味着,当下一个模块加载的时候,它可以访问已经加载的模块的服务。

当时图卸载一个模块的时候,核心需要知道这个模块不在用,它还需要一些方法来通知它准备卸载的模块。用这种方法模块可以在它从核心删除之前释放它占用的任何的系统资源,例如核心内存或中断。当模块卸载的时候,核心把这个模块输出到核心符号表中所有的符号都删除。

除了写的不好的可加载模块可能破坏操作系统之外,还有另一个危险。如果你加载一个为比你当前运行的核心要早或迟的核心建立的模块会发生什么?如果这个模块执行一个核心例程而提供了错误的参数就会引起问题。核心可以选择防止这种情况,当模块加载的时候进行严格的版本检查。

12.1 Loading a Module (加载一个模块)

用两种方法可以加载一个核心模块。第一种使用 insmod 命令手工把它插入到核心。第二种,更聪明的方法是在需要的时候加载这个模块:这叫做按需加载( demand loading )。当核心发现需要一个模块的时候,例如当用户安装一个不在核心的文件系统的时候,核心会请求核心守护进程( kerneld )试图加载合适的模块。

Kerneld 和 insmod , lsmod 以及 rmmod 都在 modules 程序包中。

核心守护进程通常是拥有超级用户特权的一个普通的用户进程。当它启动的时候(通常是在系统启动的时候启动),它打开一个通向核心的 IPC 通道。核心使用这个连接向 kerneld 发送消息,请求它执行大量的任务。 Kerneld 的主要功能是加载和卸载核心模块,但是它也可以执行其它任务,比如需要的时候在串行线上启动 PPP 连接,不需要的时候把它关闭。 Kerneld 本身并不执行这些任务,它运行必要的程序比如 insmod 来完成工作。 Kerneld 只是核心的一个代理,调度它的工作。

参见 include/linux/kerneld.h

insmod 命令必须找到它要加载的被请求的核心模块。按徐加载的核心模块通常放在 /lib/mmodules/kernel-version 目录里边。核心模块和系统中的其它程序一样是连接程序的目标文件,但是它们被连接成可以重定位的映像。就是没有连接到特定地址去运行的映像。它们可以是 a.out 或 elf 格式的目标文件。 Insmod 指向一个特权的系统调用,找出系统的输出符号。它们以符号名称和值(例如它的地址)的形式成对存放。核心的输出符号表放在核心维护的模块列表中的第一个 module 数据结构,用 module_list 指针指向。只有在核心编译和连接的时候特殊指定的符号才加到这个表中,而并非核心的每一个符号都输出它的模块。例如符号“ request_irq ”是一个系统例程,当一个驱动程序希望控制一个特定的系统中断的时候必须调用它。在我当前的核心上,它的值是 0x0010cd30 。你可以检查文件 /proc/ksyms 或使用 ksyms 工具简单地查看输出的核心符号和它们的值。 Ksyms 工具可以向你显示所有的输出的核心符号或者只显示哪些加载模块输出的符号。 Insmod 把模块读取到它的虚拟内存,使用核心的输出符号来整理这个模块对于核心例程和资源的未解析的引用。这个整理过程是用向内存中的模块映像打补丁的方式进行, insmod 物理上把符号的地址写到模块的合适的位置。

参见 kernel/module.c kernel_syms() include/linux/module.h

当 insmod 整理完了模块对于输出的核心符号的引用之后,他向核心请求足够的空间放置新的核心,又是通过特权的系统调用。核心分配一个新的 module 数据结构和足够的核心内存来存放这个新的模块,并把它放置到核心的模块列表的最后。这个新的模块被标记为 UNINITIALIZED 。图 12.1 显示了核心模块列表的后面两个模块: FAT 和 VFAT 被加载到了内存。图中没有显示的有列表的第一个模块:这是一个伪模块,用于放置核心的输出符号表。你可以使用命令 lsmod 列出所有加载的核心模块和它们之间的依赖关系。 Lsmod 只是简单地把从核心 module 数据结构列表中提取的 /proc/modules 重新安排了格式。核心为模块分配的内存映射到 insmod 进程的地址空间,所以它可以访问它。 Insmod 把模块拷贝到分配的空间,并把它重定位,这样它就可以从被分配的核心地址运行。必须进行重定位,因为一个模块不能期待在两次被加载到相同的地址或者在两个不同的 Linux 系统上被加载到相同的地址。这一次,重定位又关系到要用适当的地址为模块的映像打补丁。

参见 kernel/module.c create_module()

新的模块也向核心输出符号, Insmod 建立一个输出映像表。每一个核心模块必须包含模块初始化和模块清除的历程,这些符号必须是专用的而不是输出的,但是 insmod 必须知道它们的地址,能把它们传递给核心。所有这些做好之后, Insmod 现在准备初始化这个模块,它执行一个特权的系统调用,把这个模块的初始化和清除例程的地址传递给核心。

参见 kernel/module.c sys_init_module()

当一个新的模块加到核心的时候,它必须更新核心的符号表并改变被新的模块使用的模块。其它模块依赖的模块必须在它们的符号表之后维护一个引用列表,用它们的 module 数据结构指向。图 12.1 显示了 VFAT 文件系统模块依赖于 FAT 文件系统模块。所以 FAT 模块包含一个到 VFAT 模块的引用:这个引用在 VFAT 模块加载的时候增加。核心调用模块的初始化例程,如果成功,它开始安装这个模块。模块的清除例程的地址保存在它的 module 数据结构中,当这个模块卸载的时候核心会去调用。最后,模块的状态被设置为 RUNNING 。

12.2 Unloading a Module

模块可以使用 rmmod 命令删除,但是 kerneld 可以把所有不用的按需加载的模块从系统中删除。每一次它的空闲计时器到期的时候, kerneld 执行系统调用,请求从系统删除所有的不需要的按需加载的模块。这个计时器的值由你在启动 kerneld 的时候设定:我的 kerneld 每 180 秒检查一次。如果你安装了一个 iso9660 CD ROM 而你的 iso9660 文件系统是一个可加载模块,那么,在 CD ROM 卸载不久, iso9660 模块会从核心中删除。

如果核心中的其它组件依赖于一个模块,它就不能被删除。例如如果你安装了一个或更多的 VFAT 文件系统,你就不能卸载 VFAT 模块。如果你检查 ls 输出,你会看到每一个模块关联一个计数器。例如:

Module: #pages: Used by:

msdos 5 1

vfat 4 1 (autoclean)

fat 6 [vfat msdos] 2 (autoclean)

这个计数器( count )是依赖于这个模块的核心实体的数目。在上例中, vfat 和 msdos 都依赖于 fat 模块,所以 fat 模块的计数器是 2 。 Vfat 和 msdos 模块的依赖数

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有