Dynamic Kernel Module Support (DKMS)


To totally unlock this section you need to Log-in


Login

DKMS, a system designed to help Dell Computer Corporation distribute fixes to its customers in a controlled fashion, also speeds driver development, testing and validation for the entire community.

The DKMS framework is basically a duplicate tree outside of the kernel tree that holds module source and compiled module binaries. This duplication allows for a decoupling of modules from the kernel, which, for Linux solution and deployment providers, is a powerful tool.

The power comes from permitting driver drops onto existing kernels in an orderly and supportable manner. In turn, this frees both providers and their customers from being bound by kernel drops to fix their issues. Instead, when a driver fix has been released, DKMS serves as a stopgap to distribute the fix until the code can be merged back into the kernel.

Staying with the customer angle for a bit longer, DKMS offers other advantages. The business of compiling from source, installing or fidgeting with rebuildable source RPMs has never been for the faint-of-heart. The reality is that more Linux users are coming in with less experience, necessitating simpler solutions. DKMS bridges these issues by creating one executable that can be called to build, install or uninstall modules.

Further, using its match feature, configuring modules on new kernels could not be easier, as the modules to install can be based solely on the configuration of some kernel previously running. In production environments, this is an immense step forward as IT managers no longer have to choose between some predefined solution stack or the security enhancements of a newer kernel.

DKMS also has much to offer developers and veteran Linux users. The aforementioned idea of the decoupling of modules from the kernel through duplication (not complete separation) creates a viable test bed for driver development. Rather than having to push fixes into successive kernels, these fixes can be distributed and tested on the spot and on a large scale.

This speedup in testing translates to an overall improvement in the speed of general development. By removing kernel releases as a blocking mechanism to widespread module code distribution, the result is better tested code that later can be pushed back into the kernel at a more rapid pace—a win for both developers and users.

DKMS also makes developers' lives easier by simplifying the delivery process associated with kernel-dependent software. In the past, for example, Dell's main method for delivering modules was RPMs containing kernel-specific precompiled modules.

As kernel errata emerged, we often were taken through the monotonous and unending process of recompiling binaries for these new kernels—a situation that no developer wants to be in. However, Dell still favored this delivery mechanism because it minimized the amount of work and/or knowledge customers needed to have to install modules. With DKMS, we can meet these usability requirements and significantly decrease our workload from the development standpoint. DKMS requires module source code to be located only on the user's system.

The DKMS executable takes care of building and installing the module for any kernel users may have on their systems, eliminating the kernel catch-up game.

Dynamic Kernel Module Support (DKMS)

Using DKMS

With all of this up-front hype about DKMS, perhaps it might be best to settle into the particulars of actually how the software is used. First, using DKMS for a module requires that the module source be located on the user's system and that it be located in the directory /usr/src/(module))-((module-version))/.

In addition, a dkms.conf file must exist with the appropriately formatted directives within this configuration file to tell DKMS such things as where to install the module and how to build it.

[tweet]

Once these two requirements have been met and DKMS has been installed on the system, the user can begin using DKMS by adding a module/module-version to the DKMS tree.

The example add command would add qla2x00/v6.04.00 to the extant /var/dkms tree.

dkms add -m qla2x00 -v v6.04.00

This command includes creating the directory /var/dkms/qla2x00/v6.04.00/, creating a symlink from /var/dkms/qla2x00/v6.04.00/source to → /usr/src/qla2x00-v6.04.00/ and copying the dkms.conf file from its original location to /var/dkms/qla2x00/v6.04.00/dkms.conf.

Once this add is complete, the module is ready to be built. The dkms build command requires that the proper kernel sources are located on the system from the /lib/module/kernel-version/build symlink. The make command used to compile the module is specified in the dkms.conf configuration file. Continuing with the qla2x00/v6.04.00 example:

dkms build -m qla2x00 -v v6.04.00 -k 2.4.20-8smp

It would add qla2x00/v6.04.00 to the extant /var/dkms tree. This command includes creating the directory /var/dkms/qla2x00/v6.04.00/, creating a symlink from /var/dkms/qla2x00/v6.04.00/source to → /usr/src/qla2x00-v6.04.00/ and copying the dkms.conf file from its original location to /var/dkms/qla2x00/v6.04.00/dkms.conf.

Once this add is complete, the module is ready to be built. The dkms build command requires that the proper kernel sources are located on the system from the /lib/module/kernel-version/build symlink.

[tweet]

The make command used to compile the module is specified in the dkms.conf configuration file. Continuing with the qla2x00/v6.04.00 example:

dkms build -m qla2x00 -v v6.04.00 -k 2.4.20-8smp

