You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核下不同设备同名sysfs节点修改值互相影响如何修复?

问题根因与解决方案

根因分析

你遇到的同步修改问题核心原因是:两个设备的sysfs属性回调共用了全局静态缓冲区mybuf。
两个设备的mydevice_show/mydevice_store回调读写的都是同一块全局内存,所以不管操作哪一个设备的sysfs节点,修改的都是同一个值,自然会同步变化,和设备节点名称、所属class没有关系。

修复步骤

核心思路是给每个设备绑定独立的私有数据,回调中读写当前设备专属的存储区域:

  • 自定义设备私有数据结构体,把每个设备独有的缓冲区、属性变量都放在结构体中
  • 创建设备实例后,通过dev_set_drvdata()接口将私有数据指针和当前struct device绑定
  • 在sysfs的show/store回调中,通过入参struct device *dev调用dev_get_drvdata(),拿到当前设备对应的私有数据指针,再读写专属缓冲区

修正后的示例代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/slab.h>

/* 自定义设备私有数据结构体,每个设备独有一份 */
struct my_dev_priv {
    char mybuf[100];
};

static int major, major1;
static struct class *myclass;
static struct device *mydevice, *mydevice1;
/* 私有数据指针,每个设备对应一个 */
static struct my_dev_priv *priv0, *priv1;

static ssize_t mydevice_show(struct device *dev, struct device_attribute *attr,
        char *buf)
{
    /* 拿到当前设备对应的私有数据 */
    struct my_dev_priv *priv = dev_get_drvdata(dev);
    return sprintf(buf, "%s\n", priv->mybuf);
}
static ssize_t mydevice_store(struct device *dev, struct device_attribute *attr,
         const char *buf, size_t count)
{
    struct my_dev_priv *priv = dev_get_drvdata(dev);
    /* 只修改当前设备的私有缓冲区 */
    snprintf(priv->mybuf, sizeof(priv->mybuf), "%s", buf);
    return count;
}
static DEVICE_ATTR(mydevice, 0644, mydevice_show, mydevice_store);

static struct file_operations myfops = {
    .owner = THIS_MODULE,
};

static int __init mydevice_init(void)
{
    int ret;

    major = register_chrdev(0, "mydevice", &myfops);
    if (major < 0) {
        ret = major;
        return ret;
    }
    major1 = register_chrdev(0, "mydevice1", &myfops);
    if (major1 < 0) {
        ret = major1;
        goto unreg_major0;
    }

    myclass = class_create(THIS_MODULE, "myclass");
    if (IS_ERR(myclass)) {
        ret = PTR_ERR(myclass);
        goto unreg_major1;
    }

    /* 分配第一个设备的私有数据并初始化 */
    priv0 = kzalloc(sizeof(*priv0), GFP_KERNEL);
    if (!priv0) {
        ret = -ENOMEM;
        goto destroy_class;
    }
    strscpy(priv0->mybuf, "2", sizeof(priv0->mybuf));

    mydevice = device_create(myclass, NULL, MKDEV(major, 0), NULL, "mydevice");
    if (IS_ERR(mydevice)) {
        ret = PTR_ERR(mydevice);
        goto free_priv0;
    }
    /* 绑定私有数据到第一个设备 */
    dev_set_drvdata(mydevice, priv0);

    /* 分配第二个设备的私有数据并初始化 */
    priv1 = kzalloc(sizeof(*priv1), GFP_KERNEL);
    if (!priv1) {
        ret = -ENOMEM;
        goto destroy_dev0;
    }
    strscpy(priv1->mybuf, "2", sizeof(priv1->mybuf));

    mydevice1 = device_create(myclass, NULL, MKDEV(major1, 0), NULL, "mydevice1");
    if (IS_ERR(mydevice1)) {
        ret = PTR_ERR(mydevice1);
        goto free_priv1;
    }
    /* 绑定私有数据到第二个设备 */
    dev_set_drvdata(mydevice1, priv1);

    ret = sysfs_create_file(&mydevice->kobj, &dev_attr_mydevice.attr);
    if (ret)
        goto destroy_dev1;
    ret = sysfs_create_file(&mydevice1->kobj, &dev_attr_mydevice.attr);
    if (ret)
        goto remove_file0;

    return 0;

remove_file0:
    sysfs_remove_file(&mydevice->kobj, &dev_attr_mydevice.attr);
destroy_dev1:
    device_destroy(myclass, MKDEV(major1, 0));
free_priv1:
    kfree(priv1);
destroy_dev0:
    device_destroy(myclass, MKDEV(major, 0));
free_priv0:
    kfree(priv0);
destroy_class:
    class_destroy(myclass);
unreg_major1:
    unregister_chrdev(major1, "mydevice1");
unreg_major0:
    unregister_chrdev(major, "mydevice");
    return ret;
}

static void __exit mydevice_exit(void)
{
    sysfs_remove_file(&mydevice->kobj, &dev_attr_mydevice.attr);
    sysfs_remove_file(&mydevice1->kobj, &dev_attr_mydevice.attr);
    device_destroy(myclass, MKDEV(major, 0));
    device_destroy(myclass, MKDEV(major1, 0));
    kfree(priv0);
    kfree(priv1);
    class_destroy(myclass);
    unregister_chrdev(major, "mydevice");
    unregister_chrdev(major1, "mydevice1");
}

module_init(mydevice_init);
module_exit(mydevice_exit);

MODULE_DESCRIPTION("Fixed driver for per-device sysfs attribute");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("HLY");

额外优化建议

如果两个设备属于同类型,不需要两次调用register_chrdev注册两个主设备号,只需要注册一个主设备号,用不同次设备号区分不同设备即可,可减少不必要的资源占用。


内容的提问来源于stack exchange,提问作者Michael Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:57:02