在 Ubuntu 14.04 上,我发现当我不插入外部无线适配器时,其模块rt2800usb
仍然显示在lsmod
.
什么时候会自动加载驱动模块?是在设备连接到计算机时,还是在操作系统启动时?
什么时候会自动卸载驱动模块?是当设备与计算机断开连接时,还是当操作系统关闭时?
答案1
当内核检测到新设备时,它会运行该程序modprobe
并向其传递一个标识设备的名称。大多数设备通过供应商和型号的注册号码来识别,例如PCI或者USB身份标识。该modprobe
程序查阅模块别名表来查找包含该特定设备的驱动程序的文件的名称。类似的原则适用于非硬件设备的驱动程序,例如文件系统和加密算法。有关更多详细信息,请参阅/lib/modules/VERSION/modules.alias
Debian 重启后未检测到串行 PCI 卡
一旦 modprobe 确定了哪个模块文件 ( .ko
) 包含所请求的驱动程序,它就会将模块文件加载到内核中:模块代码是动态加载进入内核。如果模块加载成功,它将出现在 的列表中lsmod
。
当内核检测到新的可热插拔硬件时(例如,当您连接 USB 外围设备时),会自动加载模块。操作系统还会在启动初期枚举系统上存在的所有硬件,以便加载启动时存在的外围设备的驱动程序。
也可以使用modprobe
或insmod
命令手动请求加载模块。大多数发行版都包含一个启动脚本,用于加载 中列出的模块/etc/modules
。加载模块的另一种方式是如果它们是模块的依赖项:如果模块 A 依赖于模块 B,则modprobe A
在加载 A 之前加载 B。
加载模块后,即使使用该驱动程序的所有设备都已断开连接,它也会保持加载状态,直到显式卸载为止。很久以前,有一种自动卸载未使用模块的机制,但如果我没记错的话,当 udev 出现时,它被删除了。我怀疑自动模块卸载不是一个常见的功能,因为往往需要它的系统大多是拥有大量内存的台式电脑(在驱动程序代码的规模上)。
答案2
系统启动时通过以下方式加载模块初始 RAM 磁盘,又名 initrd。基本原理部分指出:
许多 Linux 发行版都提供一个通用的 Linux 内核映像,该映像是发行版开发人员专门为在各种硬件上启动而创建的。此通用内核映像的设备驱动程序作为可加载内核模块包含在内,因为将许多驱动程序静态编译到一个内核中会导致内核映像变得更大,可能太大而无法在内存有限的计算机上启动。这就提出了检测和加载在引导时安装根文件系统所需的模块的问题,或者就此而言,推断根文件系统在哪里或是什么。
Ubuntu 与许多其他发行版一样,选择将每个设备驱动程序加载到此 initrd 中,无论是否需要该驱动程序,也无论该设备是否存在于系统上。正如 Giles 指出的那样,整个东西都被加载到 RAM 中,然后在启动时检测使用的模块,并将未使用的模块从 RAM 中删除。使用这种方法可以确保 Ubuntu 始终在任何系统上启动,无论设置如何。 Ubuntu 使用微内核结构来模仿整体内核。看这样做的原因
- 该模块
rt2800usb
将始终在启动时加载,因为该模块已包含在初始化文件系统吉尔斯提到的。 initramfs 是 initrd 的后继者,因此它始终以 表示lsmod
。请注意,您可以通过使用modprobe
后跟模块名称将新编译的模块插入到内核中。
作为测试,请在拔掉无线适配器的情况下重新启动系统。如果一切顺利,该模块将不会列在lsmod
s 输出中,因为在启动期间,由 initramfs 启动的检测过程和 init sstem 在探测期间未找到该设备,并且该模块已从 RAM 中删除。
- 要在系统运行时删除模块,您可以使用
rmmod
、 或等命令,modprobe -r
后跟模块名称。下次启动时,该模块将重新加载。往上看。在大多数情况下,不会动态删除模块,因为这会禁用热插拔,即一旦删除模块,重新插入时就无法再次检测到使用该模块的设备。
为了从 中删除模块lsmod
,您必须从 initramfs 映像中删除它,该映像是通过重新编译不带所选模块的内核然后重建映像而创建的。这样做会禁用该模块的所有检测。