...compiles the module but stops short of installing it. Although build expects a kernel-version parameter, if this kernel name is left out, it assumes the currently running kernel. However, building modules for kernels not currently running also is a viable option. This functionality is assured through the use of a kernel preparation subroutine that runs before any module build is performed.

This paranoid kernel preparation involves running a make mrproper, copying the proper kernel .config file to the kernel source directory, running a make oldconfig and, finally, running a make dep.

These steps ensure that the module being built is built against the proper kernel symbols.

By default, DKMS looks for the kernel .config file in the /lib/modules/kernel-version/build/configs/ directory, utilizing Red Hat's naming structure for those config files. If the kernel .config file is not located in this directory, you must specify a --config option with your build command and tell DKMS where the .config file can be found.

Successful completion of a build creates, for this example, the /var/dkms/qla2x00/v6.04.00/2.4.20-8smp/ directory as well as the log and module subdirectories within this directory. The log directory holds a log file of the module make, and the module directory holds copies of the compiled .o binaries.

With the completion of a build, the module now can be installed on the kernel for which it was built.

Installation copies the compiled module binary to the correct location in the /lib/modules/ tree, as specified in the dkms.conf file. If a module by that name is already found in that location, DKMS saves it in its tree as an original module, so it can be put back into place at a later time if the newer module is uninstalled. The example install command:

dkms install -m qla2x00 -v v6.04.00 -k 2.4.20-8smp

...creates the symlink /var/dkms/qla2x00/v6.04.00/kernel-2.4.20-8smp → /var/dkms/qla2x00/v6.04.00/2.4.20-8smp. This symlink is how DKMS keeps tabs on which driver version is installed on which kernel. As stated earlier, if a module by the same name is installed already, DKMS saves a copy in its tree in the /var/dkms/module-name/original_module/ directory. In this case, it would be saved to /var/dkms/qla2x00/original_module/2.4.20-8smp/.

To complete the DKMS cycle, you also can uninstall or remove your module from the tree. Uninstall removes the module you installed and, if applicable, replaces it with its original module. In scenarios where multiple versions of a module are located within the DKMS tree, when one version is uninstalled, DKMS does not try to understand or assume which of these other versions should be put in its place.

Instead, if a true original_module was saved from the original DKMS installation, it is put back into the kernel. All of the other module versions for that module are left in the built state. An example uninstall would be:

dkms uninstall -m qla2x00 -v v6.04.00 -k 2.4.20-8smp

If the kernel version parameter is unset, the currently running kernel is assumed, but the same behavior does not occur with the remove command. Remove and uninstall are similar in that a remove command completes all of the same steps as does an uninstall. However, if the module-version being removed is the last instance of that module-version for all kernels on your system, after the uninstall portion of the remove completes, remove physically removes all traces of that module from the DKMS tree.

In other words, when an uninstall command completes, your modules are left in the “built” state. However, when a remove completes, you have to start over from the add command before you can use this module again with DKMS. Here are two sample remove commands:

dkms remove -m qla2x00 -v v6.04.00 -k 2.4.20-8smp

dkms remove -m qla2x00 -v v6.04.00 --all

With the first remove command, the module would be uninstalled. If this module/module-version were not installed on any other kernel, all traces of it would be removed from the DKMS tree. If, say, qla2x00/v6.04.00 also was installed on the 2.4.20-8bigmem kernel, the first remove command would leave it alone—it would remain intact in the DKMS tree. That would not be the case in the second example. It would uninstall all versions of the qla2x00/v6.04.00 module from all kernels and then completely expunge all references of qla2x00/v6.04.00 from the DKMS tree. Thus, remove is what cleans your DKMS tree.

Miscellaneous DKMS Commands

DKMS also comes with a fully functional status command that returns information about what is currently located in your tree. If no parameters are set, it returns all information found. Logically, the specificity of information returned depends on which parameters are passed to your status command. Each status entry returned is of the state added, built or installed. If an original module has been saved, this information also is displayed. Some example status commands include:

dkms status

dkms status -m qla2x00
dkms status -m qla2x00 -v v6.04.00
dkms status -k 2.4.20-8smp
dkms status -m qla2x00 -v v6.04.00 -k 2.4.20-8smp

Another major feature of DKMS is the match command. The match command takes the configuration of DKMS-installed modules for one kernel and applies it to some other kernel.

When the match completes, the same module/module-versions installed for one kernel are then installed on the other kernel. This is helpful when you are upgrading from one kernel to the next but want to keep the same DKMS modules in place for the new kernel. In the example:

dkms match --templatekernel 2.4.20-8smp -k 2.4.20-9smp

