Linux Device Drivers (3rd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Linux Device Drivers (3rd Edition) [Electronic resources] - نسخه متنی

Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








2.7. Initialization 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)
{
/* Initialization code here */
}
module_init(initialization_function);

Initialization functions should be declared
static, since they are not meant to be visible
outside the specific file; there is no hard rule about this, though,
as no function is exported to the rest of the kernel unless
explicitly requested. The _ _init token in the
definition may look a little strange; it is a hint to the kernel that
the given function is used only at initialization time. The module
loader drops the initialization function after the module is loaded,
making its memory available for other uses. There is a similar tag
(_ _initdata) for data used only during
initialization. Use of _ _init and _
_initdata
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
_ _devinit and _ _devinitdata
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_init

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, /proc 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 can be registered as add-ons for certain
drivers, but their use is so specific that it's not
worth talking about them; they use the stacking technique, as
described in Section 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 register_, so another
possible way to find them is to grep for register_
in the kernel source.


2.7.1. The Cleanup Function


Every nontrivial module also requires a cleanup function, 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)
{
/* Cleanup code here */
}
module_exit(cleanup_function);

The
cleanup
function has no value to return, so it is declared
void. The _ _exit modifier
marks the code as being for module unload only (by causing the
compiler to place it in a special ELF section). If your module is
built directly into the kernel, or if your kernel is configured to
disallow the unloading of modules, functions marked _
_exit
are simply discarded. For this reason, a function
marked _ _exit can be called only
at module unload or system shutdown time; any other use is
an error. Once again, the module_exit
declaration is necessary to enable to kernel to find your cleanup
function.

If your module does not define a cleanup function, the kernel does
not allow it to be unloaded.


2.7.2. Error Handling During Initialization


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 register utilities, the first order of
business is to decide whether the module can continue initializing
itself anyway. Often, the module can continue to operate after a
registration failure, with degraded functionality if necessary.
Whenever possible, your module should press forward and provide what
capabilities it can after things fail.

If it turns out that your module simply cannot load after a
particular type of failure, you must undo any registration activities
performed before the failure. 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
recovery is sometimes
best
handled 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 code (using fictitious registration and
unregistration functions) behaves correctly if initialization fails
at any point:

int _ _init my_init_function(void)
{
int err;
/* registration takes a pointer and a name */
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;
return 0; /* success */
fail_those: unregister_that(ptr2, "skull");
fail_that: unregister_this(ptr1, "skull");
fail_this: return err; /* propagate the error */
}

This code attempts to register three (fictitious) facilities. The
goto 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, error codes are negative numbers
belonging to the set defined in
<linux/errno.h>. If you want to generate
your own error codes instead of returning what you get from other
functions, you should include
<linux/errno.h> in order to use symbolic
values such as -ENODEV,
-ENOMEM, 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 similar
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");
unregister_that(ptr2, "skull");
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 to minimize code duplication and keep
everything streamlined is to call the cleanup function from within
the initialization whenever an error occurs. The cleanup function
then must check the status of each item before undoing its
registration. In its simplest form, the code looks like the
following:

struct something *item1;
struct somethingelse *item2;
int stuff_ok;
void my_cleanup(void)
{
if (item1)
release_thing(item1);
if (item2)
release_thing2(item2);
if (stuff_ok)
unregister_stuff( );
return;
}
int _ _init my_init(void)
{
int err = -ENOMEM;
item1 = allocate_thing(arguments);
item2 = allocate_thing2(arguments2);
if (!item2 || !item2)
goto fail;
err = register_stuff(item1, item2);
if (!err)
stuff_ok = 1;
else
goto fail;
return 0; /* success */
fail:
my_cleanup( );
return err;
}

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.7.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 should always
remember 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 consider what happens if your initialization function
decides to fail, but some part of the kernel is already making use of
a facility your module has registered. If this situation is possible
for your module, you should seriously consider not failing the
initialization at all. After all, the module has clearly succeeded in
exporting something useful. If initialization must fail, it must
carefully step around any possible operations going on elsewhere in
the

kernel
until those operations have completed.


    / 202