极限首页 业界焦点 软件工程师之路 系统工程师之路 网络工程师之路 软件下载 技术社区
 bash编程学习笔记(一)
 RPM 打包技术与典型 SPEC
 Linux Kernel核心中文手册
 精通递归程序设计
 Linux Kernel核心中文手册
 Linux/Unix环境下的make命
 Linux Kernel核心中文手册
 bash编程学习笔记(二)
 Linux Kernel核心中文手册
 Linux操作系统内核编译详解
 bash编程学习笔记(一)
 RPM 打包技术与典型 SPEC
 Linux Kernel核心中文手册
 精通递归程序设计
 Linux Kernel核心中文手册
 Linux/Unix环境下的make命
 Linux Kernel核心中文手册
 bash编程学习笔记(二)
 Linux Kernel核心中文手册
 Linux操作系统内核编译详解

Shell 中文手册

Python 2.3 中文手册

Python 2.4 中文手册

Mysql 4.x 中文手册

PHP 4.x 中文手册

Apache 2.x 中文手册
更多手册

站内搜索:
当前位置:首页>>软件工程师之路>>编程进阶>>正文
Linux Kernel核心中文手册(10~13)(4)
时间:2005-11-08 作者:未知 来源:未知

 

本章描述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 只是核心的一个代理,调度它的工作。

 

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模块的依赖数都是1,因为它们都有一个安装的文件系统。如果我加载另外一个VFAT文件系统,那么vfat模块的计数器会变成2。一 个模块的计数器放在它的映像的第一个长字中(longword)。

 

因为它也放置AUTOCLEAN和VISITED标志,所以这个字段有一些轻微过载。这些标志都用于按需加载模块。这些模块被标记为 AUTOCLEAN,这样系统可以识别出哪些它可以自动卸载。VISITED标志表示这个模块被一个或多个系统组件使用:只要另一个组件使用它就设置这个 标志。每一次kerneld请求系统删除不用的按需加载的模块的时候,它都查看系统中所有的模块,找到合适的候选。它只查看标记为AUTOCLEAN而且 状态是RUNNING的模块。如果这个候选的VISITED标记被清除,那么它就删除这个模块,否则它就清除这个VISITED标记,继续查找系统中的下 一个模块。

 

假设一个模块可以被卸载,就调用它的清除例程(cleanup),让它释放它所分配的核心资源。这个module数据结构被标记为DELTED,从 核心模块列表中删除。任何其它的它所依赖的模块的引用表被修改,这样它们不再把它当作一个依赖者。这个模块需要的所有的核心内存被释放。

 

Chapter 13

 

The Linux Kernel Sources(Linux核心源程序)

 

本章描述了你应该在Linux核心源程序的什么地方开始查看特定的核心功能。

 

本书不依赖‘C’语言的知识或要求你有Linux核心源程序才能理解Linux核心如何工作。而是说,练习查看核心源程序能够对于Linux操作系统有一个深入地理解。本章给出核心源程序的概览:它们如何组织,你应该从哪里开始查找特定的代码。

 

Where to Get The Linux Kernel Sources(从哪里得到Linux核心源程序)

 

所有的主要的Linux分发(Craftworks,Debian,Slackware,RedHat 等等)中间都有核心源程序。通常L安装在你的Linux系统上的Linux核心都是用这些源程序建立的。实际上这些源程序显得有些过时,所以你可能希望得 到附录C提到的web站点得到最新的源程序。它们放在ftp://ftp.cs.helsinki.fi和其它所有的镜像的web站点。Helsinki 的web站点最新,但是其它站点例如MIT和Sunsite也不会太落后。

 

如果你无法访问web,还有许多CDROM厂家用非常合理的费用提供世界主要web站点的块找。一些甚至提供预订服务,按季或月进行更新。你的本地的Linux用户组也是一个源程序的好的来源。

 

Linux核心源程序有一个非常简单的编号系统。任何偶数的核心(例如2.0.30)都是一个稳定的发行的核心,而任何奇数的核心(例如 2.1.42)都是一个开发中的核心。本书基于稳定的2.0.30源代码。开发版的核心具有所有的最新特点和所有最新的设备的支持,但是它们可能不稳定, 可能不是你所要的,但是让Linux社团测试最新核心是很重要的。这样可以让整个社团都进行测试。记住,即使你测试非生产用核心,最好也要备份你的系统。

 

对于核心源程序的改动作为patch文件分发。工具patch可以对于一系列源文件应用一系列修改。例如,如果你有2.0.29的源程序树,而你希望转移到2.0.30,你可以取到2.0.30的patch文件,并把这些patch(编辑)应用到源程序树上:

 

$ cd /usr/src/linux

$ patch -p1 < patch-2.0.30

 

这样可以不用拷贝整个源程序树,特别对于慢速的串行连接。一个核心补丁(正式和非正式的)的好来源是http://www.linuxhq.com

 

How The Kernel Sources Are Arranged(核心源程序如何组织)

 

在源程序树的最上层你会看到一些目录:

 

arch arch子目录包括所有和体系结构相关的核心代码。它还有更深的子目录,每一个代表一种支持的体系结构,例如i386和alpha。

Include include子目录包括编译核心所需要的大部分include文件。它也有更深的子目录,每一个支持的体系结构一个。Include/asm是这个体系 结构所需要的真实的include目录的软链接,例如include/asm-i386。为了改变体系结构,你需要编辑核心的makefile,重新运行 Linux的核心配置程序

Init 这个目录包含核心的初始化代码,这时研究核心如何工作的一个非常好的起点。 Mm 这个目录包括所有的内存管理代码。和体系结构相关的内存管理代码位于arch/*/mm/,例如arch/i386/mm/fault.c

Drivers 系统所有的设备驱动程序在这个目录。它们被划分成设备驱动程序类,例如block。

Ipc 这个目录包含核心的进程间通讯的代码

Modules 这只是一个用来存放建立好的模块的目录

Fs 所有的文件系统代码。被划分成子目录,每一个支持的文件系统一个,例如vfat和ext2

Kernel 主要的核心代码。同样,和体系相关的核心代码放在arch/*/kernel

Net 核心的网络代码

Lib 这个目录放置核心的库代码。和体系结构相关的库代码在arch/*/lib/

Scripts 这个目录包含脚本(例如awk和tk脚本),用于配置核心

 

Where to Start Looking(从哪里开始看)

 

  共5页: 上一页 [1] [2] [3] 4 [5] 下一页   
推荐】【 】【关闭


关于极限 | 站内地图 | 意见反馈 | 广告服务 | 数据服务 | 联系我们
本站所刊登的文章,技术资料,软件均整理于网络资源或本站原创,转载请务必联系原作者或本站。
Copyright ? 2001-2004 UPLinux.com All Rights Reserved.
本站唯一联系信箱:
京ICP备05010519