--templatekernel is the match-er kernel from which the configuration is based. The -k kernel is the match-ee upon which the configuration is instated.

For systems management purposes, the commands mktarball and ldtarball also have been added to DKMS. These commands allow the user to make and load tarball archives, respectively, into the DKMS tree to facilitate using DKMS in deployments where many similar systems exist. This allows the system administrator to build modules on only one system. Rather than build the same module on every other system, the built binary can be applied directly to the other systems' DKMS tree.

Specifically, mktarball creates a tarball of the source for a given module/module-version. It then archives the DKMS tree of every kernel version that has a module built for that module/module-version. Consider the example:

dkms mktarball -m qla2x00 -v v6.04.00 -k 2.4.20-8smp,2.4.20-8

Depending on the -k kernel parameter, mktarball archives only certain binaries compiled for those kernels specified. If no kernel parameter is given, it archives all built module binaries for that module/module-version.

With ldtarball, DKMS simply parses the archive created with mktarball and applies whatever is found to that system's DKMS tree. This leaves all modules in the built state; the dkms install command then can be used to place the module binaries into the /lib/modules tree.

Under normal operation, ldtarball does not overwrite any files that already exist in the system's DKMS tree. However, the archive can be forced over what is in the tree with the --force option. An example ldtarball:

dkms ldtarball --config qla2x00-v6.04.00-kernel2.4.20-8smp.tar.gz

The dkms.conf Configuration File Format

For maintainers of DKMS packages, the dkms.conf configuration file is the only auxiliary piece necessary to make your source tarball DKMS-ready. The format of the conf file is a successive list of shell variables sourced by DKMS when working with your package.

For example, an excerpt from the qla2x00/v6.04.00 dkms.conf file:

MAKE="make all INCLUDEDIR=/lib/modules/$kernelver/build/include"

MAKE_smp="make SMP=1 all INCLUDEDIR=/lib/modules/$kernelver/build/include"
LOCATION="/kernel/drivers/addon/qla2200"
REMAKE_INITRD="yes"
MODULE_NAME="qla2200.o:qla2200_6x.o qla2300.o:qla2300_6x.o"
CLEAN="make clean"
MODULES_CONF_ALIAS_TYPE="scsi_hostadapter"
MODULES_CONF0="options scsi_mod scsi_allow_ghost_devices=1"

It shows that each of the shell variable directives should be coded in all capital letters. One of the current exceptions to this rule is the MAKE_ directive.

DKMS uses the generic MAKE= command to build your module. But, if a MAKE_kernel-regexp-text command exists and the text after the MAKE_ matches (as a substring) the kernel for which it is being built, then this alternate make command is used.

In the above example, you can see how DKMS would use the MAKE_smp directive on any smp kernel for which it was building this module. Similar PATCH_ commands also exist. When the text after the underscore matches the kernel for which a module is being built, that patch first is applied to the module source. This allows developers to distribute one source tarball, with one dkms.conf and multiple patches.

Yet, different patches can be applied as necessary to the source to ensure all modules function correctly on all kernels.

Also notice that dkms.conf accepts the $kernelver variable, which, at build time, is replaced with the kernel version for which the module is being built. This is especially important so the correct include directories are referenced when compiling a module for a kernel that is not currently running.

An example

Let's say you want to install a module for your fancy "Awesome Adaptor". You are given a source tarball awesome-20091211-v1.1.tgz.

Without DKMS, you would unpack the module and read the README to figure out how to compile and install the module.

# tar -xzf awesome-20091211-v1.1.tgz

# cd awesome-20091211-v1.1/
# ls

A typical README will have you do something like this:

# cd src

# ls
Makefile awesome.c
# make
building awesome.ko
# ls
Makefile awesome.c awesome.ko awesome.o
# sudo make install
copying awesome.ko to current kernel tree....
rebuilding initrd....

With DKMS, we tell DKMS how to do that for you by creating a dkms.conf file with the appropriate entries. For example, after we've unpacked the tarball:

# cd awesome-20091211-v1.1/

# touch dkms.conf #create dkms.conf file
# texteditorofyourchoice dkms.conf

Inside dkms.conf, we might add the lines, for example:

MAKE="make -C src/ KERNELDIR=/lib/modules/${kernelver}/build"

CLEAN="make -C src/ clean"
BUILT_MODULE_NAME=awesome
BUILT_MODULE_LOCATION=src/
PACKAGE_NAME=awesome
PACKAGE_VERSION=1.1
REMAKE_INITRD=yes

