From nobody Mon Apr 6 23:08:22 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E5F65390C93 for ; Tue, 17 Mar 2026 21:32:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773783163; cv=none; b=nWtU4zYM0azHkaPHixykIzOX2T4xtVjXxpJotPiC40WO7B0MDSXPzYxI2csjHNiascU+R7PFBKD/QvlCeqz0ooLvABL0V7HmUq/WmOyOFM0fAlU+k3zz0ofxNu1eqocW9JUoQEJeN20PVEpBYTCtVA10UD5GnYGLJAZAd5dpWZw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773783163; c=relaxed/simple; bh=ESiXfncXS2izOgbwXx5WrhI7jnlONfC9CC3nzhJtA0w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WaPHsppTaaYSB7d9ijpah8kVbXsuTIA+b7dwV8jEuvvor707JTs7kz/v+2hIxH00DcxmWkIwEMPD12wx+mZCEoMsx7WT2Zdsrd5VXo7hqQwHvhA1wCk6lPhKZm63exyJyIp2siRCZmmCDNEB/xyzPGASgqVeIatK52jDaKMNqkc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=K/QQtrMw; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="K/QQtrMw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773783155; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wGtfFjSjWYMLsOVqXnCtBMJhQmVE58CI5Thu+EfYcjY=; b=K/QQtrMwUn97dFCNsrweYGQAHIwzFX2wS+CL6jDZonPxy1p0ABlckdP+5Pux9r+rmVwvyq hdFkpDM8Vmgn8YL5RJpWaN4j7267+DJltrC/qu3mG2wgvhmv1zTmrnAajWhHSeBp/ndA/7 4TTagMPjnvJPvrYHYHb5a8bLPQZk0+M= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-396--XMzTl-3PSCtNGkvLUzoeg-1; Tue, 17 Mar 2026 17:32:31 -0400 X-MC-Unique: -XMzTl-3PSCtNGkvLUzoeg-1 X-Mimecast-MFC-AGG-ID: -XMzTl-3PSCtNGkvLUzoeg_1773783149 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4E3AC195608B; Tue, 17 Mar 2026 21:32:29 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.64.56]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id CF0FD1800361; Tue, 17 Mar 2026 21:32:26 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, Danilo Krummrich , rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org Cc: Daniel Almeida , nouveau@lists.freedesktop.org, "Gary Guo" , "Miguel Ojeda" , "Simona Vetter" , "Alice Ryhl" , "Shankari Anand" , "David Airlie" , "Benno Lossin" , "Asahi Lina" , "Lyude Paul" Subject: [PATCH v5 2/4] rust/drm: Don't setup private driver data until registration Date: Tue, 17 Mar 2026 17:28:31 -0400 Message-ID: <20260317213003.606088-3-lyude@redhat.com> In-Reply-To: <20260317213003.606088-1-lyude@redhat.com> References: <20260317213003.606088-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Now that we have a DeviceContext that we can use to represent whether a Device is known to have been registered, we can make it so that drivers can create their Devices but wait until the registration phase to assign their private data to the Device. This is desirable as some drivers need to make use of the DRM device early on before finalizing their private driver data. As such, this change makes it so that the driver's private data can currently only be accessed through Device types and not Device. Signed-off-by: Lyude Paul Reviewed-by: Daniel Almeida --- V4: * Remove accidental double-aliasing &mut in Device::release() V5: * Change new members of Device to pub(super) Signed-off-by: Lyude Paul --- drivers/gpu/drm/nova/driver.rs | 4 +-- drivers/gpu/drm/tyr/driver.rs | 4 +-- rust/kernel/drm/device.rs | 64 +++++++++++++++++++++------------- rust/kernel/drm/driver.rs | 19 ++++++++-- 4 files changed, 59 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index 99d6841b69cbc..8cea5f68c3b04 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -56,8 +56,8 @@ impl auxiliary::Driver for NovaDriver { fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> impl= PinInit { let data =3D try_pin_init!(NovaData { adev: adev.into() }); =20 - let drm =3D drm::UnregisteredDevice::::new(adev.as_ref(), da= ta)?; - let drm =3D drm::Registration::new_foreign_owned(drm, adev.as_ref(= ), 0)?; + let drm =3D drm::UnregisteredDevice::::new(adev.as_ref())?; + let drm =3D drm::Registration::new_foreign_owned(drm, adev.as_ref(= ), data, 0)?; =20 Ok(Self { drm: drm.into() }) } diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 6238f6e2b3bd2..76c5aed1171b1 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -145,8 +145,8 @@ fn probe( gpu_info, }); =20 - let tdev =3D drm::UnregisteredDevice::::new(pdev.as_= ref(), data)?; - let tdev =3D drm::driver::Registration::new_foreign_owned(tdev, pd= ev.as_ref(), 0)?; + let tdev =3D drm::UnregisteredDevice::::new(pdev.as_= ref())?; + let tdev =3D drm::driver::Registration::new_foreign_owned(tdev, pd= ev.as_ref(), data, 0)?; =20 let driver =3D TyrPlatformDriverData { _device: tdev.into(), diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index b47dd9c29d578..74321fb6a9fab 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -26,13 +26,15 @@ }; use core::{ alloc::Layout, + cell::UnsafeCell, marker::PhantomData, - mem, - ops::Deref, - ptr::{ + mem::{ self, - NonNull, // + MaybeUninit, // }, + ops::Deref, + ptr::NonNull, + sync::atomic::*, }; =20 #[cfg(CONFIG_DRM_LEGACY)] @@ -141,7 +143,7 @@ impl DeviceContext for Uninit {} /// /// The device in `self.0` is guaranteed to be a newly created [`Device`] = that has not yet been /// registered with userspace until this type is dropped. -pub struct UnregisteredDevice(ARef>, Not= ThreadSafe); +pub struct UnregisteredDevice(pub(crate) ARef>, NotThreadSafe); =20 impl Deref for UnregisteredDevice { type Target =3D Device; @@ -188,7 +190,7 @@ impl UnregisteredDevice { /// Create a new `UnregisteredDevice` for a `drm::Driver`. /// /// This can be used to create a [`Registration`](kernel::drm::Registr= ation). - pub fn new(dev: &device::Device, data: impl PinInit) -= > Result { + pub fn new(dev: &device::Device) -> Result { // `__drm_dev_alloc` uses `kmalloc()` to allocate memory, hence en= sure a `kmalloc()` // compatible `Layout`. let layout =3D Kmalloc::aligned_layout(Layout::new::>()); @@ -207,22 +209,6 @@ pub fn new(dev: &device::Device, data: impl PinInit) -> Result) -> Result { dev: Opaque, - data: T::Data, + + /// Keeps track of whether we've initialized the device data yet. + pub(super) data_is_init: AtomicBool, + + /// The Driver's private data. + /// + /// This must only be written to from [`drm::Registration::new`]. + pub(super) data: UnsafeCell>, + _ctx: PhantomData, } =20 @@ -304,6 +298,22 @@ extern "C" fn release(ptr: *mut bindings::drm_device) { // SAFETY: `ptr` is a valid pointer to a `struct drm_device` and e= mbedded in `Self`. let this =3D unsafe { Self::from_drm_device(ptr) }; =20 + // SAFETY: + // - Since we are in release(), we are guaranteed that no one else= has access to `this`. + // - We confirmed above that `this` is a valid pointer to an initi= alized `Self`. + let is_init =3D unsafe { &*this }.data_is_init.load(Ordering::Rela= xed); + if is_init { + // SAFETY: + // - We confirmed we have unique access to this above. + // - We confirmed that `data` is initialized above. + let data_ptr =3D unsafe { &mut (*this).data }; + + // SAFETY: + // - We checked that the data is initialized above. + // - We do not use `data` any point after calling this functio= n. + unsafe { data_ptr.get_mut().assume_init_drop() }; + } + // SAFETY: // - When `release` runs it is guaranteed that there is no further= access to `this`. // - `this` is valid for dropping. @@ -322,11 +332,15 @@ pub(crate) unsafe fn assume_ctx(&self) -> &Device Deref for Device { +impl Deref for Device { type Target =3D T::Data; =20 fn deref(&self) -> &Self::Target { - &self.data + // SAFETY: + // - `data` is initialized before any `Device`s with the `Register= ed` context are available + // to the user. + // - `data` is only written to once in `Registration::new()`, so t= his read will never race. + unsafe { (&*self.data.get()).assume_init_ref() } } } =20 diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs index 55b01ee088548..cfb8884ece700 100644 --- a/rust/kernel/drm/driver.rs +++ b/rust/kernel/drm/driver.rs @@ -15,7 +15,8 @@ }; use core::{ mem, - ptr::NonNull, // + ptr::NonNull, + sync::atomic::*, // }; =20 /// Driver use the GEM memory manager. This should be set for all modern d= rivers. @@ -127,7 +128,18 @@ pub trait Driver { pub struct Registration(ARef>); =20 impl Registration { - fn new(drm: drm::UnregisteredDevice, flags: usize) -> Result { + fn new( + drm: drm::UnregisteredDevice, + data: impl PinInit, + flags: usize, + ) -> Result { + // SAFETY: + // - `raw_data` is a valid pointer to uninitialized memory. + // - `raw_data` will not move until it is dropped. + unsafe { data.__pinned_init(drm.0.data.get().cast()) }?; + + drm.data_is_init.store(true, Ordering::Relaxed); + // SAFETY: `drm.as_raw()` is valid by the invariants of `drm::Devi= ce`. to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags)= })?; =20 @@ -150,6 +162,7 @@ fn new(drm: drm::UnregisteredDevice, flags: usize) -= > Result { pub fn new_foreign_owned<'a>( drm: drm::UnregisteredDevice, dev: &'a device::Device, + data: impl PinInit, flags: usize, ) -> Result<&'a drm::Device> where @@ -159,7 +172,7 @@ pub fn new_foreign_owned<'a>( return Err(EINVAL); } =20 - let reg =3D Registration::::new(drm, flags)?; + let reg =3D Registration::::new(drm, data, flags)?; let drm =3D NonNull::from(reg.device()); =20 devres::register(dev, reg, GFP_KERNEL)?; --=20 2.53.0