397 lines
18 KiB
ReStructuredText
397 lines
18 KiB
ReStructuredText
Dynamic Kernel Module Support (DKMS) Basics
|
|
===========================================
|
|
|
|
References
|
|
----------
|
|
|
|
G. Lerhaupt, Linuxjournal (www.linuxjournal.com/), September 1st, 2003.
|
|
|
|
|
|
Introduction To DKMS
|
|
--------------------
|
|
|
|
Source is a wonderful thing. Merged module source in the kernel tree
|
|
is even better. Most of all, support for that source is what really
|
|
counts. In today's explosion of Linux in the enterprise, the ability
|
|
to pick up the phone and find help is critical. More than ever,
|
|
corporations are driving Linux development and requirements. Often,
|
|
this meets with skepticism and a bit of anxiety by the community, but
|
|
if done correctly, the benefits are seen and felt by everyone.
|
|
|
|
The dynamic kernel module support (DKMS) framework should be viewed as
|
|
a prime example of this. 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.
|
|
|
|
|
|
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.
|
|
|
|
- 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))/`.
|
|
|
|
- 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.
|
|
|
|
More information on the format of the `dkms.conf` file can be found
|
|
later in this article. 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::
|
|
|
|
# dkms add -m qla2x00 -v v6.04.00
|
|
|
|
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. 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 following 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 last miscellaneous DKMS command is `mkdriverdisk`. As can be
|
|
inferred from its name, `mkdriverdisk` takes the proper sources in
|
|
your DKMS tree and creates a driver disk image that can provide
|
|
updated drivers to Linux distribution installations. A sample
|
|
`mkdriverdisk` might look like::
|
|
|
|
# dkms mkdriverdisk -d redhat -m qla2x00 -v v6.04.00 -k 2.4.20-8BOOT
|
|
|
|
Currently, the only supported distribution driver disk format is Red
|
|
Hat, but this easily could expand with some help from the community in
|
|
understanding driver disk requirements and formats on a
|
|
per-distribution basis. For more information on the extra necessary
|
|
files and their formats for DKMS to create Red Hat driver disks, see
|
|
`people.redhat.com/dledford`. These files should be placed in your
|
|
module source directory.
|
|
|
|
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"
|
|
|
|
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.
|
|
|
|
Using DKMS in Conjunction with RPM
|
|
----------------------------------
|
|
|
|
DKMS and RPM actually work quite well together. The only twist is that
|
|
to make it function properly, you have to create an RPM that installs
|
|
source. Although normal practice is to install source only with source
|
|
RPMs, a source RPM does not necessarily work with DKMS; it will not
|
|
let you do much besides install the source. Instead, your source
|
|
tarball needs to be included with your RPM, so your source can be
|
|
placed in `/usr/src/module-module-version/` and the proper DMKS
|
|
commands can be called. The `%post` and `%preun` basically are DKMS
|
|
commands.
|
|
|
|
Here is a sample `.spec` file::
|
|
|
|
%define module qla2x00
|
|
|
|
Summary: Qlogic HBA module
|
|
Name: %module_dkms
|
|
Version: v6.04.00
|
|
Release: 1
|
|
Vendor: Qlogic Corporation
|
|
Copyright: GPL
|
|
Packager: Gary Lerhaupt <gary_lerhaupt@dell.com>
|
|
Group: System Environment/Base
|
|
BuildArch: noarch
|
|
Requires: dkms gcc bash sed
|
|
Source0: qla2x00src-%version.tgz
|
|
Source1: dkms.conf
|
|
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root/
|
|
|
|
%description
|
|
This package contains Qlogic's qla2x00 HBA module meant
|
|
for the DKMS framework.
|
|
|
|
%prep
|
|
rm -rf qla2x00src-%version
|
|
mkdir qla2x00src-%version
|
|
cd qla2x00src-%version
|
|
tar xvzf $RPM_SOURCE_DIR/qla2x00src-%version.tgz
|
|
|
|
%install
|
|
if [ "$RPM_BUILD_ROOT" != "/" ]; then
|
|
|
|
rm -rf $RPM_BUILD_ROOT
|
|
fi
|
|
mkdir -p $RPM_BUILD_ROOT/usr/src/%module-%version/
|
|
install -m 644 $RPM_SOURCE_DIR/dkms.conf
|
|
$RPM_BUILD_ROOT/usr/src/%module-%version
|
|
install -m 644 qla2x00src-%version/*
|
|
$RPM_BUILD_ROOT/usr/src/%module-%version
|
|
|
|
%clean
|
|
if [ "$RPM_BUILD_ROOT" != "/" ]; then
|
|
|
|
rm -rf $RPM_BUILD_ROOT
|
|
fi
|
|
|
|
%files
|
|
%defattr(0644,root,root)
|
|
%attr(0755,root,root) /usr/src/%module-%version/
|
|
|
|
%pre
|
|
|
|
%post
|
|
/sbin/dkms add -m %module -v %version
|
|
/sbin/dkms build -m %module -v %version
|
|
/sbin/dkms install -m %module -v %version
|
|
exit 0
|
|
|
|
%preun
|
|
/sbin/dkms remove -m %module -v %version --all
|
|
exit 0
|