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

Linux 6.0注册设备时初始化device class报错的解决方案咨询

问题描述

在Linux 6.0环境下注册了自定义bus、driver和device,想要为设备关联自定义class,于是在注册device前初始化了其class属性,但加载模块时出现错误:"don't try to register things with the same name in the same directory"。若不初始化class,驱动可正常工作,但需要创建自定义class来关联设备。

尝试过使用class_create和device_create,虽能成功创建class,但device_create无法初始化设备的bus属性,导致设备无法与驱动匹配,寻求解决建议。

报错信息
# insmod driver_test.ko
[   48.663393] driver_test: loading out-of-tree module taints kernel.
[   48.669891] driver_test: module verification failed: signature and/or required key missing - tainting kernel
[   48.680389] init module!
[   48.683167] Driver 'driver_test' needs updating - please use bus_type methods
[   48.690549] sysfs: cannot create duplicate filename '/devices/virtual/rapidio_port/driver_test/subsystem'
[   48.700176] CPU: 3 PID: 326 Comm: insmod Tainted: G           OE      6.0.11 #3
[   48.707511] Hardware name: OrangePi Zero2 (DT)
[   48.711961] Call trace:
[   48.714412]  dump_backtrace+0xd8/0x120
[   48.718192]  show_stack+0x18/0x50
[   48.721524]  dump_stack_lvl+0x68/0x84
[   48.725201]  dump_stack+0x18/0x34
[   48.728526]  sysfs_warn_dup+0x60/0x80
[   48.732207]  sysfs_do_create_link_sd+0x138/0x140
[   48.736839]  sysfs_create_link+0x30/0x50
[   48.740777]  bus_add_device+0xf0/0x140
[   48.744542]  device_add+0x33c/0x8b0
[   48.748043]  device_register+0x20/0x30
[   48.751804]  init_driver_test+0x98/0x1000 [mdev_hotplug]
[   48.757143]  do_one_initcall+0x50/0x1c0
[   48.760990]  do_init_module+0x44/0x1d0
[   48.764757]  load_module+0x194c/0x1d50
[   48.768521]  __do_sys_finit_module+0xac/0x130
[   48.772893]  __arm64_sys_finit_module+0x20/0x30
[   48.777439]  invoke_syscall+0x48/0x120
[   48.781203]  el0_svc_common.constprop.0+0x44/0x100
[   48.786008]  do_el0_svc+0x30/0xd0
[   48.789336]  el0_svc+0x2c/0x90
[   48.792408]  el0t_64_sync_handler+0xbc/0x140
[   48.796695]  el0t_64_sync+0x18c/0x190
[   48.800461] driver_test hotplug
[   48.803709] device register error!
[   48.838788] init module!
[   48.841389] sysfs: cannot create duplicate filename '/bus/bus-test'
[   48.847754] CPU: 3 PID: 326 Comm: insmod Tainted: G           OE      6.0.11 #3
[   48.855077] Hardware name: OrangePi Zero2 (DT)
[   48.859524] Call trace:
[   48.861974]  dump_backtrace+0xd8/0x120
[   48.865753]  show_stack+0x18/0x50
[   48.869083]  dump_stack_lvl+0x68/0x84
[   48.872760]  dump_stack+0x18/0x34
[   48.876085]  sysfs_warn_dup+0x60/0x80
[   48.879765]  sysfs_create_dir_ns+0xec/0x110
[   48.883963]  kobject_add_internal+0xbc/0x3a0
[   48.888251]  kset_register+0x58/0x90
[   48.891840]  bus_register+0xc4/0x320
[   48.895432]  init_driver_test+0x2c/0x1000 [mdev_hotplug]
[   48.900769]  do_one_initcall+0x50/0x1c0
[   48.904616]  do_init_module+0x44/0x1d0
[   48.908382]  load_module+0x194c/0x1d50
[   48.912147]  __do_sys_init_module+0x20c/0x250
[   48.916519]  __arm64_sys_init_module+0x1c/0x30
[   48.920977]  invoke_syscall+0x48/0x120
[   48.924742]  el0_svc_common.constprop.0+0x44/0x100
[   48.929546]  do_el0_svc+0x30/0xd0
[   48.932874]  el0_svc+0x2c/0x90
[   48.935946]  el0t_64_sync_handler+0xbc/0x140
[   48.940232]  el0t_64_sync+0x18c/0x190
[   48.943965] kobject_add_internal failed for bus-test with -EEXIST, don't try to register things with the same name in the same directory.
[   48.956343] bus register error!
#
现有驱动代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>           
#include <linux/device.h>
#include <linux/device/driver.h>
#include <linux/kobject.h>  
#include <linux/sysfs.h>   

static struct class test_class = {
    .name = "mytest_class",
    .owner = THIS_MODULE,
};


static int bus_match(struct device *dev, struct device_driver *drv)
{
    printk(KERN_INFO"In %s \n", __func__);
    //match by driver name and device name
    return (strcmp(dev_name(dev), drv->name) == 0);
}

static int bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
    int ret=1;
    printk(KERN_INFO "%s hotplug\n", dev_name(dev));
    ret = add_uevent_var(env, "THIS_TEST=%s", dev_name(dev));
    if(ret)
    {
        return ret;
    }
    return add_uevent_var(env, "EVENT=%s", "change");
}

static int bus_probe(struct device *dev)
{
    return dev->driver->probe(dev);
    return 0;
}

static void bus_remove(struct device *dev)
{
    dev->driver->remove(dev);
}