All directories are with respect to the location of the dkms.conf file. This tells DKMS:

  1. The command to build the module (run make in the directory src/). You should look at your Makefile and determine any environment variables that need to be set to the appropriate kernel-specific directory. Many packages will build by default against the currently running kernel, but you want dkms to be able to build against a different kernel that may be specified to it on the command line, the version of which is held in the "$kernelver" variable. The environment variable "KERNELVERSION=${kernelver}" is automatically appended to the make line by dkms at runtime, but this variable may not be the one used by your Makefile. Another common environment variable is "INCLUDEDIR=/lib/modules/${kernelver}/build/include".
  2. The command to clean the source tree (run make clean in the directory src/).
  3. The name of the module without the .o or .ko extension. This may actually be an array of modules if multiple modules are built, see man dkms.
  4. Where DKMS can find the built module.
  5. The name and version DKMS should associate with the module(s).
  6. To remake the initrd image after installing the module.

You can also add options to call scripts before or after build or install, provide additional (conditional) make commands, patch commands, etc. The dkms.conf is in fact sourced into a shell script, so a fair amount of trickery can be done if necessary. These options and more are described in the dkms.conf section in man dkms.

Next, we install the module into DKMS by copying the module installation files into the kernel source tree /usr/src/<modulename>- and tell DKMS about the new module:

# ls

README dkms.conf lib src
# sudo cp -R . /usr/src/awesome-1.1
# sudo dkms add -m awesome -v 1.1
dkms does its thing...

That's it! DKMS has now added our module to its list of modules to build for future kernel installations. To make sure it works and to install the module into our current kernel, we can instruct dkms to build and install the module:

# sudo dkms build -m awesome -v 1.1
    dkms does its thing.... watch for build errors... you may need to tweak dkms.conf
# sudo dkms install -m awesome -v 1.1
    dkms does its thing.... module is copied into current kernel module tree

