On Tue, Jul 01, 2025 at 11:25:41AM +0200, Greg KH wrote: > On Sat, Jun 21, 2025 at 09:43:26PM +0200, Danilo Krummrich wrote: > > This patch series consists of the following three parts. > > > > 1. Introduce the 'Internal' device context (semantically identical to the > > 'Core' device context), but only accessible for bus abstractions. > > > > 2. Introduce generic accessors for a device's driver_data pointer. Those are > > implemented for the 'Internal' device context only, in order to only enable > > bus abstractions to mess with the driver_data pointer of struct device. > > > > 3. Implement the Driver::unbind() callback (details below). > > > > Driver::unbind() > > ---------------- > > > > Currently, there's really only one core callback for drivers, which is > > probe(). > > > > Now, this isn't entirely true, since there is also the drop() callback of > > the driver type (serving as the driver's private data), which is returned > > by probe() and is dropped in remove(). > > > > On the C side remove() mainly serves two purposes: > > > > (1) Tear down the device that is operated by the driver, e.g. call bus > > specific functions, write I/O memory to reset the device, etc. > > > > (2) Release the resources that have been allocated by a driver for a > > specific device. > > > > The drop() callback mentioned above is intended to cover (2) as the Rust > > idiomatic way. > > > > However, it is partially insufficient and inefficient to cover (1) > > properly, since drop() can't be called with additional arguments, such as > > the reference to the corresponding device that has the correct device > > context, i.e. the Core device context. > > I'm missing something, why doesn't drop() have access to the device > itself, which has the Core device context? It's the same "object", > right? Not exactly, the thing in drop() is the driver's private data, which has the exact lifetime of a driver being bound to a device, which makes drop() pretty much identical to remove() in this aspect. // This is the private data of the driver. struct MyDriver { bar: Devres<pci::Bar>, ... } impl pci::Driver for MyDriver { fn probe( pdev: &pci::Device<Core>, info: &Self::IdInfo ) -> Result<Pin<KBox<Self>>> { let bar = ...; pdev.enable_device()?; KBox::pin_init(Self { bar }, GFP_KERNEL) } fn unbind(&self, pdev: &Device<Core>) { // Can only be called with a `&Device<Core>`. pdev.disable_device(); } } impl Drop for MyDriver { fn drop(&mut self) { // We don't need to do anything here, the destructor of `self.bar` // is called automatically, which is where the PCI BAR is unmapped // and the resource region is released. In fact, this impl block // is optional and can be omitted. } } The probe() method's return value is the driver's private data, which, due to being a ForeignOwnable, is stored in dev->driver_data by the bus abstraction. The lifetime goes until remove(), which is where the bus abstraction does not borrow dev->driver_data, but instead re-creates the original driver data object, which subsequently in the bus abstraction's remove() function goes out of scope and hence is dropped.