Modules
This chapter describes how the Linux kernel can dynamically load functions,
for example filesystems, only when they are needed.
Linux is a monolithic kernel;
that is, it is one, single, large program
where all the functional components of the kernel have access to all
of its internal data structures and routines.
The alternative is to have a micro-kernel structure where
the functional pieces of the kernel are broken out into separate units
with strict communication mechanisms between them.
This makes adding new components into the kernel via the configuration
process rather time consuming.
Say you wanted to use a SCSI driver for an NCR 810 SCSI and you had
not built it into the kernel.
You would have to configure and then build a new kernel before you
could use the NCR 810.
There is an alternative, Linux allows you to dynamically load
and unload components of the operating system as you need them.
Linux modules are lumps of code that can be dynamically linked into the
kernel at any point after the system has booted.
They can be unlinked from the kernel and removed when they are no longer
needed.
Mostly Linux kernel modules are device drivers, pseudo-device drivers
such as network drivers, or file-systems.
You can either load and unload Linux kernel modules explicitly using
the insmod and rmmod commands or the kernel itself can demand
that the kernel daemon (kerneld) loads and unloads the modules as they are needed.
Dynamically loading code as it is needed is attractive as it keeps the
kernel size to a minimum and makes the kernel very flexible.
My current Intel kernel uses modules extensively and is only 406Kbytes long.
I only occasionally use VFAT file systems and so I build my Linux kernel
to automatically load the VFAT file system module as I mount a VFAT
partition.
When I have unmounted the VFAT partition the system detects that I no
longer need the VFAT file system module and removes it from the system.
Modules can also be useful for trying out new kernel code without having
to rebuild and reboot the kernel every time you try it out.
Nothing, though, is for free and there is a slight performance and
memory penalty associated with kernel modules.
There is a little more code that a loadable module must provide
and this and the extra data structures take a little more memory.
There is also a level of indirection introduced that makes accesses of
kernel resources slightly less efficient for modules.
Once a Linux module has been loaded it is as much a part of the kernel
as any normal kernel code.
It has the same rights and responsibilities as any kernel code; in other
words, Linux kernel modules can crash the kernel just like all kernel
code or device drivers can.
So that modules can use the kernel resources that they need, they must
be able to find them.
Say a module needs to call kmalloc(), the kernel memory allocation
routine.
At the time that it is built, a module does not know where in memory
kmalloc() is, so when
the module is loaded, the kernel must fix up all of the module’s
references to kmalloc() before the module can work.
The kernel keeps a list of all of the kernel’s resources in the kernel symbol
table so that it can resolve references to those resources from the modules
as they are loaded.
Linux allows module stacking, this is where one module requires the
services of another module.
For example, the VFAT file system module requires the services
of the FAT file system module as the VFAT file system is more
or less a set of extensions to the FAT file system.
One module requiring services or resources from another module is very
similar to the situation where a module requires services and resources
from the kernel itself.
Only here the required services are in another, previously loaded
module.
As each module is loaded, the kernel modifies the kernel symbol table,
adding to it all of the resources or symbols exported by the newly
loaded module.
This means that, when the next module is loaded, it has access to
the services of the already loaded modules.
When an attempt is made to unload a module, the kernel needs to know
that the module is unused and it needs some way of notifying the module
that it is about to be unloaded.
That way the module will be able to free up any system resources that it
has allocated, for example kernel memory or interrupts, before it is
removed from the kernel.
When the module is unloaded, the kernel removes any symbols that that module
exported into the kernel symbol table.
Apart from the ability of a loaded module to crash the operating system
by being badly written, it presents another danger.
What happens if you load a module built for an earlier or later kernel
than the one that you are now running?
This may cause a problem if, say, the module makes a call to a kernel routine
and supplies the wrong arguments.
The kernel can optionally protect against this by making rigorous version
checks on the module as it is loaded.