当前位置: 首页 > news >正文

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 值。

相关文章:

  • 【由果索因】模块化代码后,这样的JavaScript技巧才值得用
  • 计算机网络知识点总结(每日更新)
  • 免费题库接口
  • 盘点十个让工作效率倍增且有趣的 Python工具包
  • 内联函数——C++
  • 数据结构-线性表
  • vue3.0--2.watch、vue3生命周期函数、Teleport、自定义事件、状态驱动的动态 CSS、Suspense
  • Java · 面向对象编程 · 包的概念 · 继承 · 组合
  • Zabbix6通过ODBC方式监控Oracle 19C最佳实践
  • 企业复杂的数据治理需求,TempoDF让数据开发更简单!
  • hive on spark 执行sql报错
  • 离散化(保序)
  • 文本纠错易语言代码
  • 【python】遇上COS美图怎么办?当然是大胆冲呀~
  • 苏小妍java开发工程师-一面面经
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • css布局,左右固定中间自适应实现
  • gitlab-ci配置详解(一)
  • Java的Interrupt与线程中断
  • JS笔记四:作用域、变量(函数)提升
  • js如何打印object对象
  • mysql中InnoDB引擎中页的概念
  • 产品三维模型在线预览
  • 大主子表关联的性能优化方法
  • 分布式事物理论与实践
  • 你真的知道 == 和 equals 的区别吗?
  • 区块链分支循环
  • 全栈开发——Linux
  • 时间复杂度与空间复杂度分析
  • 网络应用优化——时延与带宽
  • 温故知新之javascript面向对象
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • 【云吞铺子】性能抖动剖析(二)
  • 如何在招聘中考核.NET架构师
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • #WEB前端(HTML属性)
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (4.10~4.16)
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (学习日记)2024.01.19
  • (转)ABI是什么
  • (转)nsfocus-绿盟科技笔试题目
  • ******之网络***——物理***
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .net 后台导出excel ,word
  • .netcore如何运行环境安装到Linux服务器
  • /etc/fstab 只读无法修改的解决办法
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构