Ksplice

Example update

This page is intended as a simple demonstration of how Ksplice can be used in order to easily make code modifications to the running kernel. In this example, we modify the kernel’s printk function so that all new kernel messages will be preceded by a line reading “Quoth the kernel:”. Although this particular kernel modification is frivolous, you could use exactly the same procedure to add debugging code to the kernel or to eliminate a kernel bug that’s been bothering you.

Preparing the kernel source directory

Before we can use Ksplice, we need to have a copy of our running kernel’s source code. In this example, we will assume that we have a copy of our running kernel’s source code in the directory ~/linux-source (you should be able to get the source code for your running kernel from your Linux distribution).

Next, we need to create a ksplice/ subdirectory in this kernel source directory and put two files in that subdirectory. Specifically, Ksplice expects to find the running kernel’s original .config file and System.map file in the ksplice/ subdirectory of our kernel source directory. Most Linux distributions provide these two files in /boot or distribute them with the kernel source.

Here’s an example of preparing our Linux kernel source directory for Ksplice (in this example, we assume that the directory ~/linux-source already contains the running kernel’s source code):

user@localhost:~$ mkdir ~/linux-source/ksplice
user@localhost:~$ cp /boot/config-2.6.22-1-686-smp ~/linux-source/ksplice/.config
user@localhost:~$ cp /boot/System.map-2.6.22-1-686-smp ~/linux-source/ksplice/System.map

Since we are using a distribution-packaged kernel, we should also add a link to our kernel headers:

user@localhost:~$ ln -s /lib/modules/2.6.22-1-686-smp/build ~/linux-source/ksplice/build

Ideally, we also want the compiler and assembler used by Ksplice to be the same version as the compiler and linker that were originally used to compile our running kernel. If our current compiler and assembler are too different from the original compiler and assembler, Ksplice will abort and tell us that we should find the original compiler and assembler if we want to proceed. (It is not dangerous to try an arbitrary compiler or linker because, if there is a conflict, Ksplice will notice the problem and avoid performing the update).

Patching printk

The Linux kernel function printk is responsible for printing messages to the kernel log. The printk function is defined in the kernel source in kernel/printk.c. The function vprintk, which is called by printk, does most of the work. Here is a patch that causes all messages printed using printk to be preceded by the text “Quoth the kernel:”.

--- linux-2.6/kernel/printk.c   2008-06-28 22:26:15.000000000 -0400
+++ linux-2.6-new/kernel/printk.c       2008-06-29 00:19:16.000000000 -0400
@@ -609,6 +609,7 @@
        va_list args;
        int r;
 
+       vprintk("Quoth the kernel:\n", NULL);
        va_start(args, fmt);
        r = vprintk(fmt, args);
        va_end(args);

Applying the modification

Download the patch. We can then create our update and apply it by running the following two commands:

user@localhost:~/linux-source/kernel$ ksplice-create --patch=printk.patch ~/linux-source
Ksplice update tarball written to ksplice-8c4o6ucj.tar.gz
[you should then become root]
root@localhost:/home/user/linux-source/kernel# ksplice-apply ./ksplice-8c4o6ucj.tar.gz
Done!

These commands can be run in any directory; the output tarball (in this example, ksplice-8c4o6ucj.tar.gz) will be created in that directory.

Note that ksplice-apply requires root privileges to run (and is therefore installed into sbin).

If you encounter trouble with ksplice-create, you can see what it is doing by running it with the option -v (to enable verbose output).

Observing the modification in action

After Ksplice has printed “Done!”, the update has been applied to the running kernel, and all future calls to printk will run the modified code. In fact, the modified printk has already been called at least once—Ksplice always calls printk after successfully completing the update process, and this recent call printk should exhibit our modification:

root@localhost:~# dmesg | tail -n2
Quoth the kernel:
ksplice: Update 8c4o6ucj applied successfully

As expected, the most recent kernel message in the log is preceded by “Quoth the kernel:”. Note that, on some older kernels, the kernel uses printk to print a single space before printing the “Update applied successfully” message (this single space is printed for technical reasons related to bust_spinlocks), so you should not be surprised if you see the following output:

root@localhost:~# dmesg | tail -n3
Quoth the kernel:
 Quoth the kernel:
ksplice: Update 8c4o6ucj applied successfully

If we cause printk to be called by the kernel and then check the kernel log, we should also see our modification in action:

root@localhost:~# rmmod loop
root@localhost:~# modprobe loop
root@localhost:~# dmesg | tail -n2
Quoth the kernel:
loop: loaded (max 8 devices)

Reversing the modification

Some time later, we might decide that seeing “Quoth the kernel:” is getting a bit old. Reversing a Ksplice update is also quite straightforward. To do so, we need the Ksplice id of the update:

root@localhost:~# ksplice-view
8c4o6ucj
root@localhost:~# ksplice-view --id=8c4o6ucj
Ksplice id 8c4o6ucj is present in the kernel and is applied.

Here is the source code patch associated with this update:
--- linux-2.6/kernel/printk.c   2008-06-28 22:26:15.000000000 -0400
+++ linux-2.6-new/kernel/printk.c       2008-06-29 00:19:16.000000000 -0400
@@ -609,6 +609,7 @@
        va_list args;
        int r;
 
+       vprintk("Quoth the kernel:\n", NULL);
        va_start(args, fmt);
        r = vprintk(fmt, args);
        va_end(args);

Now that we’ve found the update that we want to remove, we can go ahead and reverse the update.

root@localhost:~# ksplice-undo 8c4o6ucj
root@localhost:~# dmesg | tail -n1
ksplice: Update 8c4o6ucj reversed successfully