Previous Next Table of Contents

9. Initialization

A lot of kernel code and data is used just during initialization and never used later on. This lead to the idea of discarding this code and data once kernel or module initialization is complete. Like this, you can save several hundred kilobytes of precious unswappable kernel memory. The generic code to do all this is just a couple of lines, the most of the work with initialization sections has to done by authors of all the drivers and other kernel code in separating initialization code and data from code and data, that might be executed or referenced after initialization finishes. To do this, one has to include <linux/init.h> header file and for initialization functions put __initfunc( ) around function header, like in the following piece of code:

static int my_initfunc(int arg)
{
        return arg+3;
}

should be changed to:

__initfunc(static int my_initfunc(int arg))
{
        return arg+3;
}
Before you do this, make sure the function cannot be ever referenced after initialization is complete. That is right before /sbin/init is spawned for code compiled into the kernel and right after init_module finishes for a module. Easiest way is to go and mark as initialization functions the entry initialization routine (for in kernel code) or init_module (this function is marked as initialization already in the headers, so you don't have to specify this explicitly) and then check all functions they call. If those functions are just referenced in initialization functions, you can add them. You don't have to mark all the initialization routines as described above - another way how to get the same effect is to make the function inline; if it will be inlined into some initialization function, it will be discarded as well. This is often the best solution, if some function is referenced only once. You might also have data, which you reference only during initialization. This is usually the case with various firmware codes you download once into the card. You can do this only with initialized data (otherwise compiler generates warnings and puts the variables into normal bss section), and the syntax is very simple: you put the word __initdata between the name of the variable and the = sign which assigns a value to the variable, like in the following code:
static char my_data[] __initdata = { 0x14, 0x8b };
So that discarding of initialization sections works in modules, you'll need fairly recent modutils package.

All this magic is done through ELF sections. You should remember these tricks, they are used more and more in the kernel (currently for example for the new user access exception handling, in kernel module support (module parameters, exported symbols)) and you might find them useful during your kernel hacking. One of the tricks planned for 2.3 kernels is a special ELF section which will contain driver structures. Such driver structure will describe the driver (name and attributes), the bus it can be found on (e.g. PCI, ISA, SBUS, UPA, NuBUS, etc.), the category of the driver (console, scsi, block device, character device), bus specific attributes (like PCI VendorIDs and DeviceIDs, SBUS and UPA PROM names, etc.) and perhaps some ordering stuff within each category (so that users don't complain about the order of detected adapters). With such driver structures, we'll be able to get rid of such ugly files like Space.c (listing all network adapter initialization functions), hosts.c (the same for SCSI), etc. You will just call generic kernel functions initalize_all_buses(), initialize_all_scsi_hosts() etc. Those functions will just go through that ELF section, check the compiled in drivers and call their initialization routines if appropriate.


Previous Next Table of Contents