本文摘自曼宁出版的Linux in Action第15章。

Linux 使用内核模块管理硬件外围设备。这就是它的工作原理。

正在运行的 Linux 内核是您不想打扰的事情之一。毕竟,内核是驱动计算机所做的一切的软件。考虑到在实时系统上必须同时管理多少细节,最好让内核在尽可能少的干扰下完成其工作。但是,如果不重新启动整个系统就无法对计算环境进行微小的更改,那么插入新的网络摄像头或打印机可能会对您的工作流程造成痛苦的破坏。每次添加设备时都必须重新启动才能让系统识别它,这几乎没有效率。

为了在稳定性和可用性这两个对立的优点之间建立有效的平衡,Linux 隔离了内核,但允许您通过可加载内核模块 (LKM) 动态添加特定功能。如下图所示,您可以将模块视为一个软件,它告诉内核在哪里找到设备以及如何处理它。反过来,内核使设备对用户和进程可用,并监督其操作。

内核模块

图片来源:

内核模块充当设备和 Linux 内核之间的转换器。

没有什么能阻止您编写自己的模块以完全按照您的意愿支持设备,但是为什么要麻烦呢? Linux 模块库已经非常强大,通常不需要自己编写。而且绝大多数时候,Linux 会在你不知情的情况下自动加载新设备的模块。

尽管如此,有时由于某种原因,它不会自行发生。 (你不想让招聘经理不耐烦地等待你的笑脸加入视频会议工作面试太久。)为了帮助解决问题,你需要更多地了解内核模块,特别是,如何找到将运行外围设备的实际模块,然后如何手动激活它。

查找内核模块

按照公认的约定,模块是具有 .ko(内核对象)扩展名的文件,位于/lib/modules/目录下。但是,在您一直导航到这些文件之前,您可能必须做出选择。因为您在启动时可以选择从版本列表中加载一个,所以支持您的选择所需的特定软件(包括内核模块)必须存在于某个地方。嗯,/lib/modules/ 就是其中之一。在那里,您可以找到包含每个可用 Linux 内核版本的模块的目录;例如:

$ ls /lib/模块

4.4.0-101-通用

4.4.0-103-通用

4.4.0-104-通用

在我的情况下,活动内核是具有最高版本号的版本(4.4.0-104-generic),但不能保证对你来说是一样的(内核经常更新)。如果您要使用要在实时系统上使用的模块进行一些工作,则需要确保您拥有正确的目录树。

更多 Linux 资源

  • Linux 命令备忘单

  • 高级 Linux 命令备忘单

  • 免费在线课程:RHEL 技术概述

  • Linux 网络备忘单

  • SELinux 备忘单

  • Linux常用命令备忘单

  • 什么是 Linux 容器?

  • 我们最新的 Linux 文章

好消息:有一个可靠的技巧。与其通过名称来识别目录并希望得到正确的目录,不如使用始终指向活动内核名称的系统变量。您可以使用uname -r调用该变量(-r从通常显示的系统信息中指定内核版本号):

$ unname -r

4.4.0-104-通用

有了这些信息,您可以使用称为_命令替换_的过程将uname合并到您的文件系统引用中。例如,要导航到正确的目录,请将其添加到/lib/modules。要告诉 Linux “uname”不是文件系统位置,请将uname部分括在反引号中,如下所示:

$ ls /lib/modules/`uname -r`

构建 modules.alias modules.dep modules.softdep

initrd 模块.alias.bin 模块.dep.bin 模块.符号

内核 modules.builtin modules.devname modules.symbols.bin

misc modules.builtin.bin modules.order vdso

您会发现大多数模块都组织在kernel/目录下的子目录中。花几分钟浏览这些目录,以了解事物的排列方式和可用的内容。文件名通常可以让您很好地了解您正在查看的内容。

$ ls /lib/modules/`uname -r`/kernel

arch 加密驱动程序 fs 内核 lib mm

网络声音 ubuntu virt zfs

这是定位内核模块的一种方法;实际上,这是一种快速而肮脏的方法。但这不是唯一的方法。如果您想获得完整的集合,您可以使用lsmod列出所有当前加载的模块以及一些基本信息。这个被截断的输出的第一列(这里列出的太多了)是模块名称,然后是文件大小和数量,然后是每个模块所依赖的其他模块的名称:

lsmod

[...]

vboxdrv 454656 3 vboxnetadp、vboxnetflt、vboxpci

rt2x00usb 24576 1 rt2800usb

rt2800lib 94208 1 rt2800usb

[...]

有多少是太多了?好吧,让我们再次运行lsmod,但这一次将输出管道传输到wc -l以获取行数:

