Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kernel module's parameters in sysfs - quick reaction for changes

Is it possible to notify the module when one of it's sys files was changed? My task is to do a file which controls size of buffer inside the module, I want to resize the buffer when the value in the file is changed. My other idea (if I can't notify the module) was to check the previous value each time the module is used and then resize the buffer.

like image 345
Wojciech Reszelewski Avatar asked Jan 17 '23 09:01

Wojciech Reszelewski


1 Answers

Isn't this the purpose of Sysfs?

When you create a kobject and give it a representation in Sysfs (which is a directory), you then create attributes for that object which will become files in that directory. You provide a store and a show callback to the kobject, which are basically equivalents of resp. write and read.

store is what you want here. It looks like this:

ssize_t (*store)(struct kobject *kobj, struct attribute *attr, 
    const char *buffer, size_t size);

You receive size bytes within buffer as soon as the virtual file is written in user land.

Have a look at this module which does it (taken from here):

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>

struct my_attr {
    struct attribute attr;
    int value;
};

static struct my_attr my_first = {
    .attr.name="first",
    .attr.mode = 0644,
    .value = 1,
};

static struct my_attr my_second = {
    .attr.name="second",
    .attr.mode = 0644,
    .value = 2,
};

static struct attribute * myattr[] = {
    &my_first.attr,
    &my_second.attr,
    NULL
};

static ssize_t default_show(struct kobject *kobj, struct attribute *attr,
        char *buf)
{
    struct my_attr *a = container_of(attr, struct my_attr, attr);
    return scnprintf(buf, PAGE_SIZE, "%d\n", a->value);
}

static ssize_t default_store(struct kobject *kobj, struct attribute *attr,
        const char *buf, size_t len)
{
    struct my_attr *a = container_of(attr, struct my_attr, attr);
    sscanf(buf, "%d", &a->value);
    return sizeof(int);
}

static struct sysfs_ops myops = {
    .show = default_show,
    .store = default_store,
};

static struct kobj_type mytype = {
    .sysfs_ops = &myops,
    .default_attrs = myattr,
};

struct kobject *mykobj;
static int __init sysfsexample_module_init(void)
{
    int err = -1;
    mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL);
    if (mykobj) {
        kobject_init(mykobj, &mytype);
        if (kobject_add(mykobj, NULL, "%s", "sysfs_sample")) {
             err = -1;
             printk("Sysfs creation failed\n");
             kobject_put(mykobj);
             mykobj = NULL;
        }
        err = 0;
    }
    return err;
}

static void __exit sysfsexample_module_exit(void)
{
    if (mykobj) {
        kobject_put(mykobj);
        kfree(mykobj);
    }
}

module_init(sysfsexample_module_init);
module_exit(sysfsexample_module_exit);
MODULE_LICENSE("GPL");

Also: you might want to output the buffer size to the user when the entry is read. This is usually the way of doing it. Also make sure the information (read and written) is in a human-readable format to keep up with the Unix philosophy.

Update: see this recent interesting article about Sysfs file creation written by Greg Kroah-Hartman, one of the top kernel developers.

like image 188
eepp Avatar answered Jan 24 '23 22:01

eepp