Linux如何加载内核模块(.ko)?

Linux内核模块(Kernel Object,后缀为.ko)是Linux系统中实现动态扩展内核功能的核心机制,允许在不重新编译内核的情况下添加驱动程序、文件系统支持或系统调用等功能,加载.ko模块是系统管理员和开发者常见的操作,其过程涉及模块编译、依赖管理、参数传递及内核交互等多个环节,以下将详细阐述Linux加载.ko模块的完整流程、关键命令及注意事项。

linux如何加载ko

内核模块的基础概念

Linux内核采用宏内核架构,但通过模块机制实现了“内核核心功能+动态扩展”的灵活设计,模块本质上是编译后的目标文件(.ko),包含初始化函数(在模块加载时执行)和清理函数(在模块卸载时执行),与内核核心通过符号表(导出/导入函数和变量)交互,模块加载后,其代码和数据会集成到内核空间,成为内核的一部分,因此需确保模块来源可靠,避免系统不稳定。

模块的编译与准备

加载.ko模块的前提是正确编译出符合当前内核版本的模块文件,编译过程需依赖内核头文件(kernel headers)和构建工具(如make、gcc)。

安装依赖工具

以Ubuntu/Debian为例,需安装以下包:

sudo apt install build-essential linux-headers-$(uname -r)

linux-headers-$(uname -r)提供了当前内核版本的头文件,确保模块与内核兼容。

编写模块代码与Makefile

