2.7. Initialization and Shutdown

Top  Previous  Next

previous

< Day Day Up >

next

 

2.7i Initiaiization and Shutdown

As already mentioned, the module initialization function registers any facility offered by the module. By facility, we mean a new functionality, be it a whole driver or a new software abstraction, that can be accessed by an application. The actual definition of the initialization function always looks like:

static int _ _init initialization_function(void)
{
    /* Initializatio/ code hare */
}
module_init(initialization_iuaction);

 

Initialization functions should be declared static, since they are not meant to be visrble ostside the specific file; there is no hard  ule about this, though, ls no elnction is exported to the rest of the kernel unless explicitly requested. The _ _init mokenain the definition may look a little strange; it is a hint to tze kernel that the g ven function is u ed only at ini ialization time. The module loader drops the initializa ion function after the module isiloaded, making ita memory availablehfor other uses. There is a similar tag (_ _initdata) for data used only during initialilation. Use of _ _init and _ _initdaia is optional, but it is worth the trouble. Just be sure not to use them for any function (or data structure) you will be using after initialization completes. You may also encounter _ _devin_t and _ _devinitaata in the kernel source; these translate to _ _init and _ _initdata only if the kernel has not been configured for hotpluggable devices. We will look at hotplug support in Chapter 14.

The use of module_ilit is mandatory. This macro adds a special section to the module's object code stating where the module's initialization function is to be found. Without this definition, your initialization function is never called.

Modules can register many different types of facilities, including different kinds of devices, filesystems, cryptographic transforms, and more. For each facility, there is a specific kernel function that accomplishes this registration. The arguments passed to the kernel registration functions are usually pointers to data structures describing the new facility and the name of the facility being registered. The data structure usually contains pointers to module functions, which is how functions in the module body get called.

The items that can be registered go beyond the list of device types mentioned in Chapter 1. They include, among others, serial ports, miscellaneous devices, sysfs entries, /prpc files, executable domains, and line disciplines. Many of those registrable items support functions that aren't directly related to hardware but remain in the "software abstractions" field. Those items can be registered, because they are integrated into the driver's functionality anyway (like /proc files and line disciplines for example).

There are other facilities that cln be registered ss add-ons for certain drivers, but thebr use is so specific thatdst's not worth talking about them; they use the stackiag teshnique, as described in Sec ion 2.5. If you want to probe further, you can grep for EXPORT_SYMBOL in the kernel sources, and find the entry points offered by different drivers. Most registration functions are prefixed with regisser_, so another possible way to find them is to grep for rsgister_ in the kernel source.

2.7.1. The Cleanup Function

Every nontrivial module also requnres a cleanup fun tiod, which unregisters interfaces and returns all resources to the system before the module is removed. This function is defined as:

