Driver core fixes for 6.15-rc4

Here are some small driver core fixes to resolve a number of reported
 problems.  Included in here are:
   - driver core sync fix revert to resolve a much reported problem,
     hopefully this is finally resolved
   - MAINTAINERS file update, documenting that the driver-core tree is
     now under a "shared" maintainership model, thanks to Rafael and
     Danilo for offering to do this!
   - auxbus documentation and MAINTAINERS file update
   - MAINTAINERS file update for Rust PCI code
   - firmware rust binding fixup
   - software node link fix
 
 All of these have been in linux-next for over a week with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaAuR4g8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynU0wCg2YmcO0R7M4+g5SPHEFN0jy2xcaAAn1rMLbAY
 E4U8Wo13hNMRtzMeI814
 =YKYd
 -----END PGP SIGNATURE-----

Merge tag 'driver-core-6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core

Pull driver core fixes from Greg KH:
 "Here are some small driver core fixes to resolve a number of reported
  problems. Included in here are:

   - driver core sync fix revert to resolve a much reported problem,
     hopefully this is finally resolved

   - MAINTAINERS file update, documenting that the driver-core tree is
     now under a "shared" maintainership model, thanks to Rafael and
     Danilo for offering to do this!

   - auxbus documentation and MAINTAINERS file update

   - MAINTAINERS file update for Rust PCI code

   - firmware rust binding fixup

   - software node link fix

  All of these have been in linux-next for over a week with no reported
  issues"

* tag 'driver-core-6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core:
  drivers/base/memory: Avoid overhead from for_each_present_section_nr()
  software node: Prevent link creation failure from causing kobj reference count imbalance
  device property: Add a note to the fwnode.h
  drivers/base: Add myself as auxiliary bus reviewer
  drivers/base: Extend documentation with preferred way to use auxbus
  driver core: fix potential NULL pointer dereference in dev_uevent()
  driver core: introduce device_set_driver() helper
  Revert "drivers: core: synchronize really_probe() and dev_uevent()"
  MAINTAINERS: update the location of the driver-core git tree
  rust: firmware: Use `ffi::c_char` type in `FwFunc`
  MAINTAINERS: pci: add entry for Rust PCI code
This commit is contained in:
Linus Torvalds 2025-04-25 10:02:59 -07:00
commit 3ae7f5093e
10 changed files with 106 additions and 42 deletions

View File

@ -3873,8 +3873,9 @@ AUXILIARY BUS DRIVER
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
R: Dave Ertman <david.m.ertman@intel.com>
R: Ira Weiny <ira.weiny@intel.com>
R: Leon Romanovsky <leon@kernel.org>
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
F: Documentation/driver-api/auxiliary_bus.rst
F: drivers/base/auxiliary.c
F: include/linux/auxiliary_bus.h
@ -7233,7 +7234,7 @@ M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: "Rafael J. Wysocki" <rafael@kernel.org>
M: Danilo Krummrich <dakr@kernel.org>
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
F: Documentation/core-api/kobject.rst
F: drivers/base/
F: fs/debugfs/
@ -13118,7 +13119,7 @@ KERNFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Tejun Heo <tj@kernel.org>
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
F: fs/kernfs/
F: include/linux/kernfs.h
@ -18750,6 +18751,16 @@ F: include/asm-generic/pci*
F: include/linux/of_pci.h
F: include/linux/pci*
F: include/uapi/linux/pci*
PCI SUBSYSTEM [RUST]
M: Danilo Krummrich <dakr@kernel.org>
R: Bjorn Helgaas <bhelgaas@google.com>
R: Krzysztof Wilczyński <kwilczynski@kernel.org>
L: linux-pci@vger.kernel.org
S: Maintained
C: irc://irc.oftc.net/linux-pci
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
F: rust/helpers/pci.c
F: rust/kernel/pci.rs
F: samples/rust/rust_driver_pci.rs

View File

