Lesson 9: All about module parameters

Printer-friendly versionPrinter-friendly version

So what's a module parameter?

Actually, it's exactly what it sounds like. Until now, you've gotten used to simply loading your module and having its entry routine run as is. However, you can define command-line, load time parameters for your module that allow you to customize its behaviour. For instance, you might want to define a debugging setting that forces the module to generate additional debugging information to the appropriate log file as it runs, such that loading that module would look something like this:

$ sudo insmod mymodule.ko debug=1

And that's what this lesson is all about. But first, let's do a quick recap.

Your spanking new crash4 module

Let's start with a completely generic, predictable module that introduces nothing new, and that you should be able to build, load and unload with what you've learned so far:

/* Module source file 'crash4.c'. */

#include <linux/module.h>   // for all modules
#include <linux/init.h>     // for entry/exit macros
#include <linux/kernel.h>   // for printk() definition

static int __init crash4_hi(void)
{
     printk(KERN_INFO "crash4 module being loaded.\n");
     return 0;
}

static void __exit crash4_bye(void)
{
    printk(KERN_INFO "crash4 module being unloaded.\n");
}

module_init(crash4_hi);
module_exit(crash4_bye);

MODULE_AUTHOR("Robert P. J. Day, http://crashcourse.ca");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Testing module parameters.");

At this point, I'm not going to reproduce the corresponding Makefile, since you should be able to write those in your sleep by now. Or, at the very least, simply steal the code from earlier lessons.

And one more thing -- you'll notice above that I've given the entry and exit routines more module-specific names, just so I can more easily identify them later in the kernel address space. You don't need to do that since (as experienced programmers will notice) those routines are declared as static and therefore won't clash with anything else in the kernel address space; it's just more convenient when we're scanning the kernel symbol table looking for traces of our module.

So, let's compile your crash4 module, and query it:

$ modinfo crash4.ko
filename:       crash4.ko
description:    Testing module parameters.
license:        GPL
author:         Robert P. J. Day, http://crashcourse.ca
srcversion:     5C2098578F5A3D8984017CD
depends:        
vermagic:       2.6.32-22-generic SMP mod_unload modversions 

That looks good so lets load it and, as we did in an earlier lesson, see what shows up in the kernel symbol table:

$ sudo insmod crash4.ko
$ grep crash4 /proc/kallsyms
ffffffffa05de000 t crash4_bye	[crash4]
ffffffffa05de0a0 d __this_module	[crash4]
ffffffffa05de000 t cleanup_module	[crash4]
$

Obviously, loading that module added a few symbols to the kernel symbol table, but note that, while the module's exit routine can be seen there, the entry routine is missing, which should come as no surprise since, as we tagged it with the qualifier __init, it was discarded after loading.

And once we unload that module, well, it's all gone again:

$ sudo rmmod crash4
$ grep crash4 /proc/kallsyms
$ 

All of that was entirely predictable. Now let's introduce a simple variable into the mix.

The answer is always 42

Let's extend our crash4 module with a simple static (that is, local) variable thusly:

... snip ...
static int answer = 42;

static int __init crash4_hi(void)
{
    printk(KERN_INFO "crash4 module being loaded.\n");
    printk(KERN_INFO "Initial value of answer = %d.\n", answer);
    return 0;
}

static void __exit crash4_bye(void)
{
    printk(KERN_INFO "crash4 module being unloaded.\n");
    printk(KERN_INFO "Final value of answer = %d.\n", answer);
}
... snip ...

There's clearly nothing tricky about what's happening above -- you've defined a local variable named answer whose initial value is 42, and whose final value (since you don't change it anywhere) will also be 42, so loading and unloading that module should produce the following in /var/log/messages:

... crash4 module being loaded.
... Initial value of answer = 42.
... crash4 module being unloaded.
... Final value of answer = 42.

And here's where we turn that variable into a parameter.

Defining your first parameter

In order to turn that static variable into a module parameter, extend your module source as follows:

#include <linux/module.h>
#include <linux/moduleparam.h>    // This is new for parameters.
#include <linux/init.h>
#include <linux/kernel.h>

static int answer = 42;

module_param(answer, int, 0644);
MODULE_PARM_DESC(answer, "Life, the universe, etc.");

Now compile the module and take a look at it again, at which point you should see the following difference:

$ modinfo crash4.ko
...
parm:           answer:Life, the universe, etc. (int)
$

