Dynamic Kernel Module Support
From Wikipedia:
- Dynamic Kernel Module Support (DKMS) is a program/framework that enables generating Linux kernel modules whose sources generally reside outside the kernel source tree. The concept is to have DKMS modules automatically rebuilt when a new kernel is installed.
This means that a user does not have to wait for a company, project, or package maintainer to release a new version of the module. Since the introduction of pacman hooks, the rebuild of the modules is handled automatically when a kernel is upgraded.
Installation
Install the dkms package and the headers for the target kernel/kernels. For example, for the default linux kernel this would be linux-headers. Other kernels have their own respective headers packages.
A good number of modules that lie outside the kernel source tree have a DKMS variant; a few are hosted in the official repositories, most are found in the AUR.
Upgrades
Though the rebuild of the DKMS modules is usually seamless during a kernel upgrade, it may still happen that the rebuild fails. You should pay extra attention to the pacman output. This applies in particular if the system relies on the DKMS module to boot successfully and/or if you use DKMS with a custom kernel not in the official repositories.
To deal with changes in the kernel, fix bugs, or add necessary features consider upgrading the DKMS package before rebooting.
Usage
Usage for invoking DKMS manually.
Tab-completion is available by doing:
# source /usr/share/bash-completion/completions/dkms
List modules
To list the current status of modules, versions and kernels within the tree:
# dkms status
Rebuild modules
Rebuild all modules for the currently running kernel:
# dkms autoinstall
or for a specific kernel:
# dkms autoinstall -k 3.16.4-1-ARCH
To build a specific module for the currently running kernel:
# dkms install -m nvidia -v 334.21
or simply:
# dkms install nvidia/334.21
To build a module for all kernels:
# dkms install nvidia/334.21 --all
Remove modules
To remove a module (old ones are not automatically removed):
# dkms remove -m nvidia -v 331.49 --all
or simply:
# dkms remove nvidia/331.49 --all
If the package dkms is removed the information regarding previous module build files is lost. If this is the case, go through /usr/lib/modules/KERNELVERSION-ARCH
and delete all files and directories no longer in use.
DKMS package creation
Here are some guidelines to follow when creating a DKMS package.
Package name
DKMS packages are named by appending "-dkms" to the original package name.
The variable $_pkgname
is often used below $pkgname
to describe the package name minus the "-dkms" suffix (e.g. _pkgname=${pkgname%-*}
). This is useful to help keep similarities between the original package PKGBUILD and the DKMS variant.
Dependencies
Dependencies should be inherited from the original version with dkms added and linux-headers removed (as it is listed by the dkms package as optional).
Build source location
Build sources should go into (this is the default build directory for DKMS):
/usr/src/PACKAGE_NAME-PACKAGE_VERSION
In the package directory, a DKMS configuration tells DKMS how to build the module (dkms.conf
), including the variables PACKAGE_NAME
and PACKAGE_VERSION
.
-
PACKAGE_NAME
- the actual project name (usually$_pkgname
or$_pkgbase
). -
PACKAGE_VERSION
- by convention this should also be the$pkgver
.
Patching
The sources can be patched either directly in the PKGBUILD or through dkms.conf
.
Module loading automatically in .install
Loading and unloading modules should be left to the user. Consider the possibility a module may crash when loaded.
Also, please note that you do not have to call depmod
explicitly to update the dependencies of your kernel module. Pacman is now calling DKMS dkms install
and dkms remove
automatically as hooks. dkms install
is making sure depmod
is called at the end of its process. dkms install
depends on dkms build
(to build the source against the current kernel), which itself depends on dkms add
(to add a symlink from /var/lib/dkms/<package>/<version>/source
to /usr/src/<package>
).
Example
Here is an example package that edits dkms.conf
according to the package name and version.
PKGBUILD
PKGBUILD
# Maintainer: foo <foo(at)example(dot)org> # Contributor: bar <bar(at)example(dot)org> _pkgbase=example pkgname=example-dkms pkgver=1 pkgrel=1 pkgdesc="The Example kernel modules (DKMS)" arch=('i686' 'x86_64') url="https://www.example.org/" license=('GPL2') depends=('dkms') conflicts=("${_pkgbase}") install=${pkgname}.install source=("${url}/files/tarball.tar.gz" 'dkms.conf' 'linux-3.14.patch') md5sums=(use 'updpkgsums') prepare() { cd ${_pkgbase}-${pkgver} # Patch patch -p1 -i "${srcdir}"/linux-3.14.patch } package() { # Install make DESTDIR="${pkgdir}" install # Copy dkms.conf install -Dm644 dkms.conf "${pkgdir}"/usr/src/${_pkgbase}-${pkgver}/dkms.conf # Set name and version sed -e "s/@_PKGBASE@/${_pkgbase}/" \ -e "s/@PKGVER@/${pkgver}/" \ -i "${pkgdir}"/usr/src/${_pkgbase}-${pkgver}/dkms.conf # Copy sources (including Makefile) cp -r ${_pkgbase}/* "${pkgdir}"/usr/src/${_pkgbase}-${pkgver}/ }
dkms.conf
dkms.conf
PACKAGE_NAME="@_PKGBASE@" PACKAGE_VERSION="@PKGVER@" MAKE[0]="make --uname_r=$kernelver" CLEAN="make clean" BUILT_MODULE_NAME[0]="@_PKGBASE@" DEST_MODULE_LOCATION[0]="/kernel/drivers/misc" AUTOINSTALL="yes"
.install
Now pacman has DKMS hooks implemented, you do not have to specify DKMS-specific configuration in your .install file. Calls to dkms install
and dkms remove
will be automatic.
Initial ramdisk
In case you've got any kernel modules installed via DKMS that are used in initial ramdisk, e.g. zfs-dkmsAUR, you may want to write a pacman hook to automate the process of regenerating initramfs image(s).
For example, when using linux and mkinitcpio, to update ZFS module after each zfs-dkmsAUR upgrade,
/etc/pacman.d/hooks/90-mkinitcpio-dkms-linux.hook
[Trigger] Operation=Install Operation=Upgrade Operation=Remove Type=Package Target=zfs-dkms Target=linux [Action] Description=Update dkms modules in Linux initcpio Depends=mkinitcpio When=PostTransaction NeedsTargets Exec=/bin/sh -c 'while read -r trg; do case $trg in linux) exit 0; esac; done; /usr/bin/mkinitcpio -p linux'
You may add more targets to the hook and make additional copies of the hook if you've installed other kernels. Note the 90-
prefix is necessary to make sure it runs after the DKMS hooks.