@ -156,6 +156,16 @@
* },
* .ops = my_custom_ops,
* };
*
* Please note that such custom ops approach is valid, but it is hard to implement
* it right without global locks per-device to protect from auxiliary_drv removal
* during call to that ops. In addition, this implementation lacks proper module
* dependency, which causes to load/unload races between auxiliary parent and devices
* modules.
*
* The most easiest way to provide these ops reliably without needing to
* have a lock is to EXPORT_SYMBOL*() them and rely on already existing
* modules infrastructure for validity and correct dependencies chains.
*/
static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,

View File

@ -73,6 +73,7 @@ static inline void subsys_put(struct subsys_private *sp)
kset_put(&sp->subsys);
}
struct subsys_private *bus_to_subsys(const struct bus_type *bus);
struct subsys_private *class_to_subsys(const struct class *class);
struct driver_private {
@ -180,6 +181,22 @@ int driver_add_groups(const struct device_driver *drv, const struct attribute_gr
void driver_remove_groups(const struct device_driver *drv, const struct attribute_group **groups);
void device_driver_detach(struct device *dev);
static inline void device_set_driver(struct device *dev, const struct device_driver *drv)
{
/*
* Majority (all?) read accesses to dev->driver happens either
* while holding device lock or in bus/driver code that is only
* invoked when the device is bound to a driver and there is no
* concern of the pointer being changed while it is being read.
* However when reading device's uevent file we read driver pointer
* without taking device lock (so we do not block there for
* arbitrary amount of time). We use WRITE_ONCE() here to prevent
* tearing so that READ_ONCE() can safely be used in uevent code.
*/
// FIXME - this cast should not be needed "soon"
WRITE_ONCE(dev->driver, (struct device_driver *)drv);
}
int devres_release_all(struct device *dev);
void device_block_probing(void);
void device_unblock_probing(void);

View File

@ -57,7 +57,7 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
* NULL. A call to subsys_put() must be done when finished with the pointer in
* order for it to be properly freed.
*/
static struct subsys_private *bus_to_subsys(const struct bus_type *bus)
struct subsys_private *bus_to_subsys(const struct bus_type *bus)
{
struct subsys_private *sp = NULL;
struct kobject *kobj;

View File

@ -2624,6 +2624,35 @@ static const char *dev_uevent_name(const struct kobject *kobj)
return NULL;
}
/*
* Try filling "DRIVER=<name>" uevent variable for a device. Because this
* function may race with binding and unbinding the device from a driver,
* we need to be careful. Binding is generally safe, at worst we miss the
* fact that the device is already bound to a driver (but the driver
* information that is delivered through uevents is best-effort, it may
* become obsolete as soon as it is generated anyways). Unbinding is more
* risky as driver pointer is transitioning to NULL, so READ_ONCE() should
* be used to make sure we are dealing with the same pointer, and to
* ensure that driver structure is not going to disappear from under us
* we take bus' drivers klist lock. The assumption that only registered
* driver can be bound to a device, and to unregister a driver bus code
* will take the same lock.
*/
static void dev_driver_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
struct subsys_private *sp = bus_to_subsys(dev->bus);
if (sp) {
scoped_guard(spinlock, &sp->klist_drivers.k_lock) {
struct device_driver *drv = READ_ONCE(dev->driver);
if (drv)
add_uevent_var(env, "DRIVER=%s", drv->name);
}
subsys_put(sp);
}
}
static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
{
const struct device *dev = kobj_to_dev(kobj);
@ -2655,8 +2684,8 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
if (dev->type && dev->type->name)
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
if (dev->driver)
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
/* Add "DRIVER=%s" variable if the device is bound to a driver */
dev_driver_uevent(dev, env);
/* Add common DT information about the device */
of_device_uevent(dev, env);
@ -2726,11 +2755,8 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
if (!env)
return -ENOMEM;
/* Synchronize with really_probe() */
device_lock(dev);
/* let the kset specific function add its keys */
retval = kset->uevent_ops->uevent(&dev->kobj, env);
device_unlock(dev);
if (retval)
goto out;
@ -3700,7 +3726,7 @@ done:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
DPMError:
dev->driver = NULL;
device_set_driver(dev, NULL);
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);

View File

@ -550,7 +550,7 @@ static void device_unbind_cleanup(struct device *dev)
arch_teardown_dma_ops(dev);
kfree(dev->dma_range_map);
dev->dma_range_map = NULL;
dev->driver = NULL;
device_set_driver(dev, NULL);
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);
@ -629,8 +629,7 @@ static int really_probe(struct device *dev, const struct device_driver *drv)
}
re_probe:
// FIXME - this cast should not be needed "soon"
dev->driver = (struct device_driver *)drv;
device_set_driver(dev, drv);
/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev);
@ -1014,7 +1013,7 @@ static int __device_attach(struct device *dev, bool allow_async)
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
device_set_driver(dev, NULL);
ret = 0;
}
} else {

View File

@ -816,21 +816,6 @@ static int add_memory_block(unsigned long block_id, unsigned long state,
return 0;
}
static int __init add_boot_memory_block(unsigned long base_section_nr)
{
unsigned long nr;
for_each_present_section_nr(base_section_nr, nr) {
if (nr >= (base_section_nr + sections_per_block))
break;
return add_memory_block(memory_block_id(base_section_nr),
MEM_ONLINE, NULL, NULL);
}
return 0;
}
static int add_hotplug_memory_block(unsigned long block_id,
struct vmem_altmap *altmap,
struct memory_group *group)
@ -957,7 +942,7 @@ static const struct attribute_group *memory_root_attr_groups[] = {
void __init memory_dev_init(void)
{
int ret;
unsigned long block_sz, nr;
unsigned long block_sz, block_id, nr;
/* Validate the configured memory block size */
block_sz = memory_block_size_bytes();
@ -970,15 +955,23 @@ void __init memory_dev_init(void)
panic("%s() failed to register subsystem: %d\n", __func__, ret);
/*
* Create entries for memory sections that were found
* during boot and have been initialized
* Create entries for memory sections that were found during boot
* and have been initialized. Use @block_id to track the last
* handled block and initialize it to an invalid value (ULONG_MAX)
* to bypass the block ID matching check for the first present
* block so that it can be covered.
*/
for (nr = 0; nr <= __highest_present_section_nr;
nr += sections_per_block) {
ret = add_boot_memory_block(nr);
if (ret)
panic("%s() failed to add memory block: %d\n", __func__,
ret);
block_id = ULONG_MAX;
for_each_present_section_nr(0, nr) {
if (block_id != ULONG_MAX && memory_block_id(nr) == block_id)
continue;
block_id = memory_block_id(nr);
ret = add_memory_block(block_id, MEM_ONLINE, NULL, NULL);
if (ret) {
panic("%s() failed to add memory block: %d\n",
__func__, ret);
}
}
}

View File

@ -1080,6 +1080,7 @@ void software_node_notify(struct device *dev)
if (!swnode)
return;
kobject_get(&swnode->kobj);
ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
if (ret)
return;
@ -1089,8 +1090,6 @@ void software_node_notify(struct device *dev)
sysfs_remove_link(&dev->kobj, "software_node");
return;
}
kobject_get(&swnode->kobj);
}
void software_node_notify_remove(struct device *dev)

View File

@ -2,6 +2,11 @@
/*
* fwnode.h - Firmware device node object handle type definition.
*
* This header file provides low-level data types and definitions for firmware
* and device property providers. The respective API header files supplied by
* them should contain all of the requisite data types and definitions for end
* users, so including it directly should not be necessary.
*
* Copyright (C) 2015, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*/

View File

@ -4,7 +4,7 @@
//!
//! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h)
use crate::{bindings, device::Device, error::Error, error::Result, str::CStr};
use crate::{bindings, device::Device, error::Error, error::Result, ffi, str::CStr};
use core::ptr::NonNull;
/// # Invariants
@ -12,7 +12,11 @@ use core::ptr::NonNull;
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
struct FwFunc(
unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32,
unsafe extern "C" fn(
*mut *const bindings::firmware,
*const ffi::c_char,
*mut bindings::device,
) -> i32,
);
impl FwFunc {