以简单的“Hello World”模块为例,创建hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void) {
    printk(KERN_INFO "Hello, Linux module!n");
    return 0;
}
static void __exit hello_exit(void) {
    printk(KERN_INFO "Goodbye, Linux module!n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");  // 许可证声明(避免内核taint警告)
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World module");

创建Makefile(与hello.c同目录):

obj-m += hello.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

执行make编译后,生成hello.ko文件。

模块加载的常用方法

加载.ko模块主要有三种方式:insmod(直接加载)、modprobe(智能加载,处理依赖)和通过配置文件自动加载(系统启动时加载)。

使用insmod命令直接加载

insmod是最基础的加载命令,需指定模块的绝对路径,不处理模块依赖关系,适用于无依赖的简单模块。

语法

sudo insmod /path/to/module.ko [param=value ...]

示例

sudo insmod ./hello.ko

特点

  • 需手动解决依赖问题(若模块依赖其他未加载模块,会失败)。
  • 加载时可通过命令行传递参数(需模块代码中定义参数,如module_param(name, int, 0644))。

使用modprobe命令智能加载

modprobe是更推荐的加载工具,属于module-init-toolskmod包,功能包括:

linux如何加载ko

  • 自动解析模块依赖关系(通过modules.dep文件),按顺序加载依赖模块;
  • 支持模块别名(alias),可通过别名加载模块;
  • 支持从/lib/modules/$(uname -r)/kernel/目录查找模块(无需绝对路径)。

语法

sudo modprobe [module_name] [param=value ...]

示例

sudo modprobe hello  # 假设hello.ko已复制到/lib/modules/$(uname -r)/kernel/misc/或/etc/modprobe.d/配置的路径

依赖管理
modprobe依赖/lib/modules/$(uname -r)/modules.dep文件,该文件由depmod命令生成,若新增模块或更新内核,需运行:

sudo depmod -A  # 更新依赖关系

通过配置文件自动加载

若需系统启动时自动加载模块,可通过以下方式配置:

(1) /etc/modules-load.d/目录

在该目录下创建.conf文件(如my_module.conf),写入模块名(每行一个):

echo "hello" | sudo tee /etc/modules-load.d/my_module.conf

系统启动时,systemd会读取此文件并自动加载模块。

(2) /etc/modprobe.d/目录(配置模块参数

若需指定模块参数,可在此目录下创建配置文件(如hello.conf):

options hello debug=1  # 设置模块参数

参数会在模块加载时自动生效。

模块加载的验证与管理

加载模块后,需验证加载状态、查看日志及管理模块生命周期。

验证模块是否加载

  • lsmod命令:列出已加载的模块,显示模块大小、依赖关系等。

    lsmod | grep hello

    输出示例:

    hello 16384 0 - Live 0xffffffc000800000 (POE)
  • /proc/modules文件:内核内部模块信息表,内容与lsmod一致,可直接查看:

    cat /proc/modules | grep hello
  • dmesg命令:查看内核日志,模块加载时会打印printk输出:

    linux如何加载ko

    dmesg | tail -n 5  # 查看最近5条日志

    若模块加载成功,会看到“Hello, Linux module!”的日志。

查看模块信息

使用modinfo命令查看模块的详细信息,包括作者、描述、参数、许可证等:

modinfo hello.ko

输出示例:

filename:       /path/to/hello.ko
license:        GPL
author:         Your Name
description:    A simple Hello World module
srcversion:     XXXXXXXXXX
depends:        
retpoline:      Y
name:           hello
vermagic:       5.15.0-88-generic SMP mod_unload modversions

模块参数传递

模块可通过module_param宏定义参数,加载时通过insmodmodprobe传递,若模块代码中定义:

static int debug_level = 0;
module_param(debug_level, int, 0644);

加载时可指定参数:

sudo modprobe hello debug_level=2

参数也可在运行时通过/sys文件系统修改:

echo 3 | sudo tee /sys/module/hello/parameters/debug_level

模块的卸载

使用rmmod命令卸载

rmmod用于卸载已加载的模块,需指定模块名(不含.ko后缀):

sudo rmmod hello

若模块被其他程序或内核功能占用,卸载会失败,可通过lsmod查看依赖关系。

使用modprobe -r卸载

modprobe -r可卸载模块及其依赖(需确保依赖模块无其他使用者):

sudo modprobe -r hello

加载失败的常见问题排查

问题现象 可能原因 解决方案
模块版本与内核不匹配 编译模块使用的内核头文件与运行内核不一致 重新安装对应内核版本的linux-headers并编译模块
依赖模块未加载 模块依赖的其他模块未加载 使用modprobe加载依赖模块,或手动insmod依赖模块
模块签名验证失败 内核开启模块签名验证(CONFIG_MODULE_SIG) 禁用签名验证(临时:sudo echo 0 > /proc/sys/kernel/modules/signature)或为模块签名
参数类型或值错误 传递的参数与模块定义的类型不匹配 检查模块代码中参数定义(如intcharp),确保参数值合法

相关问答FAQs

Q1: 加载模块时提示“Invalid module format”怎么办?
A: 通常是因为模块编译时使用的内核头文件版本与当前运行内核版本不一致,解决方法:安装当前内核对应的头文件包(如linux-headers-$(uname -r)),然后重新编译模块,若问题仍存在,检查内核是否开启了特定配置(如CONFIG_MODVERSIONS),确保编译时启用-DMODVERSIONS选项并包含linux/version.h

Q2: 如何查看模块被哪些进程或功能占用?
A: 若rmmod提示“Module is in use”,可通过以下方式排查占用者:

  1. 查看/proc/modules中模块的Usecount字段(非0表示被占用);
  2. 使用lsof命令查找占用模块的文件(如lsof | grep module_name);
  3. 对于内核模块,可通过grep -r "module_name" /proc/*/maps查看哪个进程映射了模块内存;
  4. 若为驱动模块,可检查/sys/module/module_name/holders目录,显示持有模块的设备实例。

原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/30970.html

(0)
酷番叔酷番叔
上一篇 2025年9月26日 22:25
下一篇 2025年9月26日 22:44

相关推荐

  • Linux跑XP虚拟机,U盘传数据卡住?

    基础环境准备宿主机检测U盘lsusb # 查看U盘是否被Linux识别(记录厂商ID和产品ID)lsblk # 确认U盘挂载点(如/dev/sdb1)若未自动挂载,手动挂载: sudo mkdir /mnt/usb && sudo mount /dev/sdb1 /mnt/usb虚拟机软件选择V……

    2025年7月18日
    11800
  • 如何生成phd文件 linux

    Linux中,可使用文本编辑器(如vim、nano等)创建文件并保存为`.

    2025年8月19日
    9900
  • 为什么必须用固定网络地址?

    在Linux系统中固定IP地址是服务器管理、网络配置的常见需求,尤其适用于避免DHCP动态分配导致的IP变化,确保服务稳定访问,以下是详细操作指南,涵盖主流发行版(Ubuntu/Debian/CentOS)的两种主流方法:稳定性:服务器、NAS等设备需永久地址供外部访问,端口转发:路由器需固定IP映射端口(如S……

    2025年6月23日
    11700
  • Linux命令界面如何返回?终端返回命令与操作步骤详解

    Linux命令界面中的“返回”操作涵盖多个场景,包括目录层级返回、命令历史返回、终端会话返回等,不同场景对应不同命令,掌握这些操作可大幅提升命令行操作效率,以下从常见场景出发,详细说明各类返回方法及注意事项,目录层级返回:文件系统中的“返回”在Linux文件系统中,“返回”最常用于目录层级切换,核心命令为cd……

    2025年10月5日
    7700
  • 如何进入Linux GRUB引导菜单页面?

    Linux系统的GRUB(Grand Unified Bootloader)是引导加载程序,负责在开机时加载操作系统内核,进入GRUB页面可以修改启动参数、选择不同的操作系统 entry 或修复系统问题,是Linux系统管理和故障排查的重要入口,以下是进入GRUB页面的详细方法及注意事项,开机时快速按下特定按键……

    2025年9月22日
    10900

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN

关注微信