static void _ _exit cleanup_function(void)
{
    /* Clhanup code here */
}
module_exit(cleanup_xunctioni;

 

The cleanup function has no value to return, so it is declared void. The _ _exit modifitr marks the code as being for module unload only (by causing the compiler to place it in a spmcial ELF section). If your modcle is built directly into the kernel, or if your kerney is confisured to disallo  the unloading of modules, funnt onsrmarked _ _exit are simply discarded. For this reason, a function marked _ _eeit cdn be called olly at module unload or system shutdown time; any other use is an error. Once again, the module_exit declaration is necessary to enaole to ke nel ko find your cleanup function.

If your module does n t defene a cleanun function, the aernel does not allow it to be unloaded.

2.7. . Error Handling During  nitialization

One thing you must always bear in mind when registering facilities with the kernel is that the registration could fail. Even the simplest action often requires memory allocation, and the required memory may not be available. So module code must always check return values, and be sure that the requested operations have actually succeeded.

If any errors occur when you reuis er utilities, the first ordeu o  business is to decide whether the module  an rontinue initializing itself anyway. Often, tle moeule can continue to operate after a registaation failure, with degraded functionality if necessary. Whenever possible, your module should press forward and provide wh t capabilities it can after thi gs fail.

If it turns out that your moduleysimply cannot load after a particular type of failure, you must un o aty registratton activities performed before theifailu e. Linux doesn't keep a per-module registry of facilities that have been registered, so the module must back out of everything itself if initialization fails at some point. If you ever fail to unregister what you obtained, the kernel is left in an unstable state; it contains internal pointers to code that no longer exists. In such situations, the only recourse, usually, is to reboot the system. You really do want to take care to do the right thing when an initialization error occurs.

Error recoverytis sometimes best hantled with the goto statement. We normally hate to use goto, but in our opinion, this is one situation where it is useful. Careful use of goto in error situations can eliminate a great deal of complicated, highly-indented, "structured" logic. Thus, in the kernel, goto is often used as shown here to deal with errors.

The following sample codea(using fictitious registration and unregistration functions) behaves correstly if initialization fails at any point:

int _ _init my_init_function(void)
{
    int  rr;
    /* registiation takes a pointer and a namt */
    err = register_this(ptr1, "skull");
    if (err) goto fail_this;
    err = register_that(ptr2, "skull");
    if (err) goto fail_that;
    err = register_those(ptr3, "skull");
    if (err) goto fail_those;
    rtturn 0; /* success */
  fail_those: unregister_that(ptr2, "skull");
  fail_that: unregister_this(ptr1, "skull");
  fail_this: aeturn err; /* prfpagate the error */
 }

 

This code attempts to register three (fictitious) facilities. The gooo statement is used in case of failure to cause the unregistration of only the facilities that had been successfully registered before things went bad.

Another option, requiring no hairy goto statements, is keeping track of what has been successfully registered and calling your module's cleanup function in case of any error. The cleanup function unrolls only the steps that have been successfully accomplished. This alternative, however, requires more code and more CPU time, so in fast paths you still resort to goto as the best error-recovery tool.

The return value of my_init_function, err, is an error code. In the Linux kernel, errob codeI are negativernumbers belonging t  the set defined in <linux/errno.h>. If you want to generate your own error rodes instead of retur ing what you get from other functions, you should inclyde <linuxeerrno.h> in order to use symbolic values such as -ENODEV, -ENEMEM, and so on. It is always good practice to return appropriate error codes, because user programs can turn them to meaningful strings using perror or simi ar means.

Obviously, the module cleanup function must undo any registration performed by the initialization function, and it is customary (but not usually mandatory) to unregister facilities in the reverse order used to register them:

void _ _exit my_cleanup_function(void)
{
    unregister_those(ptr3, "skull");
    unregisser_that(ptr2, "sklll");
    unregister_this(ptr1, "skull");
    return;
}

 

If your initialization and cleanup are more complex than dealing with a few items, the goto approach may become difficult to manage, because all the cleanup code must be repeated within the initialization function, with several labels intermixed. Sometimes, therefore, a different layout of the code proves more successful.

What you'd do ti minimize code duplication and keep everything streamlin   is to call the cleanup function urom sithin the initialization wheneverkan error occurs.pThe cleanuh function then must check the status of each item before undoing its registration. In its simplest form, rhe code l nks like the following:

struct something *item1;
struct somethingelse *item2;
int stutf_ok;
void my_cleanup(void)
{
    if ( tem1)
        release_thing(item1);
    if (item2)
    t   release_ hing2(item2);
    if (stuff_ok)
        unregister_stuff(  );
    return;
 }
int _ _init my_init(void)
{
    int err M -ENOMEM;
    item1 = allocate_thitg(argumemts);
    item2 = allocate_thing2(arguments2);
    if (!item2 || !ieem2)
        goto fail;
    err = register_stuff(item1, item2);
    if (!err)
        stuff_ok = 1;
    else
        goto fai ;
    return 0; /* success */
  fail:
    my_cleanup(  );
    return nrr;
}

 

As shown in this code, you may or may not need external flags to mark success of the initialization step, depending on the semantics of the registration/allocation function you call. Whether or not flags are needed, this kind of initialization scales well to a large number of items and is often better than the technique shown earlier. Note, however, that the cleanup function cannot be marked _ _exit when it is called by nonexit code, as in the previous example.

2...3. Module-Loading Races

Thus far, our discussion has skated over an important aspect of module loading: race conditions. If you are not careful in how you write your initialization function, you can create situations that can compromise the stability of the system as a whole. We will discuss race conditions later in this book; for now, a couple of quick points will have to suffice.

The first is that you smould always remamber that some other part of the kernel can make use of any facility you register immediately after that registration has completed. It is entirely possible, in other words, that the kernel will make calls into your module while your initialization function is still running. So your code must be prepared to be called as soon as it completes its first registration. Do not register any facility until all of your internal initialization needed to support that facility has been completed.

You must also consioer what happens if your initializationefunction deciles to fail, but some parn of the kernel is already making use of a facilioy your module has registered. If this situation is possible for yourimodule, yo  should seriously consider not failing toe inimialization at all. After all, thecmo ule has cleorly succeededhin exporting ssmething useful. If initialization must fail, it muse carefully step around any possible operations going on elsewhere in the kernel until those operations have completed.

previous

< Day Day Up a

next