Hand-building an updated upstream kernel module for your (Fedora) kernel

February 4, 2019

Suppose, not hypothetically, that you've run into an issue where a distribution kernel update has a new bug in some functionality that's important to you, for instance Fedora's 4.20.x kernels fail to see one fan sensor on your Asus Prime Z370-A motherboard. After some work, you identify the issue, report it, and the fix is made upstream. Now you would like to test this upstream fix in your kernel.

The proper way to do this would be to extract some form of the change that fixes things as a patch, get the source RPM for the latest Fedora kernel, add your patch to the specfile as another RPM patch, rebuild your new kernel source RPM to get the binary kernel RPMs, and install them (let's assume you don't have to worry about signed kernels). However, this is a lot of work and I'm lazy, so I took the easier way of rebuilding this changed code as an out of kernel module and then just dumping it into /lib/modules as a replacement for the regular Fedora kernel module from the kernel RPM. And rather than trying to create the proper control files for this, we'll just see if we can just build from the actual kernel source directory involved, which it turns out that we can in this case (but perhaps not always).

(As a disclaimer, my process here probably only works under the right circumstances because it's a hack.)

That's confusing, so let me put it more simply: we have some kernel source tree, let's call it groeck/linux-staging, and we're going to build a module from that source tree but build it for our currently running Fedora kernel. This tree has the fix we want, but it's not actually a kernel tree for the right version of the kernel, which is part of what makes this a hack.

(The current Fedora kernel is based on 4.20.5, while groeck/linux-staging is currently based on 5.0-rc3, because it's fixes that are intended to be pulled into the main Linux kernel. Eventually these fixes will hopefully make their way back into the 4.20.x series and all of this will be unnecessary.)

In theory, building a kernel module out of the tree once you have a suitable Kbuild or Makefile in the directory is very easy. The kbuild modules.txt documentation describes the important magic. When you're in the directory where the source of the module you want to build is, you run:

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

If all goes well, this will build your module to a <whatever>.ko file, say nct6775.ko. You probably want to compress this with xz, because that turns out to be the standard for kernel modules nowadays. You can check that things look good with 'modinfo nct6775.ko.xz'. My actual process wound up somewhat more involved than this, partly because I'm a cautious person and partly because I tried some things that exploded.

  1. Clone the Git repo with the fix to somewhere, say /var/tmp/linux-staging.

  2. Clone the stable kernel Git repo to somewhere, say /var/tmp/linux-stable. This isn't absolutely required, but we're going to use it to make sure we're not picking up unexpected changes.

  3. In the stable repo, check out the branch for your particular kernel line. Fedora is based on 4.20.x currently, so:
    git checkout linux-4.20.y
    

  4. In the staging repo, switch to the appropriate branch. Don't accidentally build from the wrong branch, giving you a version of the module without the fix, the way I did the first time.

    git checkout hwmon-next
    

    You may have to hunt around with 'git branch -r' and so on to find out where your fix is hiding. If you know the git commit ID, this stackoverflow answer led me to 'git branch --contains <commit-id>', which would have saved me having to guess and be somewhat lucky.

  5. Compare the module source in the stable branch and in the development version. There is probably a really clever way to put both in the same Git repo and compare with a git command, but I took the simple brute force way of two repos:

    cd /var/tmp
    diff -u linux-stable/drivers/hwmon/nct6775.c linux-staging/drivers/hwmon/nct6775.c
    

    You want to see little or no changes other than the bugfix for your issue. If there are significant changes, the module from the upstream may not compile for the stable kernel you want to build it against, or work properly in that kernel, and you have more work to do. I was lucky and the only change in nct6775.c that I cared about was the bugfix for my issue.

  6. Change into the directory holding the updated module you want and explicitly tell the module build process what module to build, instead of letting it build everything in the directory. Here we want to build the nct6775 module:

    cd /var/tmp/linux-staging/drivers/hwmon
    make -C /lib/modules/$(uname -r)/build M=$(pwd) nct6775.ko
    

    If you leave out the specific module you want to build, the build system will try to build all of them and you may find that some of the modules in your upstream tree aren't compatible with the stable kernel you're trying to build against. This is the case here and is why I wound up comparing the nct6775.c code in the stable tree against the upstream; even though it built against stable, I wanted some assurance that there hadn't been changes that would mean I was shooting myself in the foot.

    (I may still be shooting myself in the foot, but at least it's not obvious.)

  7. With nct6775.ko built, you can compress it with xz, then copy it to /lib/modules/$(uname -r)/extra/, save the original module (located in kernel/drivers/hwmon) to some other place, and run 'depmod $(uname -r)' to re-apply magic module processing. If you reboot, you should be using your new hand-built module and in my case, my case fan was back to being reported.

You can pre-build the module against a kernel other than what you're currently running by replacing the '$(uname -r)' bits with the actual name of the other kernel. This is handy if you're installing an updated kernel and don't want to reboot twice.

(Clever people who know what they're doing can proceed to make this a DKMS module. It's apparently not hard, but I'm in a brute force mood here.)

Written on 04 February 2019.
« My temptation of getting a personal laptop
A problem with strict memory overcommit in practice »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Feb 4 23:47:18 2019
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.