linux内核--模块

模块简介

Windows NT是一种微内核的结构,其内核的功能块被划分成独立的模块,在这些功能块之间有严格的通信机制;而Linux则不同,它是一种monolithic(单一大块)结构,也就是说,整个内核是一个单独的、非常大的程序。在这种结构中,部件的添加和删除都相当麻烦,需要重新编译内核。为了解决这个问题,Linux引入了一种称为module(模块)的技术,可以把某些功能代码作为模块动态装载到内核中使用。

 

模块是一种目标对象文件,需要在内核空间执行,可以把它看作是一组已经编译好而且已经链接成可执行文件的程序。在需要的时候,内核就会实用某种方法调用这些程序来执行特定的操作,实现特定的功能。内核在内核符号表中维护了一个模块的链表,每个符号表对应一个模块,在把模块加载进内核时正确地对其进行解释,并将模块作为内核的一部分来执行;加载进内核中的模块具有所有的内核权限。模块可以在系统启动时加载到系统中,也可以在系统运行的任何时刻加载;在不需要时,可以将模块动态卸载。这样就不用每次修改系统的配置时都要重新编译内核了。

 

模块的优缺点

内核模块的这种动态装载特性具有以下的优点:

1、可以把内核映像文件保持在最小。在编译内核时可以选择把一部分内容当成模块进行编译,这样在最终生成的内核映像文件中就可以不包含这部分内容,从而生成最小的内核映像文件。

2、灵活性好。如果需要实用新的模块,不必重新编译内核,只要把新的模块编译后装载进系统中就可以了。如果对内核源程序进行了修改,也不需要重新编译整个内核,只需要修改对应的部分就可以了。

 

但是,内核模块的引入也带来了一些问题:

1、这种动态加载的特性不利于系统的性能和内存的利用,会带来负面的影响。

2、装入内核的模块和其他内核部分一样具有最高的权限,使用不当就可能引起系统的崩溃。

3、内核版本和模块版本的不兼容也会导致系统的崩溃,因此必须进行严格的版本检查,这样就使模块的编写变得更加复杂了。

4、有些模块要使用其他模块(例如VFAT就要使用FAT)的内容,模块之间存在一定的依赖关系,这样模块的实用就复杂化了。

 

由于模块的这种动态装载/卸载的特性,在Linux中大部分设备驱动程序都是使用模块来编写的,例如文件系统(minix、msdos、isofs、smbms、nfs、proc等等)、SCSI设备驱动程序、以太网驱动程序、CD-ROM驱动程序等等。

 

模块的使用

1、模块的查询

我们可以使用lsmod命令来了解系统中现在装载进来了哪些模块。例如,在某机器上执行的结果为(注意,以下介绍的这些命令(包括lsmod)只有超级用户才可以执行):  

  Module Size  Used by

  lockd 30344 1 (autoclean)

  sunrpc 52132 1 (autoclean) [lockd]

  rtl8139 11748 1 (autoclean)

其中Module列是模块的名字,Size是显示的模块的大小,Used by列表示引用次数,圆括号中的autoclean表示该模块可以在空闲时自动卸载,中括号中的[lockd]表示模块lockd会引用sunrpc模块的内容。

 

2、模块的装载

模块的装载有两种方法:一种是实用insmod命令手工加载模块,第二种方法是使用内核守护进程kerneld在需要的时候动态装载。insmod命令的格式为:

  insmod //modulename.o

值得注意的是,insmod命令需要知道模块存放的位置,这样才能在内核符号表中进行解析。模块可以位于当前路径中,也可以在insmod命令中指明绝对路径,另外还有几个相关的配置文件可以说明模块的位置。

 

kerneld是一个标准的守护进程,具有超级用户的权限,其主要功能是加载和卸载核心模块, 但是它还可以执行其他任务, 如通过串行线路建立PPP连接并在适当时候关闭它。kerneld自身并不执行这些任务,它通过某些程序如insmod来做此工作。它只是内核的代理,为内核进行调度。这个守护进程仅仅是一个带有超级用户权限的普通用户进程。当系统启动时它也被启动并为内核打开了一个进程间通讯(IPC)通道,内核需要执行各种任务时就使用这个IPC来向kerneld发送消息。例如,如果内核请求现在还没有装载到系统中的文件系统,那么就通知kerneld装载这个文件系统,然后内核就可以使用这个文件系统了。在模块空闲时(即没有其他进程使用这个模块时),kerneld还可以动态卸载这个模块。

需要注意的是,如果模块之间有某种引用关系,那么装载模块时必须遵循一定的次序。例如,上面lsmod显示的结果中lockd模块要引用sunrpc的内容,那么必须首先装载sunrpc之后才能装载lockd,否则就会出错。

 

3、模块的卸载

我们可以使用rmmod命令把模块从系统中卸载出去,该命令的格式为:

  rmmod modulename

需要注意的是,模块只有在空闲时才能够从系统中卸载出去。lsmod输出结果中的Used by一列就说明了模块当前的状态。如果该值不为0,说明模块正忙,不能卸载;否则该值为0,说明模块空闲,可以从系统中卸载出去。对于繁忙的设备,我们首先得断开对应设备的连接,然后才能删除对应的模块。例如,我们要卸载模块rtl8139(这个模块是某机器中rtl8139的以太网卡对应的模块),我们首先要断开网络连接:

  ifdown eth0 /* eth0是摸机器中的第一块网卡*/

 

