Obsolete/KernelModules

= Packaging kernel modules for Fedora Extras =

Introduction
Kernel modules are a special case in rpm packaging and need careful handling. There are a lot of ways to package kernel modules -- to avoid confusion for the users and reviewers as well as to make it easier for RPM depsolvers to support kernel-modules the Fedora Extras Steering Commitee (FESCo) worked out below standard for packaging kernel-modules in Fedora. This standard hopefully solves many pitfalls earlier standards in other repos had.

The most important rule for packages with kernel modules: There are always at least two SRPMS -- one builds a userland package of the source, the other builds packages with *only* the kernel-module(s) in it.

userland package
The binary packages build from the userland SRPM contains tools, documentation, license, udev configuration etc. There always has to exist such a package -- even if the packaged software only builds kernel-modules it has at least some docs and a license file that need to be packaged in the userland package.

The packager is free to split the userland-package further into those with a the general userland parts, that works fine without the kernel-modules (docs, general tools, devel-files), and one with the kernel-module related parts (udev rules for example).

The userland packages follow the usual Packaging Guidelines. Two additional rules MUST be followed for packages with parts related to the kernel-module(s):


 * 1) The package must tie itself to the kernel-module using something like 'Requires: %{name}-kmod  >= %{version}'
 * 2) The package must provide %{name}-kmod-common using something like 'Provides: %{name}- kmod-common = %{version}' or the name of the package must be %{name}-kmod-common

kernel-module package
Of course all general rules that apply to rpm packaging in Fedora Extras apply for kernel module packages, too. Especially those around the licensing -- there are a lot of kernel-modules out there that can't be included in Fedora Extras due to licensing issues.

Besides the normal rules there are several additional rules -- instead of writing all those down FESCo created a specfile template and a script (used by the specfile) that handles most things automatically. Both are described in detail below.

All kernel module packages should use the template (see below) as a base. Reviewers of kernel modules should diff the proposed kernel module packages against the template. Only the names and the way the modules itself are build should differ. There shouldn't be other differences without a good reason.

Script
The bash script that is used by kernel-module-packages is named kmodtool. It is planed to be added to the redhat-rpm-config package and to be available to with the macro %{kmodtool}. In the testing phase the script is part of the packages. The current up2date version can be found here.

The script is no real magic -- if you understand a bit of bash scripting you should be able to see how it works. The most important part is the function get_rpmtemplate and this part of it:

%package      -n kmod-${kmod_name}${dashvariant} Summary:         ${kmod_name} kernel module(s) Group:           System Environment/Kernel Provides:        kernel-modules = ${verrel}${variant} Provides:        ${kmod_name}-kmod = %{?epoch:%{epoch}:}%{version}-%{release} Requires:        kernel-%{_target_cpu} = ${verrel}${variant} Requires:        ${kmod_name}-kmod-common >= %{?epoch:%{epoch}:}%{version} Requires(post):  /sbin/depmod Requires(postun): /sbin/depmod BuildRequires:   kernel${dashvariant}-devel-%{_target_cpu} = ${verrel} %description  -n kmod-${kmod_name}${dashvariant} This package provides the ${kmod_name} kernel modules built for the Linux kernel ${verrel}${variant} for the %{_target_cpu} family of processors. %post         -n kmod-${kmod_name}${dashvariant} /sbin/depmod -aeF /boot/System.map-${verrel}${variant} ${verrel}${variant} > /dev/null || : %postun       -n kmod-${kmod_name}${dashvariant} /sbin/depmod -aF /boot/System.map-${verrel}${variant} ${verrel}${variant} &> /dev/null || : %files        -n kmod-${kmod_name}${dashvariant} %defattr(644,root,root,755) /lib/modules/${verrel}${variant}/extra/${kmod_name}/

This macro later expands to something like the following and is inserted into the spec file before building (with kmod_name foo, Version 1.5, kver 2.6.14-1.1776_FC4, uniprocessor Build for i686):

