From 6f61a2637abe4f89877da3280775565baedb60e0 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 21 Oct 2025 00:34:24 +0200 Subject: rust: device: introduce Device::drvdata() In C dev_get_drvdata() has specific requirements under which it is valid to access the returned pointer. That is, drivers have to ensure that (1) for the duration the returned pointer is accessed the driver is bound and remains to be bound to the corresponding device, (2) the returned void * is treated according to the driver's private data type, i.e. according to what has been passed to dev_set_drvdata(). In Rust, (1) can be ensured by simply requiring the Bound device context, i.e. provide the drvdata() method for Device only. For (2) we would usually make the device type generic over the driver type, e.g. Device, where ::Data is the type of the driver's private data. However, a device does not have a driver type known at compile time and may be bound to multiple drivers throughout its lifetime. Hence, in order to be able to provide a safe accessor for the driver's device private data, we have to do the type check on runtime. This is achieved by letting a driver assert the expected type, which is then compared to a type hash stored in struct device_private when dev_set_drvdata() is called. Example: // `dev` is a `&Device`. let data = dev.drvdata::()?; There are two aspects to note: (1) Technically, the same check could be achieved by comparing the struct device_driver pointer of struct device with the struct device_driver pointer of the driver struct (e.g. struct pci_driver). However, this would - in addition the pointer comparison - require to tie back the private driver data type to the struct device_driver pointer of the driver struct to prove correctness. Besides that, accessing the driver struct (stored in the module structure) isn't trivial and would result into horrible code and API ergonomics. (2) Having a direct accessor to the driver's private data is not commonly required (at least in Rust): Bus callback methods already provide access to the driver's device private data through a &self argument, while other driver entry points such as IRQs, workqueues, timers, IOCTLs, etc. have their own private data with separate ownership and lifetime. In other words, a driver's device private data is only relevant for driver model contexts (such a file private is only relevant for file contexts). Having that said, the motivation for accessing the driver's device private data with Device::drvdata() are interactions between drivers. For instance, when an auxiliary driver calls back into its parent, the parent has to be capable to derive its private data from the corresponding device (i.e. the parent of the auxiliary device). Reviewed-by: Alice Ryhl Reviewed-by: Greg Kroah-Hartman [ * Remove unnecessary `const _: ()` block, * rename type_id_{store,match}() to {set,match}_type_id(), * assert size_of::() >= size_of::(), * add missing check in case Device::drvdata() is called from probe(). - Danilo ] Signed-off-by: Danilo Krummrich --- drivers/base/base.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/base/base.h') diff --git a/drivers/base/base.h b/drivers/base/base.h index 86fa7fbb3548..430cbefbc97f 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -85,6 +85,18 @@ struct driver_private { }; #define to_driver(obj) container_of(obj, struct driver_private, kobj) +#ifdef CONFIG_RUST +/** + * struct driver_type - Representation of a Rust driver type. + */ +struct driver_type { + /** + * @id: Representation of core::any::TypeId. + */ + u8 id[16]; +} __packed; +#endif + /** * struct device_private - structure to hold the private to the driver core portions of the device structure. * @@ -100,6 +112,7 @@ struct driver_private { * @async_driver - pointer to device driver awaiting probe via async_probe * @device - pointer back to the struct device that this structure is * associated with. + * @driver_type - The type of the bound Rust driver. * @dead - This device is currently either in the process of or has been * removed from the system. Any asynchronous events scheduled for this * device should exit without taking any action. @@ -116,6 +129,9 @@ struct device_private { const struct device_driver *async_driver; char *deferred_probe_reason; struct device *device; +#ifdef CONFIG_RUST + struct driver_type driver_type; +#endif u8 dead:1; }; #define to_device_private_parent(obj) \ -- cgit v1.2.3