Linux 模块管理方法之 DKMS

本文将描述 DKMS 是什么、怎么用、有哪些问题。

一、DKMS 是什么

如果要问 Linux 内核模块如何发布、安装。脑回路的第一反应肯定是 make && insmod。

上述方法可以满足嵌入式场景,因为嵌入式产品的软件是整体发布,包括:内核、模块、软件等交付件。但是在 PC/服务器 领域,各个组件都是互相独立的,如果一个模块基于内核 A 编译并发布,那用户更改内核后,之前发布的内核模块就不能用了。

所以,DELL 发布了 DKMS,全称 Dynamic Kernel Module System。可以做到内核变更后自动编译模块,适配新内核。

二、DKMS 怎么用

DKMS 既是软件包也是规范,使用 DKMS 必须遵守 DKMS 约定的规范。下面我们以一个可编译的内核模块为例说明 DKMS 怎么用。

DKMS 模块代码目录

DKMS 模块代码目录位于 /usr/src/modulename-version,比如:/usr/src/tinylab-1.0.0,表示 tinylab 模块的 1.0.0 版本。

DKMS 模块安装

前提:有一个可编译的内核模块,且目录符合 DKMS 规范

root@llc-vpc:/home/llc/tmp/module# tree /usr/src/tinylab-1.0.0/
/usr/src/tinylab-1.0.0/
├── Makefile
└── tinylab.c

0 directories, 2 files

添加 dkms.conf

root@llc-vpc:/usr/src/tinylab-1.0.0# cat dkms.conf 
PACKAGE_NAME="tinylab"
PACKAGE_VERSION="1.0.0"
CLEAN="make clean"
MAKE[0]="make all"
BUILT_MODULE_NAME[0]="tinylab"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"

字段含义还比较清晰,设置模块名,编译方法。最重要的就是 AUTOINSTALL 字段,表示内核变更时要重新编译模块。

DKMS ADD:将模块纳入 DKMS 管辖

root@llc-vpc:/usr/src/tinylab-1.0.0# dkms add -m tinylab -v 1.0.0

Creating symlink /var/lib/dkms/tinylab/1.0.0/source ->
                 /usr/src/tinylab-1.0.0

DKMS: add completed.

DKMS INSTALL:编译 && 安装

root@llc-vpc:/usr/src/tinylab-1.0.0# dkms install -m tinylab -v 1.0.0
...
   - Installing to /lib/modules/5.4.0-62-generic/updates/dkms/
...

PS:install 命令会自动执行 build,也可以手动执行 build 后,再执行 install。

dkms build -m tinylab -v 1.0.0
dkms install -m tinylab -v 1.0.0

DKMS REMOVE:删除模块产出,同时将模块移出 DKMS 管理

//第一次查看 status,可以看到 tinylab 模块状态为 installed
root@llc-vpc:/usr/src/tinylab-1.0.0# dkms status
tinylab, 1.0.0, 5.4.0-62-generic, x86_64: installed
root@llc-vpc:/usr/src/tinylab-1.0.0# 
root@llc-vpc:/usr/src/tinylab-1.0.0# dkms remove -m tinylab -v 1.0.0 --all

//remvoe 后查看 status,什么都看不到,说明 tinylab 模块被移除
root@llc-vpc:/usr/src/tinylab-1.0.0# dkms status
root@llc-vpc:/usr/src/tinylab-1.0.0#

总结

从上面的分步操作中可以看到基于 DKMS 编译、安装模块的几个步骤:ADD、BUILD、INSTALL。

但是上面介绍的命令并不具备产品发布能力,因为总不能全部手动操作吧。所以 DKMS 具备产出 deb/rpm 包的能力。以 deb 包为例,DKMS 产出 deb 包后,通过 dpkg -i module.deb 可以实现:

  1. 代码自动安装至 /usr/src 目录
  2. 自动 ADD/BUILD/INSTALL

产出 deb 包的命令: dkms mkdeb -m tinylab -v 1.0.0 --source-only

三、实际使用中的疑问与问题

  • 模块如何自动加载

严格说,这不是 DKMS 的问题,而是 Linux 模块自动加载机制的问题。这里简单描述一下。

关于模块机制就简单描述,大家 high level 理解一下即可,不是本文重点。

Linux 基于 module alias 机制实现模块自动加载,module alias 是模块代码中硬性指定的,就像 MODULE_LICENSE 一样。以 PCIE 设备为例,PICE 设备都有自己的 vendor_id、device_id,通过 MODULE_DEVICE_TABLE 为 PCIE 设备驱动模块添加 alias。

当 PCIE 设备添加到系统时会向系统发送 uevent 消息。这里的 uevent 消息除了包括设备号,设备名称外,还包括 module alias。用户态的 udev 机制会基于 uevent 添加设备节点,同时也会根据 uevent 中携带的 module alias 信息进行模块匹配和模块加载。

这也是为什么内核支持了 devtmpfs 后还需要 udev 机制的一个原因。

module alias 的模样

llc@llc-vpc:/usr/src/tinylab-1.0.0$ modinfo e1000
...
alias:          pci:v00008086d00002E6Esv*sd*bc*sc*i*

module alias 的含义

alias:          pci:v00008086d00002E6Esv*sd*bc*sc*i*

拆开后如下:

v00008086 --- vendor id
d00002E6E --- device id
sv*       --- sub vendor id, * 表示任意
sd*       --- sub device id, * 表示任意
bc*       --- base class, * 表示任意
sc*       --- sub class, * 表示任意
i*        --- programming interface, * 表示任意,不知道啥意思,很少用
  • 内核更新后如何触发 DKMS 编译

DKMS 安装后会生成两个新文件 /etc/kernel/postinst.d/dkms 与 /etc/kernel/header_postinst.d/dkms,这两个文件内容一样,会执行 dkms_autoinstaller,将 DKMS 管理的模块编译。在内核安装完成后,即 deb 包安装的 postinst 阶段,会执行 /etc/kernel/postinst.d/ 里面的脚本,这样 dkms 脚本就被执行到了。

头文件安装同理。

  • 系统有 4.19/5.4 两个内核,基于 DKMS 在 5.4 下编译模块后,重启系统切换到 4.19 内核,模块会重新编译吗?

不会,因为 DKMS 自动编译只能通过内核更新或内核头文件更新触发。

如果需要为系统所有已安装内核同时编译模块,需要修改 /etc/dkms/framework.conf 将 autoinstall_all_kernels 设置为非 0 值。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang_anna

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值