http://ldn.linuxfoundation.org/article/the-kernel-newbie-corner-everything-you-wanted-know-about-module-parametersThe Kernel Newbie Corner: Everything You Wanted to Know About Module ParametersThis week, we're going to discuss the ins and outs of adding parameters to your loadable modules and, as we did last week, we're going to work off the appropriate section in the book Linux Device Drivers (3rd ed.) (LDD3), that you can find online here. And again, as we did last week, we'll be dealing with some of the content from Chapter 2. (The archive of all previous "Kernel Newbie Corner" articles can be found here.)
So How Do We Start?Let's start with a module source file p1.c that has nothing to do with parameters: #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> static int answer = 42 ; static int __init hi(void) { printk(KERN_INFO "p1 module being loaded.\n"); printk(KERN_INFO "Initial answer = %d.\n", answer); return 0; } static void __exit bye(void) { printk(KERN_INFO "p1 module being unloaded.\n"); printk(KERN_INFO "Final answer = %d.\n", answer); } module_init(hi); module_exit(bye); MODULE_AUTHOR("Robert P. J. Day"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("No parameters here."); Only one thing is slightly different about this new version of our classic module--the definition of the static int variable answer, which is initialized to 42. And since that's the initial value that's compiled directly into the module, it comes as no surprise that, when we compile, load and unload this module, we expect to see the following in /var/log/messages: ... localhost kernel: p1 module being loaded. ... localhost kernel: Initial answer = 42. ... time passes, until we unload ... ... localhost kernel: p1 module being unloaded. ... localhost kernel: Final answer = 42. Obviously, since we started with answer having the value 42, and didn't change it anywhere, we're not at all surprised to see that the value is still 42 upon module exit. And now, we drag parameters into it. So What Do We Do With "Parameters?"As the name suggests, module parameters give us the ability to pass a value of some kind to a module upon loading, and also to examine its value while the module is loaded and running, and even change it on the fly if we want. Here's the simple change we would make to the code above (let's call the new source file p2.c): ... #include <linux/module.h> #include <linux/moduleparam.h> // add this ... static int answer = 42 ; module_param(answer, int, 0644); MODULE_PARM_DESC(answer, "Life, the universe, etc."); ... Now recompile your module and, without even loading it, let's discuss what just happened above:
So What Do I Do With That Parameter?This: # insmod p2.ko answer=6 # rmmod p2 whereupon you expect to see in /var/log/messages: ... kernel: p2 module being loaded. ... kernel: Initial answer = 6. ... time passes ... ... kernel: p2 module being unloaded. ... kernel: Final answer = 6. If you hadn't set the parameter value during the module load, the value would have been 42 throughout the life of the module as it was before. But since you set the parameter value to six at load time, that value was used instead to initialize the variable. This is the sort of thing that is used by some modules to be told, for instance, their I/O address or interrupt line upon loading, and you should appreciate just how handy that can be. But wait ... there's so much more. Poking Around Under /sysWe've never mentioned it before but, on most sane Linux systems, the instant you load a module, an entire subdirectory structure is created for it under /sys/module/modulename. Assuming you've reloaded your p2 module with an answer parameter value of 6, here's what you should expect to find: $ ls -1F /sys/module/p2 holders/ initstate notes/ parameters/ refcnt sections/ srcversion You can poke around the other entries related to your p2 module but we're most interested in: $ ls -l /sys/module/p2/parameters/ total 0 -rw-r--r--. 1 root root 4096 2009-07-11 09:00 answer and there it is--a user-readable way to examine the current value of a module parameter in real time while the module is loaded and running. Just list it: $ cat /sys/module/p2/parameters/answer 6 Not surprisingly, if your module changes that variable while it's running, the value you see will correspond to whatever is stored there at the time of examination. But, yes, there's more. What's With That Parameter Permission Setting?Easy--as with regular files, those permission settings dictate who is allowed to do what with that parameter file under /sys/module. In our case, since it has a file mode of 644, the owner (root) can both read and write, and everyone else can read. It's easy to see what it means to have read access, but what does it mean to have write access? It means that, on the fly, you can do this to change the value of that internal variable at any time while the module is loaded: # echo 21 > /sys/module/p2/parameters/answer # cat /sys/module/p2/parameters/answer 21 # and when you finally unload the module, you shouldn't be surprised to note that that variable now has the value 21 (unless, of course, you changed it yet again). So what else do you need to know about parameter permissions? There are a few things. First, when you define parameter permissions in your code, you can use numeric values as we did above (such as 0644) or, if you include the header file <linux/stat.h>, you can use the fairly intuitive macros: #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 or any bitwise OR'ed combination to get the same effect. It's entirely up to you. Next, if you create a parameter with a permission setting of zero, that means that that parameter will not show up under /sys at all, so no one will have any read or write access to it whatsoever (not even root). The only use that parameter will have is that you can set it at module load time, and that's it. Finally (and this one's kind of important), if you choose to define writable parameters and really do write to them while your module is loaded, your module is not informed that the value has changed. That is, there is no callback or notification mechanism for modified parameters; the value will quietly change in your module while your code keeps running, oblivious to the fact that there's a new value in that variable. If you truly need write access to your module and some sort of notification mechanism, you probably don't want to use parameters. There are better ways to get that functionality. Anything Else?Of course. Where do we even begin? First, module parameters can have a number of different types such as int, uint, short, ushort, long, bool and a few others, all defined in the header file <linux/moduleparam.h>. You can even define array-type parameters. All of this is covered in the aforementioned section of LDD3, and testing any of those is left as an exercise for the reader. Next, now that you know that loading your module creates an entire directory substructure under /sys/module/modulename that lists that module's properties and attributes, it should come as no surprise that you can view that same directory structure for any loaded module thusly: $ modinfo fuse which will pick up most of its output from that very directory. The next neat feature is that it's possible to define the filename that shows up under /sys as being different from the name of the actual static variable thusly: static int answer = 42 ; module_param_named(readable_answer, answer, int, 0444); MODULE_PARM_DESC(readable_answer, "The readable answer"); In the above snippet, the internal variable has the conveniently brief name of answer, while the visible filename under /sys that corresponds to it will have the (perhaps) more self-descriptive name of readable_answer. In fact, nothing stops you from defining more than one renaming of the same internal variable with different permission settings, for whatever reason you can imagine. And, finally, if the pre-defined parameter data types aren't adequate, you can in fact create parameters with entirely user-defined data types as described here, although this doesn't appear to be a very commonly-used feature so I wouldn't worry too much about that. Exercises for the ReaderAnd here's where we start a brand new feature of this column--puzzles for the reader to solve.
Robert
P. J. Day is a Linux consultant and long-time corporate trainer who
lives in Waterloo, Ontario. He provides assistance to the Linux Foundation's Training
Program. Robert can be reached at rpj...@crashcourse.ca, and can
be followed at http://twitter.com/rpjday. |