struct bus_type bus_test =
{
    .name  = "bus-test",
    .match = bus_match,
    .uevent= bus_uevent,
    .probe = bus_probe,
    .remove= bus_remove,
};
EXPORT_SYMBOL(bus_test);

static int driver_probe(struct device *dev)
{
    printk(KERN_INFO "driver probe!\n");
    return 0;
}

static int driver_remove(struct device *dev)
{
    printk(KERN_INFO "driver remove!\n");
    return 0;
}

static struct device_driver driver_test=
{
    .name = "driver_test",
    .bus  = &bus_test,
    .probe = driver_probe,
    .remove = driver_remove,
};

static void dev_test_release(struct device *dev)
{
    printk(KERN_INFO "device release!\n");
}

static struct device dev_test = {
    .init_name  = "driver_test",
    .bus        = &bus_test,
    .release    = dev_test_release,
};

static int __init init_driver_test(void)
{
    int ret = 0;
    printk(KERN_INFO "init module!\n");
    ret = bus_register(&bus_test);
    if (ret) {
        printk(KERN_ERR "bus register error!\n");
        return ret;
    }
    ret = class_register(&test_class);
    if (ret) {
        printk(KERN_ERR "class register error!\n");
        return ret;
    }
    dev_test.class      = &test_class,
    dev_test.devt=MKDEV(100, 1);
    ret = device_register(&dev_test);
    if(ret)
    {
        printk(KERN_ERR "device register error!\n");
        return ret;       
    }
    ret = driver_register(&driver_test);
    if (ret) {
        printk(KERN_ERR "driver register error!\n");
        return ret;
    }
    return ret;
}

static void __exit exit_driver_test(void)
{
    driver_unregister(&driver_test);
    device_unregister(&dev_test);
    class_unregister(&test_class);
    bus_unregister(&bus_test);
    printk(KERN_INFO "exit module!\n");
}
module_init(init_driver_test);
module_exit(exit_driver_test);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("NoError");
MODULE_DESCRIPTION("driver test");
解决方案建议

核心问题分析

  • 设备名称driver_test与系统中已有节点(如/devices/virtual/rapidio_port/driver_test)重名,导致sysfs创建节点冲突。
  • 模块初始化失败后未正确回滚已注册资源,残留的bus节点导致后续加载时提示重复注册。
  • 手动初始化struct class缺少内核内部必要字段的初始化,容易引发sysfs层级问题。

具体修复方案

方案1:修正手动class注册流程,避免命名冲突

  1. 修改设备名称:将dev_test的init_name改为唯一名称,比如mytest_device,避免与系统现有设备重名。
  2. 完善class初始化:推荐使用class_create替代手动初始化struct class,该函数会自动完成内核内部字段的初始化:
    static struct class *test_class;
    
    test_class = class_create(THIS_MODULE, "mytest_class");
    if (IS_ERR(test_class)) {
        ret = PTR_ERR(test_class);
        printk(KERN_ERR "class create error!\n");
        goto err_class;
    }
    
  3. 添加资源回滚逻辑:初始化每一步失败时,反向释放已注册的资源,避免残留节点:
    static int __init init_driver_test(void)
    {
        int ret = 0;
        printk(KERN_INFO "init module!\n");
    
        ret = bus_register(&bus_test);
        if (ret) {
            printk(KERN_ERR "bus register error!\n");
            goto err_bus;
        }
    
        test_class = class_create(THIS_MODULE, "mytest_class");
        if (IS_ERR(test_class)) {
            ret = PTR_ERR(test_class);
            printk(KERN_ERR "class create error!\n");
            goto err_class;
        }
    
        dev_test.init_name = "mytest_device";
        dev_test.bus = &bus_test;
        dev_test.class = test_class;
        dev_test.devt = MKDEV(100, 1);
        ret = device_register(&dev_test);
        if(ret)
        {
            printk(KERN_ERR "device register error!\n");
            goto err_device;
        }
    
        ret = driver_register(&driver_test);
        if (ret) {
            printk(KERN_ERR "driver register error!\n");
            goto err_driver;
        }
    
        return ret;
    
    err_driver:
        device_unregister(&dev_test);
    err_device:
        class_destroy(test_class);
    err_class:
        bus_unregister(&bus_test);
    err_bus:
        return ret;
    }
    
  4. 更新退出函数:使用class_destroy替代class_unregister:
    static void __exit exit_driver_test(void)
    {
        driver_unregister(&driver_test);
        device_unregister(&dev_test);
        class_destroy(test_class);
        bus_unregister(&bus_test);
        printk(KERN_INFO "exit module!\n");
    }
    

方案2:适配class_create+手动绑定bus属性

如果坚持使用class_create,不要用device_create,而是手动初始化设备结构体并绑定bus属性,确保设备能被自定义总线匹配:

  • 保持class_create创建class的逻辑,手动给dev_test设置bus = &bus_test,再调用device_register,即可让设备挂载到自定义总线,同时关联class。

额外注意事项

  • 匹配逻辑同步:如果修改了设备名称,需要同步修改驱动名称driver_test.name,或者调整bus_match函数的匹配规则,确保设备和驱动能正确匹配。
  • 内核提示处理:内核提示Driver 'driver_test' needs updating - please use bus_type methods,可检查总线的probe/remove实现,确保符合Linux 6.0的内核规范(当前实现可正常工作,若需优化可参考内核总线驱动的最新示例)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 06:45:07