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.
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
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).
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. Here's the printk code from a recent Linux kernel version:
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
int r;
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);
return r;
}
The function vprintk, which is called by printk, does most of the work.
If we wanted to modify the function printk using Ksplice, we would first copy the Linux kernel file containing this function (kernel/printk.c) to a new filename in the same kernel subdirectory (for example, “kernel/printk.c.modified”) so that we can make our changes to the copy rather than to the original:
user@localhost:~$ cd ~/linux-source/kernel user@localhost:~/linux-source/kernel$ cp printk.c printk.c.modified
We would then open the new file (printk.c.modified) in our editor of choice and make the desired code changes:
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
int r;
vprintk("Quoth the kernel:\n", NULL);
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);
return r;
}
Adding this line causes all messages printed using printk to be preceded by the text “Quoth the kernel:”.
We can then create our update and apply it by running the following two commands:
user@localhost:~/linux-source/kernel$ ksplice-create --diffext=.modified ~/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 in 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).
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 ksplice_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 ksplice_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)