如何在Linux内核v3.2中创建一个简单的sysfs类属性

Vil*_*ray 18 c linux linux-device-driver linux-kernel sysfs

我正在学习如何在我的Linux模块中使用sysfs,但我最难找到有关这些主题的当前文档.我一直在使用的Linux设备驱动程序第3版书似乎在这个领域相当过时(例如,class_device在当前的Linux版本中,结构似乎完全消失了).

我只是试图在我的模块的相应sysfs类下获得一个属性,这将允许我从内核空间读取模块变量的值.

在我的代码中,我创建了一个类,允许udev在/ dev/foo为我的模块创建一个设备节点:

dev_t foo_dev;
alloc_chrdev_region(&foo_dev, 0, 1, "bar");

struct class *bar = class_create(THIS_MODULE, "bar");

device_create(bar, NULL, foo_dev, NULL, "foo");

struct cdev foo_dev_file;
cdev_init(&foo_dev_file, &fops); /* fops defined earlier */
cdev_add(&foo_dev_file, foo_dev, 1);
Run Code Online (Sandbox Code Playgroud)

当我插入模块时,我得到了一个sysfs类目录,并在/ sys/class/bar/foo /中填充了一些默认属性.如何创建显示在此新目录下的属性?

我相信我的概念非常好 - 创建属性结构,定义sysfs_ops函数等 - 我的问题是我不知道使用哪个特定的内核结构(class_attribute?),也不知道如何使这些属性出现在右边sysfs目录.

有人会指点我的教程或文章详细介绍当前Linux内核的过程吗?

Dan*_*tos 15

尽管我的知识在这个主题上仍然相当低,但我将仅仅因为这个问题的年龄而发布答案.如果有其他人有更好的答案,请发布!:)

首先,我将假设您已经阅读了整章(特别是关于kobjects和ksets).因此,几乎设备驱动程序模型中的每个结构都包含在其中.如果你想操纵它自己的类的kobject(不确定这是否明智),那就是你struct classdev_kobj成员.

但是,您希望操纵该类的属性.我相信,通过定义它们的(通常是静态的),空值终止的数组,如下所示,然后到指定的地址,这样做struct classclass_attrs成员(摘自drivers/uwb/driver.c):

static struct class_attribute uwb_class_attrs[] = {
    __ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
           beacon_timeout_ms_show, beacon_timeout_ms_store),
    __ATTR_NULL,
};

/** Device model classes */
struct class uwb_rc_class = {
    .name        = "uwb_rc",
    .class_attrs = uwb_class_attrs,
};
Run Code Online (Sandbox Code Playgroud)

当我不知道如何使用某些东西时,我通常git grep是使用它的其他人的存储库,并尝试以这种方式学习它.看起来这就是为什么他们倾向于说内核"黑客"而不是"开发者".


Cir*_*四事件 6

最小的可运行示例

用法:

insmod /sysfs.ko
cd /sys/kernel/lkmc_sysfs
printf 12345 >foo
cat foo
# => 1234
dd if=foo bs=1 count=2 skip=1 status=none
# => 23
Run Code Online (Sandbox Code Playgroud)

sysfs.c

#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <uapi/linux/stat.h> /* S_IRUSR, S_IWUSR  */

enum { FOO_SIZE_MAX = 4 };
static int foo_size;
static char foo_tmp[FOO_SIZE_MAX];

static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
        char *buff)
{
    strncpy(buff, foo_tmp, foo_size);
    return foo_size;
}

static ssize_t foo_store(struct  kobject *kobj, struct kobj_attribute *attr,
        const char *buff, size_t count)
{
    foo_size = min(count, (size_t)FOO_SIZE_MAX);
    strncpy(foo_tmp, buff, foo_size);
    return count;
}

static struct kobj_attribute foo_attribute =
    __ATTR(foo, S_IRUGO | S_IWUSR, foo_show, foo_store);

static struct attribute *attrs[] = {
    &foo_attribute.attr,
    NULL,
};

static struct attribute_group attr_group = {
    .attrs = attrs,
};

static struct kobject *kobj;

static int myinit(void)
{
    int ret;

    kobj = kobject_create_and_add("lkmc_sysfs", kernel_kobj);
    if (!kobj)
        return -ENOMEM;
    ret = sysfs_create_group(kobj, &attr_group);
    if (ret)
        kobject_put(kobj);
    return ret;
}

static void myexit(void)
{
    kobject_put(kobj);
}

module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");
Run Code Online (Sandbox Code Playgroud)

GitHub上游

经过Linux内核5.0测试。