1.2. 模块如何进入内核?

你可以通过运行 lsmod 命令查看哪些模块已经被加载到内核中,lsmod 通过读取以下文件获取信息/proc/modules.

这些模块是如何进入内核的呢?当内核需要一个内核中没有的功能时,内核模块守护进程 kmod[1] 会执行 modprobe 来加载模块。modprobe 接收一个字符串,字符串有两种形式

如果 modprobe 收到一个通用标识符,它首先会在以下文件中查找该字符串/etc/modules.conf。如果它找到类似这样的别名行

   alias char-major-10-30 softdog
	

它就知道这个通用标识符指的是模块softdog.o.

接下来,modprobe 会查看以下文件/lib/modules/version/modules.dep,以查看在加载请求的模块之前是否必须加载其他模块。此文件由 depmod -a 创建,包含模块依赖关系。例如,msdos.o需要fat.o模块已经被加载到内核中。如果另一个模块定义了请求模块使用的符号(变量或函数),则请求的模块依赖于另一个模块。

最后,modprobe 使用 insmod 首先将任何先决条件模块加载到内核中,然后加载请求的模块。modprobe 指示 insmod 到/lib/modules/version/[2],这是模块的标准目录。insmod 在模块的位置方面相当简单,而 modprobe 则知道模块的默认位置。因此,例如,如果您想加载 msdos 模块,您必须运行

    insmod /lib/modules/2.5.1/kernel/fs/fat/fat.o
    insmod /lib/modules/2.5.1/kernel/fs/msdos/msdos.o
	

或者直接运行 “modprobe -a msdos”。

Linux 发行版以名为 modutils 或 mod-utils 的软件包形式提供 modprobe、insmod 和 depmod。

在结束本章之前,让我们快速看一下一段/etc/modules.conf:

    #This file is automatically generated by update-modules
    path[misc]=/lib/modules/2.4.?/local
    keep
    path[net]=~p/mymodules
    options mydriver irq=10
    alias eth0 eepro
	

以 '#' 开头的行是注释。空行将被忽略。

这个path[misc]行告诉 modprobe 将 misc 模块的搜索路径替换为目录/lib/modules/2.4.?/local。正如你所看到的,shell 元字符被支持。

这个path[net]行告诉 modprobe 在目录中查找 net 模块~p/mymodules,但是,在path[net]指令之前的 "keep" 指令告诉 modprobe 将此目录添加到 net 模块的标准搜索路径,而不是像我们对 misc 模块所做的那样替换标准搜索路径。

alias 行表示加载eepro.o每当 kmod 请求加载通用标识符 `eth0' 时。

你不会在/etc/modules.conf中看到像 "alias block-major-2 floppy" 这样的行,因为 modprobe 已经知道大多数系统上将使用的标准驱动程序。

现在你知道模块是如何进入内核的了。如果你想编写依赖于其他模块的自己的模块(我们称之为“堆叠模块”),那么还有更多的内容。但这必须等到以后的章节。在解决这个相对高级的问题之前,我们还有很多内容要介绍。

1.2.1. 在我们开始之前

在我们深入研究代码之前,我们需要讨论几个问题。每个人的系统都不同,每个人都有自己的习惯。让你的第一个 “hello world” 程序正确编译和加载有时可能很棘手。请放心,在您第一次克服最初的障碍之后,一切都将一帆风顺。

1.2.1.1. 模块版本控制

如果您启动不同的内核,则为某个内核编译的模块将不会加载,除非您启用CONFIG_MODVERSIONS在内核中。我们将在本指南的后面部分介绍模块版本控制。在我们介绍模块版本控制之前,如果您运行的内核启用了模块版本控制,则本指南中的示例可能无法工作。但是,大多数 Linux 发行版内核都默认启用它。如果您因版本控制错误而无法加载模块,请编译一个禁用模块版本控制的内核。

1.2.1.2. 使用 X

强烈建议您键入、编译和加载本指南讨论的所有示例。还强烈建议您从控制台执行此操作。您不应该在 X 环境中处理这些东西。

模块不能像printf()一样打印到屏幕,但它们可以记录信息和警告,这些信息和警告最终会打印在您的屏幕上,但仅在控制台上。如果您从 xterm 中 insmod 一个模块,信息和警告将被记录,但仅记录到您的日志文件中。除非您查看日志文件,否则您看不到它。为了立即访问此信息,请从控制台完成所有工作。

1.2.1.3. 编译问题和内核版本

通常,Linux 发行版会分发以各种非标准方式修补过的内核源代码,这可能会导致问题。

更常见的问题是,一些 Linux 发行版分发不完整的内核头文件。您需要使用 Linux 内核中的各种头文件来编译代码。墨菲定律指出,缺少的头文件正是您模块工作所需的头文件。

为了避免这两个问题,我强烈建议您下载、编译并启动到一个全新的、标准的 Linux 内核,该内核可以从任何 Linux 内核镜像站点下载。有关更多详细信息,请参阅 Linux 内核 HOWTO。

具有讽刺意味的是,这也可能导致问题。默认情况下,您系统上的 gcc 可能会在其默认位置查找内核头文件,而不是您安装新内核副本的位置(通常在/usr/src/。这可以通过使用 gcc 的-I开关来解决。

注释

[1]

在早期版本的 Linux 中,这被称为 kerneld。

[2]

如果您正在修改内核,为了避免覆盖您现有的模块,您可能需要使用EXTRAVERSION内核 Makefile 中的变量来创建一个单独的目录。