Tuesday, November 20, 2007

Module/kernel parameters

Sometimes it's desirable to pass some arguments to module to customize its behavior, e.g.: to set/unset verbosity level of debug output, set operation mode etc... Linux modules can get this information from insmod utility, but kldload is not capable of doing such kind of things. What a pity. But don't get desperate - tunables to the rescue!

Just like an ordinary command shell (bash, csh, sh) kernel has its own environment, the set of <name, value> pairs. You can get, set, test, unset these variables using getenv, setenv, testenv, unsetenv functions in the kernel and kenv(2) syscall or kenv(1) command in userland. So if you want to set verbosity level for module, you would do something like this:

# kenv zaptel.debug=1
# kldload ./zaptel.ko

and then in module initialization routine:

static int debug = 0; /* Hush-hush */
char * value = getenv("zaptel.debug");
if (value) {
debug = strtol(value, NULL, 10);

Too much code for such a simple task, don't you think? Yeah, like for every common task there are useful macroses defined in kernel headers, you should just find them. Heavy coffeinated kernel hackers knew most of them. In this particular case neat code would look something like that (for statically initialized variable):

static int debug = 0; /* Hush-hush */
TUNABLE_INT("zaptel.debug", &debug);

or, if debug is the member of structure or local variable:

sc->debug = 0;
TUNABLE_INT_FETCH("zaptel.debug", &sc->debug);

TUNABLE_XXX macroses exist for INT, LONG, ULONG and STR types. TUNABLE_STR unlike the others requires third parameter - maximum size of the string. For a dynamic value retrieval every type has TUNABLE_XXX_FETCH macro defined. Nota bene: if there is no environent variable set with requested name, the value of acceptor variable remains untouched.


misamoll said...

do you know, how to make common/shared variables for different kernel modules ? How can one module export its symbols to another kernel module, or how can some module acces variables from other kernel modules ?


Oleksandr Tymoshenko said...

It's all done in automated fashion by dynamic kernel loader. So let's say you have
modulea.c with
int global_module_a_var = 99;
modulea.h with
extern int global_module_a_var;
and moduleb.c with
#include "modulea.h"
printf("from a: %d\n", global_module_a_var);

you should load modulea before moduleb and everything should work out of the box.

misamoll said...

no, it doesen't work.
after kldload in terminal i have:
kldload: can't load ./mymod2.ko: No such file or directory

and in messages:
link_elf: symbol global_module_a_var undefined

It's not so easy.Sure, i have tested this variant.

Oleksandr Tymoshenko said...

modb should contain something like:
MODULE_DEPEND(modb, moda, 1, 1, 1);
So you should explicitly define module dependency. It's done in order to prevent symbols in a from accidental "disappearance" as a result of "kldunload moda"

misamoll said...

Ok, thanx very much for your help. Now it works. I tried to find some information about exporting of symboles from kernel modules. But I could not find anything helpfull. Man page of MODULE_DEPEND doesen't say anything about exporting of symbols, but it really works :)
Are there some papers , that describe these problems ? Or schould I be able to find it out from kernel source code ?
It would be very nice if you can give me some URL to this theme.


David said...

Exporting symbols doesn't seem to work when the module is pre-loaded in loader.conf. Is there a solution for this?