At this point, you can test that new parameter two ways.

If you simply load and unload the module as before, you should get exactly the same output as before since you didn't select a new value for your parameter.

On the other hand, if you load with:

$ sudo insmod crash4.ko answer=43

your log file contents should look like:

... crash4 module being loaded.
... Initial value of answer = 43.
... crash4 module being unloaded.
... Final value of answer = 43.

Not surprisingly, both the entry and exit routine print the same value since the entry routine sees the value you passed as the paramater value and since the module code doesn't change that value anywhere, it exits having the same value.

And after you load your module, you'll notice that there's some extra information that's been added to the kernel symbol table:

$ grep crash4 /proc/kallsyms
ffffffffa05fc000 t crash4_bye	[crash4]
ffffffffa05fc118 d answer	[crash4]
ffffffffa05fc0e8 r __param_answer	[crash4]
ffffffffa05fc110 r __param_str_answer	[crash4]
ffffffffa05fc120 d __this_module	[crash4]
ffffffffa05fc000 t cleanup_module	[crash4]
$

But wait. There's more. Much more. We're just getting started.

(Aside: While there are more parameter types than just the int example we're using so far, let's stick with that type -- we'll summarize the other types toward the end of this lesson.)

Module parameters and the /sys filesystem

Another useful feature of module parameters is that even after your module is loaded, you can examine and -- in some cases -- even change the value of parameters on the fly while the module is running.

Assuming your system is configured relatively sanely, chances are you have access to what is called the sys filesystem under the top-level /sys directory, under which you'll find the /sys/module directory containing one subdirectory per loaded module.

So once you load your crash4 module, you should be able to (if you have the tree utility installed) examine your module's properties with:

tree /sys/module/crash4
/sys/module/crash4
|-- holders
|-- initstate
|-- notes
|-- parameters
|   `-- answer
|-- refcnt
|-- sections
|   `-- __param
`-- srcversion

4 directories, 5 files

Specifically, you can display the current contents of the module's answer variable through its parameter with:

$ cat /sys/module/crash4/parameters/answer 
42
$

Note carefully that whenever you examine a module parameter that way, you'll see the value of the underlying variable at the time of examination. In our case, our module isn't doing anything that would change that value so the initial value is all we'll ever see.

But wait ... there's still more.

Changing module parameters on the fly

In addition to simply examining the values of module parameters as above, you might also be able to modify them on the fly, depending on the permissions you defined the parameter with.

Recall the original definition:

static int answer = 42;
module_param(answer, int, 0644);

If you remember your Linux file permissions, the access mode "0644" means read/write for owner, and read for group and others, and that is in fact the permissions you see on that parameter file:

$ ls -l /sys/module/crash4/parameters/answer 
-rw-r--r-- 1 root root ... /sys/module/crash4/parameters/answer
$

In short, if you happen to be root, you can modify that parameter value with something as simple as shell redirection:

$ echo 43 > /sys/module/crash4/parameters/answer
$ cat /sys/module/crash4/parameters/answer
43
$

However, if you try the above on Ubuntu, it's going to fail because of lack of permissions.

You clearly need to have root privilege to modify that parameter file but if you're using Ubuntu, simply using the sudo command is not enough:

$ sudo echo 43 > /sys/module/crash4/parameters/answer 
bash: /sys/module/crash4/parameters/answer: Permission denied
$

To get legitimate root privilege, you can:

$ sudo sh -c "echo 43 > /sys/module/crash4/parameters/answer"
$ cat /sys/module/crash4/parameters/answer
43
$

and there we go.

Exercise for the student: Obviously, test the above with different combinations, and verify that whenever you unload your module, the value printed upon exit represents the last value you assigned to that parameter.

By the way, if you don't like using octal values to represent your parameter permissions, you can include the kernel header file

#include <linux/stat.h>

and take advantage of the OR-compatible bitwise macro definitions in that file:

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

And having explained all that, here's an important disclaimer about writable module parameters. If you define a parameter as being writable, then, yes, you will be able to modify it from user space but your module will not be informed that such a change has occurred. Make sure you appreciate what this means -- when you change that parameter, there is no callback or notification mechanism that informs your module of that; the module simply sees a different value the next time it accesses that variable. You'll see in future lessons that there are different mechanisms for communicating with your modules that do support the idea of notification.

A couple more subtle parameter features

First, if you want to define a module parameter but have no need for it to show up under the /sys directory structure, define it with an access mode of zero. It will still act as a parameter, it will simply not be visible from user space.

Also, you can select a different name for the /sys user space than the one used for the variable in your code, as in:

static int answer = 42;
module_param_named(crash4_answer, answer int, 0644);
MODULE_PARM_DESC(crash4_answer, "Life, the universe, etc.");

The value of that is if you want to keep, say, the module variable relatively short, but have the user space name be much more informative. Or perhaps the other way around -- it's entirely up to you.

The variety of module parameter types

While we've restricted ourselves to just the int module parameter type, there are a number of others including uint, byte, short, ushort, pointers, character strings and more. To see the full list, peruse the kernel header file include/linux/moduleparam.h.

An excellent way to understand any kernel feature is to scan the kernel source tree looking for examples of its usage. Assuming that your system has the module usbhid, use modinfo to check its properties, then examine its source file under drivers/hid/usbhid/hid-core.c to examine its parameters, and compare what you see with what's under the /sys directory.

Do you see anything unusual or worth commenting on?

Comments

__init tag for other routines

In usbhid module, hid_init is the registered function pointer that will be called during module init. hid_init calls hiddev_init() which is also tagged __init.
If the hiddev_init is not tagged as __init, won't the linker check that it is referred by a __init tagged function only (i.e. hid_init). So, can't hiddev_init also be placed in .init.text section even if it is not tagged as __init?

some problem in running above code


/* Module source file 'crash4.c'. */

#include // for all modules
#include // for entry/exit macros
#include // for printk() definition

static int answer = 42;
module_param(answer, int, 0644);
MODULE_PARAM_DESC(answer, "Life ,the universe etc");

static int __init crash4_hi(void)
{
printk(KERN_INFO "crash4 module being loaded.\n");
return 0;
}

static void __exit crash4_bye(void)
{
printk(KERN_INFO "crash4 module being unloaded.\n");
}

module_init(crash4_hi);
module_exit(crash4_bye);

MODULE_AUTHOR("Robert P. J. Day, http://crashcourse.ca");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Testing module parameters.");

Above is the code I tried

and following is the Makefile

ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
.PHONY: build clean
build:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -rf modules.order Module.symvers
else
$(info Building with KERNELRELEASE =${KERNELRELEASE})
obj-m := crash4.o

endif

Now when I do a make then get the following error

make -C /lib/modules/2.6.28-11-generic/build M=/home/electricity/LKP/pandora/temp/crashcourse/crash4 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.28-11-generic'
Building with KERNELRELEASE =2.6.28-11-generic
CC [M] /home/electricity/LKP/pandora/temp/crashcourse/crash4/crash4.o
/home/electricity/LKP/pandora/temp/crashcourse/crash4/crash4.c:9: error: expected ‘)’ before string constant
make[2]: *** [/home/electricity/LKP/pandora/temp/crashcourse/crash4/crash4.o] Error 1
make[1]: *** [_module_/home/electricity/LKP/pandora/temp/crashcourse/crash4] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.28-11-generic'
make: *** [build] Error 2

any guesses as what could have caused it .
I am using Ubuntu 9.04 32 bit.~
~
~

You've lost the header files that you're trying to include.

It seems that you've lost the names of the header files you're trying to include at the top of your source file.

Well when I tried to post the

Well when I tried to post the comment here I could not post the name of header files you say I missed.
I am trying again to post with code tag.

/* Module source file 'crash4.c'. */

#include // for all modules
#include // for entry/exit macros
#include // for printk() definition

static int answer = 42;
module_param(answer, int, 0644);
MODULE_PARAM_DESC(answer, "Life ,the universe etc");

static int __init crash4_hi(void)
{
printk(KERN_INFO "crash4 module being loaded.\n");
return 0;
}

static void __exit crash4_bye(void)
{
printk(KERN_INFO "crash4 module being unloaded.\n");
}

module_init(crash4_hi);
module_exit(crash4_bye);

MODULE_AUTHOR("Robert P. J. Day, http://crashcourse.ca");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Testing module parameters.");

ok here is the problem I am

ok here is the problem I am unable to post the name of header files or say header files are getting delete from my reply
here are the names of header files
linux/module.h
linux/init.h
linux/kernel.h
these are the files I included.

Solved:

Hi,
Got the error solved.
I was using MODULE_PARAM_DESC which should be MODULE_PARM_DESC

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <br> <pre> <h1> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.