Tuesday, November 3, 2009

Using sysctl interface for Out-of-Kernel Modules

This post is for that exorbitantly frustrated Linux Kernel Dev,  who is about to start pulling out his/her hair, trying to figure out how to use sysctl interface in Out-of-Tree kernel modules, in 2.6.24+ Kernels. (Did I just described my own state? ;) ).

1. What is sysctl?
Consider following points:
  • sysclt is an interface for user-space <--> kernel communication.
  • It is used to read/write some Kernel variables, from User-Space.
  • Each files under /proc/sys directory represents a Kernel variable
  • Reading/Writing these files is equivalent to a read/write of the corresponding Kernel variable.
(I won't go further in describing sysctl interface here, you can look out for it in Understanding Linux Network Internals book)


2. What's the problem in using sysctl with 2.6.24+?

A patch was released after 2.6.24, which prohibits Out-of-Kernel modules from using sysctl interface in the normal way. This was apparently done as many broken entries were detected and thus only In-Kernel modules were allowed to use sysctl the conventional way.


3. The way out?


To use sysctl in an Out-of-Kernel module, all you have to do is to set the ctl_name field of ctl_table, of every child in subdir, to 0 (zero). Only the top level ctl_table shall have a ctl_name defined.


EDIT (30th March 2010) : In 2.6.33 onwards, ctl_name field is no longer a member of struct ctl_table. For out-of-tree kernel module, remove the ctl_name from all the concerned ctl_table structure, to get things working.


Example: 

If you want following set of files under /proc/sys/net:

/proc/sys/net
|
|----foo---|-----var1
              |-----var2



you need to have a config like: 




static struct ctl_table child_table[] = {
    {
    .ctl_name    =    0,
    .procname    =    "var1",
    .data        =    &x1,
    .maxlen        =    sizeof(int),
    .mode        =    0644,
    .child        =    NULL,
    .proc_handler    =    &proc_dointvec},


    {
        .ctl_name       =       0,
        .procname       =       "var2",
        .data           =       &x2,
        .maxlen         =       sizeof(int),
        .mode           =       0644,
        .child          =       NULL,
        .proc_handler   =       &proc_dointvec},

    {    .ctl_name    =    0,

          .procname    =    NULL
    }
};


static struct ctl_table foo_table[] = {
    {
        .ctl_name       =      0,
        .procname       =       "foo",
        .data           =       NULL,
        .maxlen         =       0,
        .mode           =       0555,
        .child          =       child_table},

    {
    .ctl_name    =    0,
    .procname    =    NULL
    }

};



static struct ctl_table root_table[] = {
    {
        .ctl_name       =       CTL_NET,
        .procname       =       "net",
        .data           =       NULL,
        .maxlen         =       0,
        .mode           =       0555,
        .child          =       foo_table},
   
    {
    .ctl_name    =    0,
    .procname    =    NULL
    }

};



Cheers!

No comments:

Post a Comment