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