%package      -n kmod-foo Summary:         foo kernel module(s) Group:           System Environment/Kernel Provides:        kernel-modules = 2.6.21-1.1776_FC7 Provides:        foo-kmod = 1.5-1 Requires:        kernel-i686 = 2.6.21-1.1776_FC7 Requires:        foo-kmod-common >= 1.5 Requires(post):  /sbin/depmod Requires(postun): /sbin/depmod BuildRequires:   kernel-devel-i686 = 2.6.21-1.1776_FC7 %description  -n kmod-foo This package provides the foo kernel modules built for the Linux kernel 2.6.21-1.1776_FC7 for the i686 family of processors. %post         -n kmod-foo /sbin/depmod -aeF /boot/System.map-2.6.21-1.1776_FC7 2.6.21-1.1776_FC7 > /dev/null || : %postun       -n kmod-foo /sbin/depmod -aF /boot/System.map-2.6.21-1.1776_FC7 2.6.21-1.1776_FC7 &> /dev/null || : %files        -n kmod-foo %defattr(644,root,root,755) /lib/modules/2.6.21-1.1776_FC7/extra/foo/

Why all that? Let's go though the interesting bits in detail:



All kernel modules need to have the prefix kmod (that's a bit shorter than kernel-module)



With the explicit Provides depsolvers such as yum can know that it's working with a kernel module. You also easily can get the kver the module was build for with this.



The userland-package that depends on a package that provides that to make sure that yum and other depsolvers install a proper kernel-module if you install a userland package that requires a kernel-module.



A kernel module without the kernel it was built for is useless. Don't use /boot/vmlinuz-*, it's not portable.



Kernel modules without the userland part is useless in most cases. There are rare packages when kernel modules don't need a part in userland, but we require it anyway -- at least the license and the docs needs to be placed somewhere in any case and a userland package is the right place for them.



Needed for building kernel-modules



Kernel modules shall not be executable -- but they need to be after %install to allow /usr/lib/rpm/find-debuginfo.sh to strip them.



Separate location -- don't mess up with the rest of the kernel. "extra" was picked because of upstream kernel documentation. Only kernel modules in that dir are allowed -- nothing else, because otherwise they might conflict between different versions!

kernel module specfile
An example kernel module specfile for "foo" might looks like this (download ; note that the first part of the page needs adjustments for the different releases -- see the end of this page for up2date examples):

Source10: kmodtool %define  kmodtool bash %{SOURCE10}

%{!?kversion: %define kversion 2.6.21-1.2111_FC7}

%define kmod_name foo %define kverrel %(%{kmodtool} verrel %{?kversion} 2>/dev/null)

%define upvar "" %ifarch i586 i686 ppc %define smpvar smp %endif %ifarch i686 x86_64 %define xenvar xen0 xenU %define kdumpvar kdump %endif %{!?kvariants: %define kvariants %{?upvar} %{?smpvar} %{?xenvar} %{?kdumpvar}}

Name:          %{kmod_name}-kmod Version:       1.5 Release:       3.%(echo %{kverrel} | tr - _) Summary:       %{kmod_name} kernel modules

Group:         System Environment/Kernel License:       GPL URL:           http://foo.sf.net Source0:       http://download.sf.net/%{kmod_name}/%{kmod_name}-%{version}.tar.bz2 Patch0:        %{kmod_name}-foo.patch BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

ExclusiveArch: i586 i686 x86_64 ppc

%description foo bar foobar

%{expand:%(%{kmodtool} rpmtemplate %{kmod_name} %{kverrel} %{kvariants} 2>/dev/null)}

%prep %setup -q -c -T -a 0 pushd %{kmod_name}-%{version}* %patch0 -b .patch0 popd for kvariant in %{kvariants} ; do cp -a %{kmod_name}-%{version} _kmod_build_${kvariant} done

%build for kvariant in %{kvariants} do ksrc=%{_usrsrc}/kernels/%{kverrel}${kvariant:+-$kvariant}-%{_target_cpu} pushd _kmod_build_$kvariant make -C "${ksrc}" SUBDIRS=${PWD} modules %{?_smp_mflags} popd done

%install rm -rf $RPM_BUILD_ROOT for kvariant in %{kvariants} do pushd _kmod_build_$kvariant make install \ DESTDIR=$RPM_BUILD_ROOT INST_DIR=$RPM_BUILD_ROOT/lib/modules/%{kverrel}${kvariant}/extra/%{kmod_name} popd done chmod u+x $RPM_BUILD_ROOT/lib/modules/*/extra/%{kmod_name}/*

%clean rm -rf $RPM_BUILD_ROOT

%changelog

So how does it work? let's go through important parts to describe them:

%define  kmodtool sh %{SOURCE10}

Include kmodtool and Source10 and define a variable for it



The kernel-version for which the module will be build needs to be hardcoded for now. Hint: this can he overridden with "--define kversion foo" on the rpmbuild command line.



The name of the belonging userland package/the original name of the software. It is used in several places, therefore we define a macro for it.



Define kverrel for the "kernel version release" (for example 2.6.21-1.1776_FC7 for kernel 2.6.21-1.1776_FC7smp). The kmodtool takes care here for stipping off "smp", "xen-guest" or other known variants from the sting %{?kver}. That is normally defined by the buildsys or the user to specify the kernel to build for. Kmodtool will use the string from $(uname -r) if kver is not defined.

%ifarch i586 i686 ppc %define smpvar smp %endif %ifarch i686 x86_64 %define xenvar xen0 xenU %define kdumpvar kdump %endif %{!?kvariants: %define kvariants %{?upvar} %{?smpvar} %{?xenvar} %{?kdumpvar}}

The kernel variants for which the module will be build need to be hardcoded for now. Define a variable kvariants with all the know kernel-variants for the current arch. Hint: this can he overridden with "--define kvariant foo bar" on the rpmbuild comand line.



This is only the name for the SRPM -- the kernel module package itself is named the other way around, e.g. "Name: kmod-{kmod_name}" (see the rpm macro). This might be a bit confusing in the beginning, but solves some problems nicely.



This needs to be the same as in the userland package.



This results in 3.2.6.21_1.1776_FC7 (e.g. the whole src.rpm is named something like "foo-kmod-1.5-3.2.6.21_1.1776_FC7").

The kver needs to be in the release to get proper debuginfo packages later. With this scheme we of course get a SRPM for each kernel we build the modules for. Therefore it might be better to create a stripped down tarball of the original source (e.g. remove the userland parts) to avoid wasting a lot of disk space. This is one of the drawbacks in this scheme, but it works.



This one is important for the buildsys. i386 should never be in the list because there is no i386 kernel in Fedora -- the buildsys would not find the BuildRequire and fail at that point. If a kernel module is only of interest for some of those archs of course feel free to list only those.



Well, as the comment already says, the magic from kmodtool is buried here -- kmodtool is called with all relevant parameters and will output the part we showed in above example trough the function get_rpmtemplate. One or multiple such parts will get inserted depending on how many variants are passed to kmodtool it (in case the spec file is for example called with '--define "kvariants up smp"')

%setup -q -c -T -a 0

Use some fancy options from the %setup macro -q -- Quiet -c -- Create a subdir before extracing -T -- don't extract -a 0 -- extract Source0 after creating subdir

%patch0 -p0[BR] cd ..

Patch the extracted sources (if needed)

cp -a foo-%{version} _kmod_build_$kvariant done

Create subdirs for each kernel variant

for kvariant in %{kvariants} do ksrc=%{_usrsrc}/kernels/%{kverrel}${kvariant:+-$kvariant}-%{_target_cpu} cd _kmod_build_$kvariant make -C "${ksrc}" SUBDIRS=$PWD/foo modules %{?_smp_mflags} cd .. done

Build the module -- this or similar commands should work with most modern kernel modules.

rm -rf $RPM_BUILD_ROOT for kvariant in %{kvariants} do make -C $dir install DESTDIR=$RPM_BUILD_ROOT     INST_DIR=$RPM_BUILD_ROOT/lib/modules/%{kverrel}${kvariant}/extra/%{kmod_name} done chmod u+x $RPM_BUILD_ROOT/lib/modules/*/extra/%{kmod_name}/*

Install the module and mark it executable for stripping.

What's the best way to test if the spec file works fine
Build the kmod with rpmbuild and in mock for a kernel with a different version than the one that are running currently, e.g., if you running 2.6.21-1.2122_FC7 try to build for 2.6.21-1.2111_FC7.

Will there be further enhancements for the kernel module proposal?
Probably yes. We probably didn't consider every possible scenario out there. But the general scheme/direction probably will stay.

Will other repos use the same scheme?
You have to ask those repos. One popular 3rd party repo that enhances Core and Extras uses it currently.

Does it work with yum?
Not perfectly (yet). We need a plugin for yum that will handles some special cases for kernel module packages. It is available in Extras currently, but not perfect yet.

Does it work in the Extras Buildsys?
Not perfectly (yet). We need a plugin or enhancement that will search for the latest kernel version and then will pass this to the rpmbuild command with "--define 'kversion foo'". There are no concrete plans who works on that ATM. Are you interested to help?

Will this proposal be used for the GFS stuff in Fedora Core, too?
That's the plan.

Is it possible to compile against self compiled kernels?
Yes, if self compiled means "packaged in a manner compatible with FC kernels". Otherwise: no. Well, it's _possible_, but not supported nor documented. Just create a FC compatible kernel package of your custom kernel, and compile the module packages for it by passing --define 'variant foo' to rpmbuild.

This standard is stupid.
Maybe. Post a better one. (No offense, more a FYI: We invested a lot of time in this standard and had to make a lot of compromises to make everyone happy -- doing bigger changes just "because I like my scheme better" probably won't help. But technical advantages that are documented and already tested in real life might convince us).

How do I rebuild a kmod srpm for one kernel
There are several ways:

Build foo-kmod.src for UP-Kernel 2.6.21-1.2139_FC7 i686: $ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.21-1.2139_FC7' --define 'kvariants ""' --target i686

Build foo-kmod.src for UP-Kernel 2.6.21-1.2139_FC7 x86_64: $ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.21-1.2139_FC7' --define 'kvariants ""' --target x86_64

Build foo-kmod.src for SMP-Kernel 2.6.21-1.2139_FC7 i686: $ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.21-1.2139_FC7' --define 'kvariants smp' --target i686

Build foo-kmod.src for UP- and SMP-kernel 2.6.21-1.2139_FC7 i686: $ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.21-1.2139_FC7' --define 'kvariants "" smp' --target i686

Note: you can't rebuild kmod's for i386 because there is no i386 kernel in Fedora. So on x86 you always have to use --target i686 or --target i586 when rebuilding kmod's.

Examples

 * lirc: main userland, kernel-dependent userland , kmod
 * thinkpad: userland, kmod
 * There are also some kmod-packages in a major 3rd party repo that enhances Core and Extras

Header for dists
The first part of the spec files needs adjustments to make sure that kmod's are build for all kernels. Here are the current up2date version:

For FC6:

%{!?kversion: %define kversion 2.6.16-1.2111_FC6}

%define kmod_name foo %define kverrel %(%{kmodtool} verrel %{?kversion} 2>/dev/null)

%define upvar "" %ifarch i686 %define paevar PAE %endif %ifarch ppc %define smpvar smp %endif %ifarch i686 x86_64 %define xenvar xen %define kdumpvar kdump %endif %{!?kvariants: %define kvariants %{?upvar} %{?smpvar} %{?paevar} %{?xenvar} %{?kdumpvar}}