Require a borrowed `DeviceEnableGuard` for the same device before enabling bus-mastering. Check device identity so a guard for another device cannot satisfy this requirement.
Keep `set_master()` on `Device<Core>` to retain callback synchronization: the guard is shareable, while `pci_set_master()` modifies device state without locking. Convert nova-core to pass its enable guard. Link: https://lore.kernel.org/rust-for-linux/[email protected] Suggested-by: Danilo Krummrich <[email protected]> Signed-off-by: Maurice Hieronymus <[email protected]> --- drivers/gpu/nova-core/driver.rs | 2 +- rust/kernel/pci.rs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index f0aebfe705ba..94f207c6078d 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -107,7 +107,7 @@ fn probe<'bound>( try_pin_init!(NovaCore { _enable: { let enable = pdev.enable_device()?; - pdev.set_master(); + pdev.set_master(&enable)?; enable }, diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 75efd5c5ee97..20f45ca960cd 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -516,10 +516,18 @@ pub fn enable_device(&self) -> Result<DeviceEnableGuard<'_>> { } /// Enable bus-mastering for this device. + /// + /// Returns `EINVAL` if `enable` belongs to another device. #[inline] - pub fn set_master(&self) { - // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`. + pub fn set_master(&self, enable: &DeviceEnableGuard<'_>) -> Result { + if self.as_raw() != enable.dev.as_raw() { + return Err(EINVAL); + } + + // SAFETY: `self` is a valid device in core context, and `enable` + // keeps this device enabled for the duration of the call. unsafe { bindings::pci_set_master(self.as_raw()) }; + Ok(()) } } -- 2.54.0
