Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

driver core: generalize driver_override in struct device

Currently, there are 12 busses (including platform and PCI) that
duplicate the driver_override logic for their individual devices.

All of them seem to be prone to the bug described in [1].

While this could be solved for every bus individually using a separate
lock, solving this in the driver-core generically results in less (and
cleaner) changes overall.

Thus, move driver_override to struct device, provide corresponding
accessors for busses and handle locking with a separate lock internally.

In particular, add device_set_driver_override(),
device_has_driver_override(), device_match_driver_override() and
generalize the sysfs store() and show() callbacks via a driver_override
feature flag in struct bus_type.

Until all busses have migrated, keep driver_set_override() in place.

Note that we can't use the device lock for the reasons described in [2].

Link: https://bugzilla.kernel.org/show_bug.cgi?id=220789 [1]
Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [2]
Tested-by: Gui-Dong Han <hanguidong02@gmail.com>
Co-developed-by: Gui-Dong Han <hanguidong02@gmail.com>
Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patch.msgid.link/20260303115720.48783-2-dakr@kernel.org
[ Use dev->bus instead of sp->bus for consistency; fix commit message to
refer to the struct bus_type's driver_override feature flag. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+162 -1
+42 -1
drivers/base/bus.c
··· 504 504 } 505 505 EXPORT_SYMBOL_GPL(bus_for_each_drv); 506 506 507 + static ssize_t driver_override_store(struct device *dev, 508 + struct device_attribute *attr, 509 + const char *buf, size_t count) 510 + { 511 + int ret; 512 + 513 + ret = __device_set_driver_override(dev, buf, count); 514 + if (ret) 515 + return ret; 516 + 517 + return count; 518 + } 519 + 520 + static ssize_t driver_override_show(struct device *dev, 521 + struct device_attribute *attr, char *buf) 522 + { 523 + guard(spinlock)(&dev->driver_override.lock); 524 + return sysfs_emit(buf, "%s\n", dev->driver_override.name); 525 + } 526 + static DEVICE_ATTR_RW(driver_override); 527 + 528 + static struct attribute *driver_override_dev_attrs[] = { 529 + &dev_attr_driver_override.attr, 530 + NULL, 531 + }; 532 + 533 + static const struct attribute_group driver_override_dev_group = { 534 + .attrs = driver_override_dev_attrs, 535 + }; 536 + 507 537 /** 508 538 * bus_add_device - add device to bus 509 539 * @dev: device being added ··· 567 537 if (error) 568 538 goto out_put; 569 539 540 + if (dev->bus->driver_override) { 541 + error = device_add_group(dev, &driver_override_dev_group); 542 + if (error) 543 + goto out_groups; 544 + } 545 + 570 546 error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev)); 571 547 if (error) 572 - goto out_groups; 548 + goto out_override; 573 549 574 550 error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem"); 575 551 if (error) ··· 586 550 587 551 out_subsys: 588 552 sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev)); 553 + out_override: 554 + if (dev->bus->driver_override) 555 + device_remove_group(dev, &driver_override_dev_group); 589 556 out_groups: 590 557 device_remove_groups(dev, sp->bus->dev_groups); 591 558 out_put: ··· 646 607 647 608 sysfs_remove_link(&dev->kobj, "subsystem"); 648 609 sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev)); 610 + if (dev->bus->driver_override) 611 + device_remove_group(dev, &driver_override_dev_group); 649 612 device_remove_groups(dev, dev->bus->dev_groups); 650 613 if (klist_node_attached(&dev->p->knode_bus)) 651 614 klist_del(&dev->p->knode_bus);
+2
drivers/base/core.c
··· 2556 2556 devres_release_all(dev); 2557 2557 2558 2558 kfree(dev->dma_range_map); 2559 + kfree(dev->driver_override.name); 2559 2560 2560 2561 if (dev->release) 2561 2562 dev->release(dev); ··· 3160 3159 kobject_init(&dev->kobj, &device_ktype); 3161 3160 INIT_LIST_HEAD(&dev->dma_pools); 3162 3161 mutex_init(&dev->mutex); 3162 + spin_lock_init(&dev->driver_override.lock); 3163 3163 lockdep_set_novalidate_class(&dev->mutex); 3164 3164 spin_lock_init(&dev->devres_lock); 3165 3165 INIT_LIST_HEAD(&dev->devres_head);
+60
drivers/base/dd.c
··· 381 381 } 382 382 __exitcall(deferred_probe_exit); 383 383 384 + int __device_set_driver_override(struct device *dev, const char *s, size_t len) 385 + { 386 + const char *new, *old; 387 + char *cp; 388 + 389 + if (!s) 390 + return -EINVAL; 391 + 392 + /* 393 + * The stored value will be used in sysfs show callback (sysfs_emit()), 394 + * which has a length limit of PAGE_SIZE and adds a trailing newline. 395 + * Thus we can store one character less to avoid truncation during sysfs 396 + * show. 397 + */ 398 + if (len >= (PAGE_SIZE - 1)) 399 + return -EINVAL; 400 + 401 + /* 402 + * Compute the real length of the string in case userspace sends us a 403 + * bunch of \0 characters like python likes to do. 404 + */ 405 + len = strlen(s); 406 + 407 + if (!len) { 408 + /* Empty string passed - clear override */ 409 + spin_lock(&dev->driver_override.lock); 410 + old = dev->driver_override.name; 411 + dev->driver_override.name = NULL; 412 + spin_unlock(&dev->driver_override.lock); 413 + kfree(old); 414 + 415 + return 0; 416 + } 417 + 418 + cp = strnchr(s, len, '\n'); 419 + if (cp) 420 + len = cp - s; 421 + 422 + new = kstrndup(s, len, GFP_KERNEL); 423 + if (!new) 424 + return -ENOMEM; 425 + 426 + spin_lock(&dev->driver_override.lock); 427 + old = dev->driver_override.name; 428 + if (cp != s) { 429 + dev->driver_override.name = new; 430 + spin_unlock(&dev->driver_override.lock); 431 + } else { 432 + /* "\n" passed - clear override */ 433 + dev->driver_override.name = NULL; 434 + spin_unlock(&dev->driver_override.lock); 435 + 436 + kfree(new); 437 + } 438 + kfree(old); 439 + 440 + return 0; 441 + } 442 + EXPORT_SYMBOL_GPL(__device_set_driver_override); 443 + 384 444 /** 385 445 * device_is_bound() - Check if device is bound to a driver 386 446 * @dev: device to check
+54
include/linux/device.h
··· 483 483 * on. This shrinks the "Board Support Packages" (BSPs) and 484 484 * minimizes board-specific #ifdefs in drivers. 485 485 * @driver_data: Private pointer for driver specific info. 486 + * @driver_override: Driver name to force a match. Do not touch directly; use 487 + * device_set_driver_override() instead. 486 488 * @links: Links to suppliers and consumers of this device. 487 489 * @power: For device power management. 488 490 * See Documentation/driver-api/pm/devices.rst for details. ··· 578 576 core doesn't touch it */ 579 577 void *driver_data; /* Driver data, set and get with 580 578 dev_set_drvdata/dev_get_drvdata */ 579 + struct { 580 + const char *name; 581 + spinlock_t lock; 582 + } driver_override; 581 583 struct mutex mutex; /* mutex to synchronize calls to 582 584 * its driver. 583 585 */ ··· 706 700 }; 707 701 708 702 #define kobj_to_dev(__kobj) container_of_const(__kobj, struct device, kobj) 703 + 704 + int __device_set_driver_override(struct device *dev, const char *s, size_t len); 705 + 706 + /** 707 + * device_set_driver_override() - Helper to set or clear driver override. 708 + * @dev: Device to change 709 + * @s: NUL-terminated string, new driver name to force a match, pass empty 710 + * string to clear it ("" or "\n", where the latter is only for sysfs 711 + * interface). 712 + * 713 + * Helper to set or clear driver override of a device. 714 + * 715 + * Returns: 0 on success or a negative error code on failure. 716 + */ 717 + static inline int device_set_driver_override(struct device *dev, const char *s) 718 + { 719 + return __device_set_driver_override(dev, s, s ? strlen(s) : 0); 720 + } 721 + 722 + /** 723 + * device_has_driver_override() - Check if a driver override has been set. 724 + * @dev: device to check 725 + * 726 + * Returns true if a driver override has been set for this device. 727 + */ 728 + static inline bool device_has_driver_override(struct device *dev) 729 + { 730 + guard(spinlock)(&dev->driver_override.lock); 731 + return !!dev->driver_override.name; 732 + } 733 + 734 + /** 735 + * device_match_driver_override() - Match a driver against the device's driver_override. 736 + * @dev: device to check 737 + * @drv: driver to match against 738 + * 739 + * Returns > 0 if a driver override is set and matches the given driver, 0 if a 740 + * driver override is set but does not match, or < 0 if a driver override is not 741 + * set at all. 742 + */ 743 + static inline int device_match_driver_override(struct device *dev, 744 + const struct device_driver *drv) 745 + { 746 + guard(spinlock)(&dev->driver_override.lock); 747 + if (dev->driver_override.name) 748 + return !strcmp(dev->driver_override.name, drv->name); 749 + return -1; 750 + } 709 751 710 752 /** 711 753 * device_iommu_mapped - Returns true when the device DMA is translated
+4
include/linux/device/bus.h
··· 65 65 * this bus. 66 66 * @pm: Power management operations of this bus, callback the specific 67 67 * device driver's pm-ops. 68 + * @driver_override: Set to true if this bus supports the driver_override 69 + * mechanism, which allows userspace to force a specific 70 + * driver to bind to a device via a sysfs attribute. 68 71 * @need_parent_lock: When probing or removing a device on this bus, the 69 72 * device core should lock the device's parent. 70 73 * ··· 109 106 110 107 const struct dev_pm_ops *pm; 111 108 109 + bool driver_override; 112 110 bool need_parent_lock; 113 111 }; 114 112