Lesson 5: The care and feeding of loadable kernel modules (LKMs)

Printer-friendly versionPrinter-friendly version

I can haz kernel programming, pleez?

Not just yet. Soon, but not just yet, since there is still one more lesson worth of kernel fundamentals we need to cover before you write, build and load your first kernel module. And you'll be using what you learn in this lesson almost immediately with that first kernel module of yours, so take your time and digest all of what follows here. It's important.

What's a loadable module, anyway?

Most readers -- even those new to kernel programming -- know that a Linux loadable kernel module (or kernel module, or loadable module, or module, or LKM, etc, etc) is simply a compiled object file that you can load into kernel space, at which point it's now just another part of the running kernel and provides some functionality that wasn't there before.

The benefits of loadable modules should be obvious. Anything which is running in kernel space takes up RAM, so the larger your kernel, the more RAM it's consuming. If you need some functionality only rarely, you can build that functionality as a loadable module and load it as needed, and unload it afterwards.

In addition, loadable modules give you the opportunity of writing, say, a new device driver, then loading it, testing it, identifying bugs, unloading it, fixing it, recompiling it, reloading it, and so on, all without rebooting your system. It should be obvious that this is the perfect vehicle for new device driver development. But one last point.

Many people use the phrases "module" and "device driver" interchangeably. Technically, that's a bit sloppy. While loadable modules are primarily used for device drivers, they can certainly be used for other purposes -- you'll see later in this course how to write and load modules that help you debug the kernel. So while we'll certainly be referring to device drivers constantly throughout the rest of this course, try to keep the above distinction in mind.

Does your kernel support loadable modules?

Almost certainly. In fact, it would be astonishing if it didn't since all modern Linux distros come with a massive number of loadable modules ready to go. But there are exceptions.

You could, if you wanted to, configure and build a kernel that had no module support whatsoever. From the kernel configuration menus you saw in the earlier lessons, here's the section related to loadable modules:

--- Enable loadable module support
[ ]   Forced module loading
[*]   Module unloading
[ ]     Forced module unloading
[*]   Module versioning support
[*]   Source checksum for all modules          

I'm not going to spend any time explaining the above because it's highly unlikely you'll ever need to mess with it. In special cases where you're building a tiny embedded system, you might want to configure a kernel with everything built in and no module support whatsoever, but that's unusual and we won't discuss it any further, at least for now. Onward.

The two names for a kernel module

Because I like to be precise, let me explain the two different types of "names" we'll use to refer to kernel modules from now on.

First, there's what you might think of as the, say, simple name, such as vfat or btrfs or lzo, as in, "Of course you can't mount that USB stick, you haven't loaded the vfat module, silly!" In this situation, the name vfat clearly identifies a particular module, and this type of name is the proper form to use in a number of module-related commands.

On the other hand, at times, you'll need to refer to the actual filename containing the loadable module code, such as vfat.ko, either as a relative pathname or possibly fully-qualified if you need to specify precisely where to find it. I mention this difference since some module commands expect to get a simple module name (like vfat) and they'll take it from there, whereas others need a precise filename (like vfat.ko). You'll be able to recognize the difference shortly.

And one more point. Readers who have been around since version 2.4 of the kernel might remember that loadable modules used to be stored in files with a normal object suffix of .o. Nowadays, the file prefix is .ko, short for "kernel object," otherwise known as a module.

Your current kernel's modules

For the rest of this lesson, we'll be working with the LKMs that correspond to your currently running kernel, and it won't make much difference if you're running your distro's official, latest kernel or the kernel you configured and built yourself. Either way, you should be able to run everything you see here, with the only difference probably being some version numbers or other irrelevancies. In my case, I'm running my hand-rolled kernel with the name 3.3.0-rday+ which is why you might see that name string popping up on occasion.

First, where are all the modules that already exist for your running kernel? You might remember that they're all under /lib/modules/, in a separate subdirectory for each installed kernel. My system currently looks like this:

$ ls -1 /lib/modules
3.0.0-12-generic
3.0.0-13-generic
3.0.0-14-generic
3.0.0-15-generic
3.0.0-16-generic
3.0.0-17-generic
3.3.0-rc7
3.3.0-rday+
$

and I can see which kernel I'm running with:

$ uname -a
Linux oneiric 3.3.0-rday+ ... snip ...
$

so if I wanted to list all of the modules available for a particular kernel, I could run a simple find command of the form:

$ cd /lib/modules/3.3.0-rday+
$ find . -name "*.ko"
./kernel/lib/ts_fsm.ko
./kernel/lib/crc-itu-t.ko
./kernel/lib/crc-ccitt.ko
./kernel/lib/raid6/raid6_pq.ko
./kernel/lib/libcrc32c.ko
./kernel/lib/bch.ko
./kernel/lib/crc7.ko
... lots snipped here ...
$

Shortly, we'll be picking on some of these modules as we experiment loading and unloading them.

By the way, you can always get the version of the running kernel with the command

$ uname -r
3.3.0-rday+
$

which is handy since you can automate generating the name of the appropriate modules directory with either of /lib/modules/`uname -r` or /lib/modules/$(uname -r). This is useful to remember since it allows you to write, say, shell scripts that manipulate modules, knowing that no matter what kernel version you're running, you'll be accessing the appropriate modules directory.

