[PATCH 1/2] driver: core: Allow drivers to opt out of driver_override
From: Thierry Reding
Date: Tue Sep 22 2026 - 07:39:38 EST
From: Thierry Reding <treding@xxxxxxxxxx>
Some drivers rely on device data obtained through device ID matching and
will not work otherwise. Some such drivers don't check for the validity
of the device data because it is never NULL when the device is matched
against the device ID table.
However, Uwe recently pointed out that drivers always need to check this
device data because any device can be forced to bind against a driver if
their driver_override sysfs attribute is set and the driver rebound. Any
such device will now not have device data from a device ID match table
and may crash.
Add a flag that allows drivers to opt out of the override mechanism when
it doesn't make sense. This allows us to deal with these situations in
the core rather than sprinkle checks throughout all of these drivers to
check for validity of the device data.
Cc: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxx>
Signed-off-by: Thierry Reding <treding@xxxxxxxxxx>
---
include/linux/device.h | 12 +++++++++---
include/linux/device/driver.h | 12 ++++++++++++
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/include/linux/device.h b/include/linux/device.h
index 90cdd77458bb..45c23cc5efa8 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -899,14 +899,20 @@ static inline bool device_has_driver_override(struct device *dev)
*
* Returns > 0 if a driver override is set and matches the given driver, 0 if a
* driver override is set but does not match, or < 0 if a driver override is not
- * set at all.
+ * set at all or the driver opts out of the override mechanism.
*/
static inline int device_match_driver_override(struct device *dev,
const struct device_driver *drv)
{
guard(spinlock)(&dev->driver_override.lock);
- if (dev->driver_override.name)
- return !strcmp(dev->driver_override.name, drv->name);
+ if (dev->driver_override.name) {
+ if (strcmp(dev->driver_override.name, drv->name) != 0)
+ return 0;
+
+ if (driver_allow_override(drv))
+ return 1;
+ }
+
return -1;
}
diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h
index 29fbc01ef06f..c985622a67a5 100644
--- a/include/linux/device/driver.h
+++ b/include/linux/device/driver.h
@@ -57,6 +57,8 @@ enum probe_type {
* @owner: The module owner.
* @mod_name: Used for built-in modules.
* @suppress_bind_attrs: Disables bind/unbind via sysfs.
+ * @disallow_override: Prevents the driver from being bound to a device via
+ * driver_override.
* @probe_type: Type of the probe (synchronous or asynchronous) to use.
* @of_match_table: The open firmware table.
* @acpi_match_table: The ACPI match table.
@@ -105,6 +107,7 @@ struct device_driver {
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
+ bool disallow_override;
enum probe_type probe_type;
const struct of_device_id *of_match_table;
@@ -249,6 +252,15 @@ void driver_deferred_probe_add(struct device *dev);
int driver_deferred_probe_check_state(struct device *dev);
void driver_init(void);
+static inline bool driver_allow_override(const struct device_driver *drv)
+{
+ if (drv->disallow_override)
+ pr_err("driver '%s' cannot be bound to via override\n",
+ drv->name);
+
+ return !drv->disallow_override;
+}
+
/**
* module_driver() - Helper macro for drivers that don't do anything
* special in module init/exit. This eliminates a lot of boilerplate.
--
2.55.0