I want to build a kernel module that will be compatible with all the kernel’s releases. For example, if I build a kernel module on kernel 3.2.0-29 and try to load it on 3.2.
Add an Environment variable to the Makefile viz. 'K_VERSION'.
Build the module against an installed kernel by passing the version as the environment variable
eg.
make K_VERSION=`uname -r`
to build against currently running kernel.
Once built, the modprobe utility can be used.
The Linux kernel module API is unstable as design choice
This is explicitly explained in the source tree at Documentation/stable_api_nonsense.txt. The summary reads:
Executive Summary
-----------------
You think you want a stable kernel interface, but you really do not, and
you don't even know it. What you want is a stable running driver, and
you get that only if your driver is in the main kernel tree. You also
get lots of other good benefits if your driver is in the main kernel
tree, all of which has made Linux into such a strong, stable, and mature
operating system which is the reason you are using it in the first
place.
But an important clarification is:
The kernel to userspace interface is the one that application programs use,
the syscall interface. That interface is **very** stable over time, and
will not break. I have old programs that were built on a pre 0.9something
kernel that still work just fine on the latest 2.6 kernel release.
That interface is the one that users and application programmers can count
on being stable.
But worry not! Our friendly Linux developers explain the solution right in the same document:
What to do
----------
So, if you have a Linux kernel driver that is not in the main kernel
tree, what are you, a developer, supposed to do? Releasing a binary
driver for every different kernel version for every distribution is a
nightmare, and trying to keep up with an ever changing kernel interface
is also a rough job.
Simple, get your kernel driver into the main kernel tree (remember we
are talking about GPL released drivers here, if your code doesn't fall
under this category, good luck, you are on your own here, you leech
<insert link to leech comment from Andrew and Linus here>.) If your
driver is in the tree, and a kernel interface changes, it will be fixed
up by the person who did the kernel change in the first place. This
ensures that your driver is always buildable, and works over time, with
very little effort on your part.
Linux kernel version macro
Try using:
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
as mentioned at Is there a macro definition to check the Linux kernel version?
In short: you hardly can write useful kernel module, which can be loaded to kernels of relatively wide range of versions.
When you build the module against kernel compiled with CONFIG_MODVERSIONS
(like in your case), for every symbol, exported from the kernel, CRC for this symbol is stored in module's file. CRC is some sort of control sum, which takes into account, among other things, layout of types, used for function's parameters. For example, if layout of a hypothetical struct A
differs in two kernels, CRC for function f(struct A *a)
in these kernels differs too.
When a module is loaded into running kernel, CRC for all functions in the module are compared with ones for the kernel. If they differ, the kernel refuses to load the module. To read more about this mechanism see the kernel's documentation (Documentation/kbuild/modules.txt).
So, for make a module loadable into two different kernels, you are restricted only with functions whose parameters have same layout in both kernels. In particular, if layout of type struct module
differs, no single module can be loaded for both kernels.
There are several approaches to deliver a driver suitable for several kernels. The simplest way is to deliver the driver's sources and add them to dkms
. Such a way, if running kernel doesn't have the driver built, the driver will be compiled automatically using its sources.