Which modules are currently loaded?

Easy -- there's the lsmod command:

$ lsmod
Module                  Size  Used by
nls_iso8859_1          12713  1 
nls_cp437              16991  1 
vfat                   17461  1 
fat                    61230  1 vfat
rfcomm                 46622  8 
bnep                   18144  2 
kvm_intel             132467  0 
kvm                   404372  1 kvm_intel
... etc etc ...

In fact, as the man page for lsmod makes clear, "lsmod is a trivial program which nicely formats the contents of the /proc/modules [file], showing what kernel modules are currently loaded." So you could just as easily have done:

$ cat /proc/modules
nls_iso8859_1 12713 1 - Live 0x0000000000000000
nls_cp437 16991 1 - Live 0x0000000000000000
vfat 17461 1 - Live 0x0000000000000000
fat 61230 1 vfat, Live 0x0000000000000000
rfcomm 46622 8 - Live 0x0000000000000000
bnep 18144 2 - Live 0x0000000000000000
kvm_intel 132467 0 - Live 0x0000000000000000
kvm 404372 1 kvm_intel, Live 0x0000000000000000
... etc etc ...

I think you can see the obvious aesthetic advantage of lsmod. We'll stick with that.

Loading and unloading modules

As a simple example of loading and unloading a single module, let's pick an example that we'll almost certainly have, regardless of which kernel we're running. From under the appropriate /lib/modules directory, I'm going to experiment on the module that provides support for the Btrfs filesystem, kernel/fs/btrfs/btrfs.ko (If you're doing this on a system that actually uses the Btrfs filesystem, then you'll need to select some other arbitrary module for the rest of this lesson.)

In a nutshell, run the following commands that verify that that module is not loaded, then load it, then check again:

$ lsmod | grep btrfs
$ sudo modprobe btrfs
$ lsmod | grep btrfs
btrfs                 683103  0 
zlib_deflate           26914  1 btrfs
libcrc32c              12644  1 btrfs
$

Clearly, that module was loaded, and dragged a couple more modules along with it. And when you're done with it (and since you don't actually need it), simply unload it:

$ sudo modprobe -r btrfs
$ lsmod | grep btrfs
$

Yes, it's really that simple. Now some notes about the above.

First, you need root privilege to run modprobe. Since we're running Ubuntu, we'll use the sudo utility. If you're running a different distro, figure out what it takes.

Next, you'll notice that loading that single module automatically dragged in its two dependencies that were not yet loaded. That's how modprobe works -- it examines the dependency information in the corresponding modules.dep file for the running kernel where, in our case, it would eventually find something resembling the following:

...
kernel/fs/btrfs/btrfs.ko:
  kernel/lib/zlib_deflate/zlib_deflate.ko
  kernel/lib/libcrc32c.ko
...

And, finally, there are a couple simpler (and older) utilities for loading and unloading modules -- insmod and rmmod -- but they aren't as sophisticated and don't handle dependencies, so we're going to avoid them for now. But they will suddenly become important when we start loading and unloading the modules we write. You'll see that in the next lesson.

Poking at a module with modinfo

If you just want to know about the attributes of a particular module, there's the terrific command modinfo:

$ modinfo btrfs
filename:       /lib/modules/3.3.0-rday+/kernel/fs/btrfs/btrfs.ko
license:        GPL
alias:          devname:btrfs-control
alias:          char-major-10-234
srcversion:     48860D16F770F239F8DF2B7
depends:        libcrc32c,zlib_deflate
intree:         Y
vermagic:       3.3.0-rday+ SMP mod_unload modversions
$

Note that since that's just an informational command, it doesn't require root privilege, and also note that it lists the module's dependencies.

In addition, it doesn't matter if the module is loaded or not, modinfo works equally well. Feel free to check the man page for that command to see how specific you can be in what information you're asking for.

Loadable modules and the kernel address space

Up to now, everything laying the groundwork for finally writing our first loadable kernel module has been fairly straightforward. So let's push the envelope a bit to finish this lesson off and show you something you might not have seen before.

Future lessons are going to get into working in the kernel address space, and which symbols are available in that address space and which aren't, and how loading your module affects what gets added. Well, let's look at the kernel address space symbol table right now:

$ less /proc/kallsyms
0000000000000000 D irq_stack_union
0000000000000000 D __per_cpu_start
0000000000000000 D gdt_page
0000000000000000 d exception_stacks
0000000000000000 d tlb_vector_offset
0000000000000000 d cpu_loops_per_jiffy
0000000000000000 D xen_vcpu_info
0000000000000000 D xen_vcpu
0000000000000000 d idt_desc
... etc etc ...

That listing typically goes on for tens of thousands of lines, and represents the various types of symbols and their corresponding addresses in the kernel address space. We'll be digging into that output in far more detail in a later lesson.

Coming next -- writing and loading your very own module

At this point, we've covered everything you'll need to finally write, compile and load your very first LKM. And that's what's coming in the next lesson. You seriously don't want to miss that.

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <br> <pre> <h1> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.