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注册流程,避免命名冲突
- 修改设备名称:将
dev_test的init_name改为唯一名称,比如mytest_device,避免与系统现有设备重名。 - 完善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; } - 添加资源回滚逻辑:初始化每一步失败时,反向释放已注册的资源,避免残留节点:
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; } - 更新退出函数:使用
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
相关产品推荐
相关产品推荐

