How (recipe) to build only one kernel module?

Solution 1:

The recipe to build a custom module might need to be split in three sections.

Setup once

$ cd ~
$ apt-get source linux-source-3.13.0 

I am too lazy to copy the mvsas specific driver source files; just copy them all to your current working directory. If apt-get results in an error message about missing source URIs then see note #4 at the bottom.

$ cd linux-3.13.0
$ make oldconfig
$ make prepare
$ make scripts

This will prepare some files necessary to build a kernel module.

Each kernel version

$ apt-get install linux-headers-$(uname -r)

This will install headers and the Ubuntu kernel configuration file for that kernel version in /lib/modules.

$ cd ~/linux-3.13.0
$ cp -v /usr/src/linux-headers-$(uname -r)/Module.symvers .

This to prevent the message "no symbol version for module_layout" when loading the module with insmod or modprobe.

$ mv -v /lib/modules/$(uname -r)/kernel/drivers/scsi/mvsas/mvsas.ko /lib/modules/$(uname -r)/kernel/drivers/scsi/mvsas/mvsas.ko.backup

This will rename the original (Ubuntu build) kernel module to make sure that the custom patched one will load.

Each edit

$ cd ~/linux-3.13.0/drivers/scsi/mvsas
$ nano mv_sas.h
$ nano mv_sas.c

These are for the edits.

$ make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

This will compile and build the kernel module .ko file using the kernel configuration from your stock Ubuntu distribution as stored in /lib/modules/$(uname -r)/.

$ make -C /lib/modules/$(uname -r)/build M=$(pwd) modules_install

This will install the kernel module in /lib/modules/$(uname -r)/extra/, not overwriting the distribution module in case you didn't rename the distribution kernel module file. In this mvsas case it will also run depmod.

$ lsmod | grep mvsas

If this results in any output, the mvsas module needs unloading with (modprobe -r mvsas) first.

$ sudo modprobe -v mvsas

This should load the new kernel module.

Check the output to verify that /lib/modules/.../extra/mvsas.ko is being loaded.

Modprobe error: could not insert

In some cases you might experience a modprobe: ERROR: could not insert 'xyz': Unknown symbol in module, or unknown parameter (see dmesg) while in the verbose modprobe output you see that insmod is trying to load the module from the kernel default location. For example:

# insmod /lib/modules/3.17.0-031700rc7-generic/kernel/drivers/scsi/pm8001/pm80xx.ko
modprobe: ERROR: could not insert 'pm80xx': Unknown symbol in module, or unknown parameter (see dmesg)

In that case you need to manually run depmod and try to load the module again:

# depmod
# sudo modprobe -v mvsas

Notes

  1. It may be the case that the resulting .ko module files are much (for example 20 times) larger in size than the original module files as distributed by Ubuntu; in that case the make prepare step could have created a Linux developers debugging kernel configuration file and you are building from the source directory. Your -C param might not function as expected.
  2. I have seen guides with other commands like make modules_prepare and make M=scripts/mod but I don't think these are necessary for this case.
  3. You can use the Linux developers debug config by replacing -C /lib/modules/$(uname -r)/build with -C /usr/src/linux-headers-$(uname -r)
  4. In a default setup, apt-get source linux-sources will return error E: You must put some 'source' URIs in your sources.list. To fix this issue you can modify file /etc/apt/sources.list by uncommenting (removing the leading # from) the first deb-src line. Example for Ubuntu 17.10: deb-src http://ie.archive.ubuntu.com/ubuntu/ artful main restricted. run sudo apt-get update, and then the command will deliver sources for you. See also this question where a GUI method for doing this is described too.