From Fedora Project Wiki

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.

Idea.png
Note
The kernel-module packaging standard is quite new -- there still might be some issues that need finetuning, so be prepared for a little more maintain work. This document also still needs a bit love.

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. There are two additional rule for the package with the parts that are related to the kernel-module(s) :

- MUST: The package needs to require the matching kernel-module with something like 'Requires: %{name}- kmod = %{version}'

- MUST: The package needs to provide %{name}-kmod-common with 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. To save yourself the trouble it might be worth asking FESCo and or fedora-extras-list if a certain module is okay for Extras before you actually start packaging it.

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.

Besides rules around the packaging there is one additional *before* you start packaging a kernel module for Fedora Extras: Open a Review bug in http://bugzilla.redhat.com and ask FESCo via fedora<AT>leemhuis<DOT>info for permission if this module is allowed for Extras. This requires that you give at least the following informations:

  • Name of the package
  • URL of the project and a tarball of the latest version
  • License
  • A publishable explanation from the author(s) why the module is not merged with the mainline kernel yet and when it's planed to get merged. You of course can ask the author to explain it directly in the bug report.

FESCo will look at those informations on the next meeting (those are normally every thursday) and will vote if the kernel module is suitable for Fedora Extras. If not it will explain the reasons in the bug report for further discussion. For example ndiswrapper is not suitable for Fedora Extras -- yes, it is GPLed software, but it taints the kernel and most windows drivers won't work in the Fedora Kernel anyway due to 4K Stacks.

Why all this?

  • The Fedora Project wants to encourage driver developers to merge their sources in the kernel
  • It easier for everyone if the modules are in the main kernel (even for the developers -- but they often don't know that yet)
  • There is often a good reason why the kernel developers refuse to merge a driver. If it's not good enough for the kernel, why should it be good enough for Fedora?
  • Most modules that are maintained independently of the kernel have licensing issues that also make it impossible to ship them in Fedora Extras.

If the package is permitted for Fedora Extras start to write the specfile and use the bug you opened before for review of the kernel-module. Everyone can review such a package, but after is was set to APPROVED by the reviewer a Fedora Extras Sponsor or someone experienced with kernel modules has to take a quick look at the package and post an additional approved notice before it is allowed to import the package into CVS.

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

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

  • %package -n kmod-foo-2.6.14-1.776_FC4

All kernel modules need to have the prefix kmod (that's a bit shorter than kernel-module). Having the kver in the Name is overloading the variable, but this is done to ensure that we can have kernel modules for each kernel on the system, and that each kernel module can be updated independently without affecting the others.

  • Provides: kernel-modules = 2.6.14-1.1776_FC4
Stop (medium size).png
TBD
the kernel-modules provision triggers yum's "install, not upgrade" behaviour which is probably unneeded and undesirable with this scheme

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.

  • Provides: foo-kmod = 1.5

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.

  • Requires: kernel-i686 = 2.6.14-1.1776_FC4

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

  • Requires: foo-kmod-common >= 1.5

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.

  • BuildRequires: kernel-devel-i686 = 2.6.14-1.1776_FC4

Needed for building kernel-modules

  • %defattr(644,root,root,755)

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

  • /lib/modules/2.6.14-1.1776_FC4/extra/foo/

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 File:PackagingDrafts KernelModulesWithKverInName kmod-template.spec):

Source10: kmodtool
%define   kmodtool bash %{SOURCE10}

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

%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%{?dist}
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:


  • Source10: kmodtool

%define kmodtool sh %{SOURCE10}

Include kmodtool and Source10 and define a variable for it


  • %{!?kversion: %define kversion 2.6.16-1.2111_FC5}

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.

  • %define kmod_name foo

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  %(%{kmodtool} verrel  %{?kver} 2>/dev/null)

Define kverrel for the "kernel version release" (for example 2.6.14-1.1776_FC4 for kernel 2.6.14-1.1776_FC4smp). 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.

  • %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}}

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.

  • Name:  %{kmod_name}-kmod

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.

  • Version: 1.5

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

  • Release: 3.%(echo %{kver} | tr - _ )
Stop (medium size).png
Warning
The above line and its explanation below is outdated. Sane debuginfo generation is an open issue in this draft -- one possible way to achieve it would be something along the lines of https://www.redhat.com/archives/fedora-packaging/2006-August/msg00053.html

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

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.

  • ExclusiveArch: i586 i686 x86_64 ppc

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.

  • # magic hidden here:[BR] %{expand:%(%{kmodtool} rpmtemplate %{kmod_name} %{kverrel} %{kvariants} 2>/dev/null)}

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"')

  • %prep

%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

  • cd %{kmod_name}-%{version}

%patch0 -p0[BR] cd ..

Patch the extracted sources (if needed)

  • for kvariant in %{kvariants} ; do

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

Create subdirs for each kernel variant

  • %build

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.

  • %install

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.

Mini-FAQ

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.16-1.2122_FC5 try to build for 2.6.16-1.2111_FC5.

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.17-1.2139_FC5 i686:

$ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.17-1.2139_FC5' --define 'kvariant ""' --target i686

Build foo-kmod.src for UP-Kernel 2.6.17-1.2139_FC5 x86_64:

$ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.17-1.2139_FC5' --define 'kvariant ""' --target x86_64

Build foo-kmod.src for SMP-Kernel 2.6.17-1.2139_FC5 i686:

$ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.17-1.2139_FC5' --define 'kvariant smp' --target i686

Build foo-kmod.src for UP- and SMP-kernel 2.6.17-1.2139_FC5 i686:

$ rpmbuild --rebuild foo-kmod.src --define 'kversion 2.6.17-1.2139_FC5' --define 'kvariant "" 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