Adding a Kernel Parameter to Proc Filesystem (procfs)

Details about where to modify the kernel source code to add a kernel parameter that can be accessed in procfs.

Kernel parameters that are accessible via procfs offer a good interface to expose the kernel internals.
Apart from allowing users to monitor the kernel, it is particularly useful for some features that are configurable at run-time (e.g., CPU frequency scaling).

[Step 1] Declare Your Variable

Let’s assume that you are working on something in the kernel file, say my.c, and there is a gobal variable that you want to expose to procfs.
To make such a variable more identifiable, you may want to name it with the prefix sysctl_. Let’s assume the variable is an integer named sysctl_my_param. So you will declare such a variable in my.c as usual (with a default value):

my.c
int sysctl_my_param = 0;

[Step 2] Optional: Implement the Handler Function

There is a default handler that handles the read/write operations coming from the procfs.
If you want to do something different (e.g., checking if certain conditions meet and thus updating the parameters is accepted), there is a way to create your own handler and associate it with your kernel parameter.

To create and implement a handler of your own, use the following template (and replace function name with yours):

my.c
int my_handler(struct ctl_table *table, int write,
               void __user *buffer, size_t *lenp,
               loff_t *ppos)
{
    int ret;

    ret = proc_dointvec(table, write, buffer, lenp, ppos);

    if (ret) {
        // update fails
    } else {
        // update succeeds
    }

    return ret;
}

[Step 3] Register in Kernel Table

Next we will have to expose and register our variable and function in the sysctl.

First, declare the variable and, optionally, the function in include/linux/sched/sysctl.h.

include/linux/sched/sysctl.h
extern int sysctl_my_param;
extern int my_handler(struct ctl_table *table, int write,
                      void __user *buffer, size_t *lenp,
                      loff_t *ppos);

Then, we need register the variable.
To do so, find the variable static struct ctl_table kern_table[] in include/linux/sched/sysctl.c and create a structure entry as follows:

include/linux/sched/sysctl.c
static struct ctl_table kern_table[] = {
    // ...
    {
        .procname   = "my_param",
        .data       = &sysctl_my_param,
        .maxlen     = sizeof(int),
        .mode       = 0644,
        .proc_handler   = my_handler,
    },
    // ...
}

You can give a different name to the field .procname that will be used to expose this parameter (i.e., our sysctl_my_param variable) in procfs.

If you choose to use the default handler, then you can replace the last field with this:

        .proc_handler   = proc_dointvec,

[Step 4] Access It from procfs!

At run-time, your can read the parameter by using the following command:

# option 1 (no sudo required)
sysctl kernel.my_param

# option 2
sudo cat /proc/sys/kernel/my_param

To assign a new value to the parameter, there are also two ways:

# option 1
sudo sysctl kernel.my_param=1

# option 2
sudo su
echo 1 > /proc/sys/kernel/my_param

Was this post helpful?

Leave a Reply

Your email address will not be published.