$ lsmod | wc -l

113

这些是加载的模块。总共有多少可用?运行modprobe -c并计算行数将为我们提供该数字:

$ modprobe -c | wc -l

33350

有 33,350 个可用模块!?!看起来有人多年来一直在努力为我们提供运行物理设备的软件。

更多 Linux 资源

  • Linux 命令备忘单

  • 高级 Linux 命令备忘单

  • 免费在线课程:RHEL 技术概述

  • Linux 网络备忘单

  • SELinux 备忘单

  • Linux 常用命令备忘单

  • 什么是 Linux 容器?

  • 我们最新的 Linux 文章

注意:在某些系统上,您可能会遇到在/etc/modules文件中使用其唯一条目或作为保存到/etc/modules-load.d/的配置文件引用的自定义模块。这些模块很有可能是当地开发项目的产物,可能涉及尖端实验。无论哪种方式,最好对您正在查看的内容有所了解。

这就是你找到模块的方式。你的下一个工作是弄清楚如果由于某种原因它没有自行发生,如何手动加载非活动模块。

手动加载内核模块

在加载内核模块之前,逻辑要求您必须确认它存在。在你能做到这一点之前,你需要知道它叫什么。获得这部分有时需要同等的魔法和运气,以及在线文档作者辛勤工作的一些帮助。

我将通过描述一段时间前遇到的问题来说明这个过程。一天美好的一天,由于我仍然无法理解的原因,笔记本电脑上的 WiFi 接口停止工作。就这样。也许软件更新将其淘汰。谁知道?我跑了lshw -c network并被处理了这个非常奇怪的信息:

网络无人认领

AR9485 无线网络适配器

Linux 识别出该接口(Atheros AR9485),但将其列为无人认领。好吧,正如他们所说,“当事情变得艰难时,艰难地搜索互联网。”我搜索了 atheros ar9 linux 模块,在筛选了 5 年甚至 10 年的结果,建议我要么编写自己的模块,要么干脆放弃,我终于发现(使用 Ubuntu 16.04,至少)存在一个工作模块。它的名字是ath9k。

是的!战斗和胜利一样好!向内核添加模块比听起来容易得多。要仔细检查它是否可用,您可以针对模块的目录树运行find,指定-type f以告诉 Linux 您正在查找文件,然后添加字符串ath9k和一个全局星号以包含所有以您的字符串开头的文件名:

$ find /lib/modules/$(uname -r) -type f -name ath9k*

/lib/modules/4.4.0-97-generic/kernel/drivers/net/wireless/ath/ath9k/ath9k_common.ko

/lib/modules/4.4.0-97-generic/kernel/drivers/net/wireless/ath/ath9k/ath9k.ko

/lib/modules/4.4.0-97-generic/kernel/drivers/net/wireless/ath/ath9k/ath9k_htc.ko

/lib/modules/4.4.0-97-generic/kernel/drivers/net/wireless/ath/ath9k/ath9k_hw.ko

再上一步,加载模块:

# modprobe ath9k

而已。没有重新启动。别大惊小怪。

这里还有一个示例向您展示如何使用已损坏的活动模块。曾经有一段时间,将我的 Logitech 网络摄像头与特定软件一起使用会使任何其他程序无法访问该摄像头,直到下一次系统启动。有时我需要在不同的应用程序中打开相机,但没有时间关闭并重新启动。 (我运行了很多应用程序,启动后将它们全部安装到位需要一些时间。)

因为这个模块大概是活跃的,使用lsmod搜索单词 video 应该会给我一个关于相关模块名称的提示。事实上,这比提示要好:用 video 一词描述的唯一模块是 uvcvideo(如下所示):

$ lsmod |抓取视频

uvcvideo 90112 0

videobuf2_vmalloc 16384 1 uvcvideo

videobuf2_v4l2 28672 1 uvcvideo

videobuf2_core 36864 2 uvcvideo,videobuf2_v4l2

videodev 176128 4 uvcvideo,v4l2_common,videobuf2_core,videobuf2_v4l2

媒体 24576 2 uvcvideo,videodev

可能是我可以控制的东西导致了崩溃,我想我可以更深入地挖掘一下,看看我是否能以正确的方式解决问题。但你知道它是怎么回事;有时您并不关心理论,只希望您的设备正常工作。因此,我使用rmmod杀死了 uvcvideo 模块并使用modprobe重新启动它,一切都很新鲜:

# rmmod uvcvideo

zz100004 modprobe uvcvideo

再次:没有重新启动。没有顽固的血迹。

Logo

更多推荐