Linux中的DKMS机制
目录
一、DKMS是什么?
二、DKMS解决了什么问题?
三、DKMS出现之前的问题是如何解决的?
四、DKMS是如何解决问题的?
五、DKMS如何处理闭源驱动?
六、DKMS的不足
1.新版本内核头文件接口更新
2.闭源驱动
一、DKMS是什么?
dkms是动态内核模块支持,是一款开源工具,核心功能是当Linux内核版本更新时,自动为新内核重新编译并安装内核模块,确保内核模块与新内核兼容。
二、DKMS解决了什么问题?
前置条件:Linux内核模块与与内核版本是强绑定的。
内核本质是一段运行在内核空间的代码,编译内核模块依赖于内核头文件和配置信息。当内核版本更新时,内核的内部接口(函数定义,结构体数据)、内核编译配置可能会发生变化,或者导致基于旧内核编译的模块无法在新内核中加载,就会出现“insmod: ERROR: could not insert module xxx.ko: Invalid module format”等错误。
dkms解决的核心问题就是当内核版本更新时,避免用户手动编译内核模块,由dkms工具自动编译确保模块与新版本内核兼容。
三、DKMS出现之前的问题是如何解决的?
在dkms出现之前,用户需要手动编译内核模块来确保与新内核兼容。
用户首先需要手动下载内核模块的源码,同时安装新内核的开发包(kernel-devel或kernel-headers),包含重新编译内核模块的头文件和配置;接下来进入模块源码目录,使用makefile工具编译出适配新内核的.ko模块文件;再通过make install或insmod加载模块,并运行depmod更新模块依赖。
四、DKMS是如何解决问题的?
- 模块注册:用户或软件包管理器会将内核模块源码安装到dkms的目录中(/usr/src/<模块名-版本>)中,并在/etc/dkms/<模块名.conf> 中配置模块信息(模块名、版本、支持的内核版本范围等)
- 检测内核更新:当系统通过apt/yum/pacman/dpkg等包管理器工具安装新内核时,新内核头文件会被安装到/lib/modules<新内核版本>/build中,dkms会通过系统服务(dkms.service)自动检测到新内核的存在,并触发dkms模块适配流程
- 自动编译:dkms读取已注册模块的配置,调用make工具,使用新内核头文件(/lib/modules<新内核版本>/build)编译模块源码,生成兼容新内核的.ko文件
- 自动安装:模块编译完成后,dkms会将.ko模块复制到新内核的模块目录下(/lib/modules/<新内核版本>),并运行dpmod -a <新内核版本>更新模块依赖
- 多版本管理:dkms会为所有已安装的内核版本保留对应的模块编译结果,当用户切换到旧内核时,就可以直接加载dkms准备好的兼容模块
五、DKMS如何处理闭源驱动?
对于闭源驱动,厂商不公开完整的源码,只提供驱动的dkms包,包括闭源二进制blob(驱动的核心功能代码,以二进制的形式提供,通常存储为.bin或.o文件)和开源适配层代码(用于连接二进制blob与Linux内核接口的中间代码,此部分代码是开源的,可编译),以及编译脚本makefile和配置文件。
安装此类闭源驱动dkms包完成后,dkms首先会通过dkms add命令将闭源驱动注册到dkms系统中,当检测到内核更新时,dkms会调用厂商提供的makefile脚本,编译适配层源码(如nv.c),生成与新内核接口兼容的目标文件(nv.o);再将目标文件与闭源二进制blob(如nvdia.bin)链接,生成完整的内核模块;最后再通过dkms install将生成的nvidia.ko复制到新内核的模块目录夏,并通过depmod更新模块依赖。
六、DKMS的不足
1.新版本内核头文件接口更新
如果新版本内核头文件的接口更新了,那么dkms即使基于新版本内核头文件编译驱动,也会编译出错。因为旧驱动源码仍然在调用被新内核丢弃或修改的接口。这种情况只能获取最新的驱动源码(通常由硬件厂商或开源社区维护),如果厂商或社区没有更新驱动,那么用户就需要手动修改驱动源码或者回退到旧版本内核。这是dkms的不足之处,dkms只能处理自动化编译的问题。
2.闭源驱动
大量硬件驱动(如NVADIA显卡、无线网卡)是闭源的,仅提供二进制编译工具或预编译脚本。这类驱动虽然可以通过dkms管理,但是一旦与新内核不兼容,用户无法修改驱动源码,只能被动等待厂商适配。
