2    Module Initialization

Kernel module initialization refers to the tasks necessary to incorporate a kernel module into the kernel and make it available for use by the system. After you write your kernel module, you create a single binary image (a file with the .mod extension) from the kernel module source file (usually a C file). This file is loaded into memory and its configure routine is called to perform initialization. Module initialization consists primarily of allocating and initializing data structures and calling on other kernel modules to tell them that your module is loaded and available.

The configure routine manages initialization. This chapter describes how this routine performs a variety of initialization tasks, including:

Other requests to the configure routine, such as reconfiguring the kernel module when an attribute value changes and returning information from the attribute table, are covered in Chapter 3.

2.1    The configure Routine

The configure routine handles requests targeted at the kernel module and performs the required actions. The configure routine's structure is the same for all kernel modules, regardless of the function they perform and whether or not the kernel module is a device driver.

The naming convention for the configure routine requires that the name of the routine be the module name followed by _configure. This allows the module framework to locate the routine and call it. For example, for the kernel module example.mod, the configure routine would be named example_configure.

Note that if your module does not contain a properly named configure routine, one of the following conditions will occur:

2.1.1    Parameters

The configure routine accepts the following parameters:

op (cfg_op_t)

The module framework sets this parameter to one of several request codes that describe the operation the module should perform:

These operations are described in Section 2.1.2.

indata (cfg_attr_t)

Specifies a pointer to an array of data structures that contain information about the attributes in your kernel module attribute table, plus status information. The module framework checks the validity of attribute values when it copies attributes into memory, and it sets the status to indicate whether the value passes those tests.

indatalen (size_t)

Specifies the number of structures in the indata array.

outdata (cfg_attr_t)

Specifies a pointer to a module-specific output data structure when the op parameter specifies a subsystem-defined operation. Otherwise, its value is NULL.

outdatalen (size_t)

Specifies the size of the outdata parameter in bytes.

Typically, the configure routine is written as a switch statement, with one case statement to handle each operation.

For example:

int example_configure (cfg_op_t op,         
                       cfg_attr_t *indata,  
                       size_t indatalen,    
                       cfg_attr_t *outdata, 
                       size_t outdatalen)   
{
    int status;.
    
.
.
.
switch(op) { case CFG_OP_CONFIGURE: status=value;
.
.
.
break; case CFG_OP_QUERY: status=value;
.
.
.
break; case CFG_OP_UNCONFIGURE: status=value;
.
.
.
break; case CFG_OP_RECONFIGURE: status=value;
.
.
.
break; default: status=ENOTSUP; break; }   return (status); }

The ENOTSUP error return value indicates that the kernel module does not support the requested operation. Otherwise, the routine returns a status value appropriate for the request. (See Section 2.1.3 for information on return status values.)

2.1.2    Request Codes

The configure routine accepts several parameters (see Section 2.1.1 for a list of all parameters accepted by the configure routine). The op parameter takes one of the following request codes, which describe the specific operation the module should perform:

2.1.3    Return Status Values

The configure routine may return any standard status value from the file /usr/include/errno.h as an int to the module framework. The following list defines the most common return status values:

The return status value is later appended to the higher 16 bits of a final return that is returned to the caller. The module framework status resides in the lower 16 bits of the return status.

2.2    Module Initialization

Before a kernel module can be useful, it typically needs to initialize data structures and let other kernel modules know that it exists and is available. The module framework calls the configure routine with the CFG_OP_CONFIGURE request code to alert the module to perform initialization. Likewise, the module framework passes the CFG_OP_UNCONFIGURE request code to alert the kernel module to prepare for removal from the system. These codes are described in detail in the following sections.

2.2.1    Receiving the CFG_OP_CONFIGURE Request

The module framework calls the configure routine with the CFG_OP_CONFIGURE request code to request that the module perform its one-time initialization. This is always the first call into the module, regardless of whether it is statically or dynamically loaded. If the kernel module is statically loaded, the module framework calls the configure routine very early in the boot timeline. Because of this, the kernel module typically registers callback routines to execute immediately or at specific dispatch points to perform initialization tasks. These tasks include:

When you code your kernel module initialization process using callbacks, the result is a single binary image that can be loaded statically or dynamically. Otherwise, your kernel module will be either a static module or a dynamic module, but not both. Chapter 4 expands on this concept by discussing the relationship between callbacks and dispatch points. The following sections present further considerations for modules that are loaded either statically or dynamically.

2.2.1.1    Implementing Statically or Dynamically Loaded Kernel Modules

When a kernel module is statically loaded, it is linked as part of /vmunix and loaded into memory as part of the kernel. The module framework must call the configure routine with the CFG_OP_CONFIGURE request code before memory can be allocated, locks can be used, and subsystems can be used. As a result, a statically loaded module typically is not able to perform initialization when its configure routine is called with the CFG_OP_CONFIGURE request code. Instead, it registers callbacks that are invoked when these resources become available as the system boots. In contrast, a dynamically loaded module is linked as its own image and loaded into memory on its own. If you used callbacks in a dynamically loaded module, the initialization still occurs properly.

To overcome the problem of resources not being available for a statically loaded module, the configure routine registers callback routines to be called at specific dispatch points, as described in Chapter 4. Initialization takes place when these callback routines are called. Callbacks enable your module to be a single binary image that can be statically or dynamically loaded.

2.2.1.2    Checking the Configuration

To handle initialization correctly, whether your module is statically loaded or dynamically loaded, global variables keep track of the following information:

2.2.1.3    Allocating Memory for Data Structures

Your kernel module may need to allocate memory for data structures during initialization. You must wait until the CFG_PT_VM_AVAIL dispatch point occurs. When you are ready to allocate memory, you use the MALLOC macro. (Use the FREE macro to deallocate memory.) See Section 5.3.7 for more information about allocating memory.

2.2.2    Receiving the CFG_OP_UNCONFIGURE Request

The module framework calls the configure routine with the CFG_OP_UNCONFIGURE request code to have both statically loaded and dynamically loaded kernel modules prepare to go off line. When modules are brought off line, they are not available for use by any other module in the kernel. Only dynamically loaded kernel modules can actually be unloaded. Statically loaded modules remain loaded once they are brought off line. (See Section 2.2.1.2 to determine how the kernel module was loaded.)

When a module (static or dynamic) has successfully gone off line, it should return ESUCCESS.

To prepare to go off line, the kernel module must accomplish the following tasks before returning a success status value to the module framework:

A kernel module (static or dynamic) can determine that it cannot be unloaded. In this case, the module should return an error to the module framework to keep it from attempting to unload the module.