最近遇到一个麻烦的问题,几台服务器在升级内核之后,新的内核启动直接panic,无法正常驱动raid卡. 通过进入ramos,发现新的内核里面没有对应的raid卡驱动ko文件. 后面才发现老的内核中rraid卡驱动是从源代码单独编译出来的. 换了新的kernel之后,忘了给新的内核重新编译这个驱动就重启了,导致kernel panic.
在linux中,每个驱动ko文件是与一个特定内核绑定的,也就是在老内核下面编译的驱动在新内核下面无法使用,同样的,在新内核下面编译的驱动在老内核也无法使用.
在linux kernel源代码树中,已经包含了我们常见的很多驱动,那么在安装一个新的内核rpm包的时候,这些驱动也就被一起安装了. 但是有些驱动不在源代码树里面,这些驱动需要手动编译安装;还有一些驱动虽然在源代码树中,但是源代码树中的可能太老了,新的驱动也需要单独编译安装.
使用dkms来管理源代码树外的驱动dkms就是用来处理在kernel源代码树中不存在的驱动,或者我们自己维护的驱动的. 它可以保证新的kernel安装之后,这些驱动被自动重新编译,自动运行depmod命令,自动生成新的initram文件.
dkms这个工具存在于epel源中,需要先保证epel打开,然后yum -y install dkms就可以安装这个工具了.使用rpm -ql dkms看下这个包安装了什么东西.
/usr/sbin/dkms是dkms命令行本身,是一个bash脚本.我们用的最多的是dkms status,用来查看当前dkms管理的驱动的状态
/var/lib/dkms是dkms工作目录.
/etc/kernel/目录下面的两个文件,分别是postinst和prerm的kernel hook,dkms自动管理驱动核心就是这两个文件.
现在大部分驱动rpm包都有两种形式的,一种是直接针对rhel特定版本(也就是特定内核)编译好的. 还有就是一个dkms enabled的rpm包.
下面以megaraid_sas-07.710.06.00-1dkms.noarch.rpm这个dkms enabled包为例来操作.什么是dkms enabled的rpm包呢
首先,这个rpm安装文件的路径一定是/usr/src/module-version目录,比如这儿的/usr/src/megaraid_sas-07.710.06.00,然后这个包里面一定有一个dkms.conf文件.
因为dkms工作的时候需要读取这个dkms.conf文件,这个文件实际是一个shell脚本,dkms工作的时候会source进去.
我们看下安装这个包的时候具体会做的事情
安装之前,dkms status输出为空,表示没有管理任何驱动
这个包安装的时候,会看到dkms add,dkms build(编译驱动),dkms install(把编译好的驱动安装到/lib/modules/`uname -r`目录下),跑depmod,跑dracut重新生成initramfs的过程(如果手动装驱动,就是这些过程)
dkms enabled包的scripts,里面是核心的dkms命令
dkms enabled包的安装过程,能看到关键的步骤被执行
如果dkms只是能帮我们执行这些命令,那么其实用处也不大. dkms最主要的用处是当我们安装了一个新的kernel包之后,其会用到kernel hook给我们自动重新给新内核完成上面的事情.
dkms使用kernel hook自动管理驱动在我们安装了这个dkms enabled的驱动包之后,我们安装一个新的内核
能看到这个新的kernel包安装的过程中跑了一些脚本.
完成之后,dkms status直接显示新的内核直接把这个驱动包安装上了.
dkms的工作目录/var/lib/dkms也显示这个驱动包安装到了新的内核.
那么dkms在安装新的内核包的时候,怎么触发给新的内核包重新编译驱动的呢?
我们看下内核包的scripts,发现里面有对/usr/sbin/new-kernel-pkg脚本的调用
而/usr/sbin/new-kernel-pkg里面有对/etc/kernel/postinst.d/目录下的脚本进行调用的逻辑.
dkms给/etc/kernel/postinst.d下面安装了脚本
这个脚本里面调用/usr/lib/dkms/dkms_autoinstaller进行自动安装
dkms_autoinstaller调用dkms autoinstall,在autoinstall中,会对当前所有状态为installed,并且dkms.conf配置汇总AUTOINSTALL=yes的模块对安装的内核进行编译安装.
总结dkms是dell做的一个自动管理kernel源代码树外的驱动框架,现在大量用于各种硬件,特别是存储硬件的驱动管理中. 其使用方法特别简单,只需要将一个dkms enabled的源代码包安装即可. 后面的事情就是dkms自己处理了. 大家找硬件驱动包的时候可以找dkms enabled的,如果没有也可以从源代码用tarball的方式导入,自己再加个dkms.conf就可以了.