现在再执行lsmod命令的输出结果为:

  

  Module Size Used by

  lockd 30344 1 (autoclean)

  sunrpc 52132 1 (autoclean) [lockd]

  rtl8139 11748 0 (autoclean)

 

 

说明已经没有设备再使用rtl8139了,我们可以使用

  rmmod rtl8139

命令将其从系统中卸载出去。

标志为autoclean的模块可以自动卸载。前面我们已经提到,模块之间可能会有引用关系。如果A模块引用了B模块的内容,那么必须先装载B模块之后才能成功装载A模块;在卸载B模块之前也要首先卸载A模块,否则就会导致系统的崩溃(当然,如果模块源程序编写的正确,在卸载A模块之前,B模块是无法卸载的)。

 

4、模块实用工具

以上我们介绍的lsmod、insmod、rmmod是一组实用工具所提供的三个命令,这组实用工具一般是和内核版本对应的,其1.3.57版本名为modules(modules-1.3.57.tar.gz),高一点的版本名为modutils(例如modutils-2.4.2.tar.gz)。最好保证你的系统中的模块实用工具的版本号(可以使用modinfo -V命令来查看)不低于内核版本号(可以使用uname -r来查看)。1.3.57版本的modules内容包括modprobe、depmod、genksyms、makecrc32、insmod、rmmod、lsmod、ksyms、kerneld等命令。其中modprobe和insmod命令类似,不过它要依赖于相关的配置文件;depmod用于生成模块依赖文件/lib/modules/kernel-version/modules.dep;genksyms和ksyms与内核函数的版本号有关(由于内核的不断更新,各个版本的内核函数各有不同,为了不会引起系统的崩溃,内核源程序中要对内核函数的版本号进行严格地控制)。在以后版本的实用工具中,使用kmod来取代了kerneld。kmod的功能和kerneld类似,但是它不能自动卸载模块。之所以采用kmod的原因在于kerneld是使用IPC通道实现的,相当于多经过了一层处理,另外kerneld的代码也比较复杂,kmod的代码数量也比kerneld少得多。

 

5、与模块有关的内核编译选项和过程

在使用make confing / make menuconfig / make xconfig对内核进行配置时,和模块有关的选项有:

  Code maturity level options -->

  Prompt for development and/or incomplete code/drivers

此选项为代码的成熟程度。所有新的设计与改进都首先在开发版(版本号为x.y.z,其中y是奇数)中试用,经过验证技术可行之后再在稳定版(版本号为x.y.z,其中y是偶数)中正式引入。尚不成熟或不完善的技术在默认的情况中是不会编译到内核中的,如果希望试验这些内容(例如2.4.*版本中的khttpd、IPV6等),就要选中这个选项。

  >

  Loadable module support -->

  Enable module support

  Set version information on all module symbols

  Kernel module loader

此选项是对可装载内核的支持以及对模块符号的版本号、内核模块装载程序支持的选项。对于其他大部分选项来说,你可以将相应的代码编译到内核中(使用build-in方式),也可以将他们编译成模块(使用module)方式。

 

 

 
### Linux内核编译教程及相关信息 Linux内核的编译是一项复杂但非常重要的任务,它允许用户根据自己的硬件和需求定制操作系统的核心部分。以下是关于Linux内核编译的相关信息和步骤: #### 1. 下载并解压内核源代码 首先需要从官方站点下载最新的稳定版本内核源代码。推荐从以下地址获取: `http://www.kernel.org/pub/linux/kernel/`[^1] 假设下载的文件名为 `linux-x-y-z.tar.gz`,可以使用以下命令解压: ```bash tar -xvzf linux-x-y-z.tar.gz -C /usr/src/ ``` 为避免冲突,建议将现有内核源代码目录重命名或备份。 #### 2. 配置内核选项 进入解压后的内核源代码目录后,需要配置内核选项。可以通过图形界面工具或者命令行工具完成此操作: - 使用菜单配置工具: ```bash make menuconfig ``` - 或者直接复制当前系统的内核配置作为基础: ```bash cp /boot/config-$(uname -r) .config make oldconfig ``` 通过这些工具,可以根据硬件环境和需求裁剪内核功能,从而减少不必要的模块加载[^1]。 #### 3. 编译内核 配置完成后,开始编译内核及其模块- 编译内核: ```bash make -j$(nproc) ``` - 编译模块: ```bash make modules ``` #### 4. 安装内核模块 编译成功后,需要将新编译的内核安装到系统中: - 安装内核: ```bash sudo make install ``` - 安装模块: ```bash sudo make modules_install ``` #### 5. 更新引导加载程序 为了使新编译的内核生效,需要更新引导加载程序(如GRUB)。执行以下命令以更新引导配置: ```bash sudo update-grub ``` #### 6. 重启系统 最后,重启系统以加载新编译的内核: ```bash sudo reboot ``` #### 查看内核编译时间 如果需要查看内核的编译时间,可以通过以下命令实现: ```bash cat /proc/version ``` 该命令会显示内核版本以及编译时间等信息[^1]。 #### 注意事项 在某些情况下,编译完成的内核镜像可能会带有额外的头信息,这可能导致启动时出现异常。例如,`uImage` 文件可能需要调整其下载地址和入口地址,以避免冲突[^3]。 --- ### 示例代码:检查内核版本和编译时间 以下是一个简单的脚本,用于检查当前运行内核的版本和编译时间: ```bash #!/bin/bash echo "当前运行的内核版本及编译时间:" cat /proc/version ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值