With some luck (if needed, check the .configure script, in your module source, used to prepare the compiling of your module to check if you've prepared all as needed), your module will be installed and reinstalled into future kernel updates.

Another Example (CIFS Module)

The method described above builds a module for a particular kernel version. If you upgrade the kernel or change the hardware architecture, you will have to manually build the module once again.

The dynamic kernel module support (DKMS) framework is basically a duplicate tree, outside of the kernel source, that holds the source and compiled binaries for a particular module. DKMS can be called on to build, install or uninstall modules. DKMS requires the module source code to be located on your system.

The DKMS binary takes care of building and installing the module(s) into any kernel(s) you may have on your system.

Here we will use the same example as above and build & install the cifs module. You will need to assume root's powers for this entire section.

Create a directory /usr/src/<module>-<module -version>/:

[root@host]# mkdir /usr/src/cifs-1.45fixed/

Copy the module's source code to that directory.

[root@host]# cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18-i686/fs/cifs

[root@host cifs]# cp -a * /usr/src/cifs-1.45fixed/

Create a dkms.conf file in the directory /usr/src/<module>-<module -version>/

[root@host cifs]# cd /usr/src/cifs-1.45fixed

[root@host cifs-1.45fixed]# vi dkms.conf

The dkms.conf file will need to contain these lines:

PACKAGE_NAME="cifs"

PACKAGE_VERSION="1.45fixed"
BUILT_MODULE_NAME[0]="cifs"
DEST_MODULE_LOCATION[0]="/kernel/fs/cifs/"
AUTOINSTALL="yes"

Note: The DEST_MODULE_LOCATION[0] line will be ignored during module installation because this will always be to the /lib/modules//extra/ directory. This parameter, however, will be used when a module is uninstalled as the location to which the stored, old module (if any) will be restored.

Add the <module>/<module -version> to the DKMS tree.

[root@host cifs-1.45fixed]# dkms add -m cifs -v 1.45fixed

Compile the module, under DKMS control.

[root@host cifs-1.45fixed]# dkms build -m cifs -v 1.45fixed

Install the module, again under DKMS control.

[root@host cifs-1.45fixed]# dkms install -m cifs -v 1.45fixed

Other DKMS actions to note are uninstall, remove, status and mkrpm which uninstalls the module from the kernel, removes the <module>/<module -version> from the DKMS tree, displays the current DKMS status of the system and creates a rpm file in the directory /var/lib/dkms/<module>/<module -version>/rpm/ respectively.

A last example...

Prepare your kernel module source. It contains the C file and its Makefile at least. The following is an hello world kernel module as an example:

#include <linux/kernel.h>

#include <linux/init.h>
static int __init hello_init(void)
{
pr_info("Hello world.\n");
return 0;
}
static void __exit hello_exit(void)
{
pr_info("Goodbye world.\n");
}
module_init(hello_init);
module_exit(hello_exit);

The following is its Makefile as example:

obj-m := hello.o

KVERSION := $(shell uname -r)
all:
$(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) clean

Please use a variable to keep the kernel version we want to compile. In the above example, it is $(KVERSION). We usually run dkms build under the various kernel version, and the DKMS will pass the target kernel version to Makefile.

Please put your Makefile and source code at /usr/src/<module>-<module -version>. For example, we put above two files at /usr/src/hello-0.1.

dkms.conf

Add dkms.conf and put it with your Makefile. Here is an example dkms.conf for hello-0.1:

PACKAGE_NAME="hello"

PACKAGE_VERSION="0.1"
CLEAN="make clean"
MAKE[0]="make all KVERSION=$kernelver"
BUILT_MODULE_NAME[0]="hello"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"

PACKAGE_NAME, PACKAGE_VERSION is necessary information, it shall be the same with the information or your folder name.

CLEAN is the command to clean up the folder. Every time before build, it will be executed. If unset, it is assumed to be "make clean".

MAKE[0] is the first command to build the kernel object. Since this is an example, this is the only command we have. This field tells DKMS how to build the kernel object, and we can pass the target kernel version by using $kernelver that DKMS provides us.

DEST_MODULE_LOCATION[0] tells DKMS where to put the kernel object when installing. In this example, the kernel object will be "/lib/modules/$kernelver/updates". In Ubuntu, this information will be overrade to "/updates/dkms". It means our kernel objects will be put at /lib/modules/$kernelver/updates/dkms". Although this information will be overrade, it is still a necessary field.

AUTOINSTALL set to yes means DKMS will try to build and install the kernel object when booting and it won't be re-built nor re-installed if the kernel object has been installed.

DKMS commands

Now, use "dkms add" to tell DKMS we have a module is ready. DKMS will create symlink from /var/lib/dkms to /usr/src.

user@here:~$ sudo dkms add -m hello -v 0.1

Creating symlink /var/lib/dkms/hello/0.1/source -> /usr/src/hello-0.1
DKMS: add Completed.

Then, you can try to build this module with "DKMS build".

user@here:~$ sudo dkms build -m hello -v 0.1

Kernel preparation unnecessary for this kernel. Skipping...
Building module: cleaning build area....
su nobody -c "make KERNELRELEASE=2.6.31-15-generic -C /lib/modules/2.6.31-15-generic/build M=/var/lib/dkms/hello/0.1/build"....
cleaning build area....
DKMS: build Completed.

And, you can install this module to the kernel module tree.

user@here:~$ sudo dkms install -m hello -v 0.1

hello.ko:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/2.6.31-15-generic/updates/dkms/
depmod......
DKMS: install Completed.

Then, you can see the kernel object has been add to your module tree:

user@here:~$ ls -al /lib/modules/2.6.31-15-generic/updates/dkms/hello.ko

-rw-r--r-- 1 root root 3328 2009-11-11 11:19 /lib/modules/2.6.31-15-generic/updates/dkms/hello.ko

And you can use it now.

user@here:~$ sudo modprobe hello

user@here:~$ dmesg | tail -1
[ 7328.183867] Hello world.

If the module is useless for you, you can remove the module from DKMS. All files related to this module under /var/lib/dkms and /lib/modules will be removed.

user@here:~$ sudo dkms remove -m hello -v 0.1 --all

You can also ask DKMS to build and install this module for another kernel version after "dkms add".

user@here:~# sudo dkms build -m hello -v 0.1 -k 2.6.31-14-generic

Kernel preparation unnecessary for this kernel. Skipping...
Building module:
cleaning build area....
su nobody -c "make KERNELRELEASE=2.6.31-14-generic all KVERSION=2.6.31-14-generic"....
cleaning build area....
DKMS: build Completed.
user@here:~# dkms install -m hello -v 0.1 -k 2.6.31-14-generic
hello.ko:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/2.6.31-14-generic/updates/dkms/
depmod....
DKMS: install Completed.

It is also possible to build against multiple kernel versions.

user@here:~# sudo dkms build -m hello -v 0.1 -k 2.6.31-14-generic -k 2.6.31-14-generic-pae

The pre-built modules will be included in the DKMS deb made later. When the versions of the pre-built modules and the kernel on the target computer match, the pre-built modules will just be used rather than compiling on installation.

Debug when DKMS build failed

If DKMS build kernel failed, it will leave the make.log for you to tell what happened. The log will be at:

/var/lib/dkms///build/make.log

Download

You’ll be able to download the following pdf only if registered and logged on HeelpBook. Be calm, it’s totally free. :-)

[wpfilebase tag="file" id=176 /]