From nobody Mon Jun 8 06:23:01 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.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 AD48A3FB7DC for ; Tue, 2 Jun 2026 17:28:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421311; cv=none; b=dSqCwsA1S1fhmWaXT92Vs3qDLp2wxrQAiCdKwXxqAam94tSMdranE+hA7pbQPcw1cZyxFL9rmYHFdc8D0/pZp1aclS4IKkvHG9yYvgtcDQtUHez4wOI5I5X+w2okNVb4etEUzbC1JLZ64IwO1kbbh8X6mvshnOTiKfklGIK16LQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421311; c=relaxed/simple; bh=B2ettEfwrb1maCglnnHQMfh+NCX01PsYVUogO+O7KpE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=D5vI6zBILx8Hbm+sOpHgtfQbA1gxLem/nrnMr63ff8Kl+mU6VuhhnoOUe6UACAM3jIZML0A3Wan2l6T2cDf0iJAiFJzRUElaJ79p8Ll4+RCCtB6k4HPAOhNay72+AAupl0X4x9vKdr+P++yX2i9hAOqhgXR5NcSRqCkJBOeKH4Q= 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=VTn/f4zQ; arc=none smtp.client-ip=170.10.129.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="VTn/f4zQ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780421308; 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=iiu2k48lTbJ2zRhc2enw21PwFA9k//oCqgyKya13hYA=; b=VTn/f4zQfcr6N4NDvAHV4UFN/VvQdRHnjK4GPwlEqTp6z7luHQJukYlAvSsTyUFeJCmla3 bNizq6bATgQKlkJ2STkhi15G/yNjbXDx+NO46neUhTd7AckOAjO6qt6no0A1nMC0nCmNhu F1QvCxZWEDIgGITgjk9LEHXY9IWmX0E= Received: from mx-prod-mc-01.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-649-CLtrAznaN1mflpjtejW0WA-1; Tue, 02 Jun 2026 13:28:24 -0400 X-MC-Unique: CLtrAznaN1mflpjtejW0WA-1 X-Mimecast-MFC-AGG-ID: CLtrAznaN1mflpjtejW0WA_1780421301 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9F377195608F; Tue, 2 Jun 2026 17:28:20 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.216]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AC5DE19560A7; Tue, 2 Jun 2026 17:28:16 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, nouveau@lists.freedesktop.org Cc: Alexandre Courbot , Gary Guo , =?UTF-8?q?Christian=20K=C3=B6nig?= , driver-core@lists.linux.dev, Miguel Ojeda , Maarten Lankhorst , Alice Ryhl , Simona Vetter , linux-kernel@vger.kernel.org, Sumit Semwal , linux-media@vger.kernel.org, "Rafael J . Wysocki" , Thomas Zimmermann , Maxime Ripard , David Airlie , Benno Lossin , linaro-mm-sig@lists.linaro.org, Danilo Krummrich , Mukesh Kumar Chaurasiya , Asahi Lina , Daniel Almeida , Lyude Paul , Greg Kroah-Hartman Subject: [PATCH v16 1/6] rust: drm: gem/shmem: Add DmaResvGuard helper Date: Tue, 2 Jun 2026 13:25:00 -0400 Message-ID: <20260602172807.1051806-2-lyude@redhat.com> In-Reply-To: <20260602172807.1051806-1-lyude@redhat.com> References: <20260602172807.1051806-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.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Just a temporary holdover to make locking/unlocking the dma_resv lock much easier. Signed-off-by: Lyude Paul Co-authored-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- rust/kernel/drm/gem/shmem.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index 35d7523e164ff..066a820b0bffc 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -27,7 +27,10 @@ Deref, DerefMut, // }, - ptr::NonNull, + ptr::{ + self, + NonNull, // + }, }; use gem::{ BaseObjectPrivate, @@ -224,3 +227,29 @@ impl driver::AllocImpl for Object { dumb_map_offset: None, }; } + +/// Private helper-type for holding the `dma_resv` object for a GEM shmem = object. +/// +/// When this is dropped, the `dma_resv` lock is dropped as well. +/// +// TODO: This should be replace with a WwMutex equivalent once we have suc= h bindings in the kernel. +struct DmaResvGuard<'a, T: DriverObject>(&'a Object); + +impl<'a, T: DriverObject> DmaResvGuard<'a, T> { + #[inline(always)] + #[expect(unused)] + fn new(obj: &'a Object) -> Self { + // SAFETY: This lock is initialized throughout the lifetime of `ob= ject`. + unsafe { bindings::dma_resv_lock(obj.raw_dma_resv(), ptr::null_mut= ()) }; + + Self(obj) + } +} + +impl<'a, T: DriverObject> Drop for DmaResvGuard<'a, T> { + #[inline(always)] + fn drop(&mut self) { + // SAFETY: We are releasing the lock grabbed during the creation o= f this object. + unsafe { bindings::dma_resv_unlock(self.0.raw_dma_resv()) }; + } +} --=20 2.54.0 From nobody Mon Jun 8 06:23:01 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 9047F3FC5A1 for ; Tue, 2 Jun 2026 17:28:33 +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=1780421315; cv=none; b=RCvux2iPeT6TBqEr+Jwfm5DaRd6CpBogz52B3MD2yafLY7RViKaR6KIkQmWQdGGZsp2kPSILVi/kEessQxKHuy8CyvXfdgCF9CsIRoEFTdFfZ8Xwk/OR5nx1NMg3Fd5yQjOKl6YTJQGRqglL41qxHMa3EyNXzc8kQsimwGeq7lk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421315; c=relaxed/simple; bh=yKPcKS2MpFPg+M+N6KqYk8LHbyPjE6YqJKboKdIFKW0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uXMJe7Du1ZX1NvIqmAdgZp0WMRFr7QEww4Lhxokdl2EQPnR4cC9ReElVsZtzMwWF3RDCUjXsFbEW8MyGfCvpHCEhcm8Ss4Ej7SlqdS07PTp5Ykk9BlSOPA0NDP3mSScs44tiKMFuUKvgLK+8wzmDG2uun6WIPC1lIjrdtmfX7o4= 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=bkfZJBEA; 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="bkfZJBEA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780421312; 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=G16szch7yoIn/veBF2u86w0gskpJ02Xp0g+fTSiAhYQ=; b=bkfZJBEAnYQkL7L5koxtC2dhrfXTm9uRK5Hoh93SP1dRWD23pReqZlsp/G7ZsuAr/cRCym HOMI/6Lu4Nl9P8fHaSCyUOuWmbzsk4BhpYKbiFMISj57FTo3i+8z9BTwt3SGDeYDJf7nVD YlV4sFNXdGf+TPBcmE9LHSgALg0B7Fs= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-364-0vsbTWD-PH-okU7T1G8aJw-1; Tue, 02 Jun 2026 13:28:27 -0400 X-MC-Unique: 0vsbTWD-PH-okU7T1G8aJw-1 X-Mimecast-MFC-AGG-ID: 0vsbTWD-PH-okU7T1G8aJw_1780421304 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 600341800343; Tue, 2 Jun 2026 17:28:24 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.216]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id CF10119560B0; Tue, 2 Jun 2026 17:28:20 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, nouveau@lists.freedesktop.org Cc: Alexandre Courbot , Gary Guo , =?UTF-8?q?Christian=20K=C3=B6nig?= , driver-core@lists.linux.dev, Miguel Ojeda , Maarten Lankhorst , Alice Ryhl , Simona Vetter , linux-kernel@vger.kernel.org, Sumit Semwal , linux-media@vger.kernel.org, "Rafael J . Wysocki" , Thomas Zimmermann , Maxime Ripard , David Airlie , Benno Lossin , linaro-mm-sig@lists.linaro.org, Danilo Krummrich , Mukesh Kumar Chaurasiya , Asahi Lina , Daniel Almeida , Lyude Paul , Greg Kroah-Hartman Subject: [PATCH v16 2/6] rust: drm: gem: Add vmap functions to shmem bindings Date: Tue, 2 Jun 2026 13:25:01 -0400 Message-ID: <20260602172807.1051806-3-lyude@redhat.com> In-Reply-To: <20260602172807.1051806-1-lyude@redhat.com> References: <20260602172807.1051806-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.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" One of the more obvious use cases for gem shmem objects is the ability to create mappings into their contents. So, let's hook this up in our rust bindings. Signed-off-by: Lyude Paul --- V7: * Switch over to the new iosys map bindings that use the Io trait V8: * Get rid of iosys_map bindings for now, only support non-iomem types * s/as_shmem()/as_raw_shmem() V9: * Get rid of some outdated comments I missed * Add missing SIZE check to raw_vmap() * Add a proper unit test that ensures that we actually validate SIZE at compile-time. Turns out it takes only 34 lines to make a boilerplate DRM driver for a kunit test :) * Add unit tests * Add some missing #[inline]s V10: * Correct issue with iomem error path We previously called raw_vunmap() if we got an iomem allocation, but raw_vunmap() was written such that it assumed all allocations were sysmem allocations. Fix this by just making raw_vunmap() accept a iosys_map. V11: * Use Alexandre's clever solution to remove the macros we were using for maintaining two different VMap types. * Change the order of items in Object to ensure that sgt_res is always dropped before obj. * Fix typo in Object.raw_vmap() * s/raw_vmap()/make_vmap()/ Deduplicate code a bit more as well by using more generics here V15: * Add these patches back * We only have one VMap type now! * Use ObjectConfig::default() in unit tests since we unbroke it. V16: * Fix huge rebase error I made and did not notice that squashed 1.5 patches together that were definitely not supposed to be squashed * Update old commit message rust/kernel/drm/gem/shmem.rs | 303 ++++++++++++++++++++++++++++++++++- 1 file changed, 302 insertions(+), 1 deletion(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index 066a820b0bffc..843869056b1d7 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -18,11 +18,18 @@ Device, // }, error::to_result, + io::{ + Io, + IoCapable, + IoKnownSize, // + }, prelude::*, sync::aref::ARef, types::Opaque, // }; use core::{ + ffi::c_void, + mem::MaybeUninit, // ops::{ Deref, DerefMut, // @@ -33,6 +40,7 @@ }, }; use gem::{ + BaseObject, BaseObjectPrivate, DriverObject, IntoGEMObject, // @@ -177,6 +185,80 @@ extern "C" fn free_callback(obj: *mut bindings::drm_ge= m_object) { // SAFETY: We're recovering the Kbox<> we created in gem_create_ob= ject() let _ =3D unsafe { KBox::from_raw(this) }; } + + /// Attempt to create a vmap from the gem object, and confirm the size= of said vmap. + fn make_vmap<'a, R, const SIZE: usize>(&'a self) -> Result> + where + R: Deref + From<&'a Self>, + { + // INVARIANT: We check here that the gem object is at least as lar= ge as `SIZE`. + if self.size() < SIZE { + return Err(ENOSPC); + } + + let mut map: MaybeUninit =3D MaybeUninit::uni= nit(); + let guard =3D DmaResvGuard::new(self); + + // SAFETY: drm_gem_shmem_vmap can be called with the DMA reservati= on lock held + to_result(unsafe { + bindings::drm_gem_shmem_vmap_locked(self.as_raw_shmem(), map.a= s_mut_ptr()) + })?; + + // Drop the guard explicitly here, since we may need to call raw_v= unmap() (which re-acquires + // the lock). + drop(guard); + + // SAFETY: The call to drm_gem_shmem_vmap_locked succeeded above, = so we are guaranteed that + // map is properly initialized. + let map =3D unsafe { map.assume_init() }; + + // XXX: We don't currently support iomem allocations + if map.is_iomem { + // SAFETY: + // - The vmap operation above succeeded, guaranteeing that `ma= p` points to a valid + // memory mapping. + // - We checked that this is an iomem allocation, making it sa= fe to read vaddr_iomem + unsafe { self.raw_vunmap(map) }; + + Err(ENOTSUPP) + } else { + Ok(VMap { + // SAFETY: We checked that this is not an iomem allocation= , making it safe to read + // vaddr + addr: unsafe { map.__bindgen_anon_1.vaddr }, + owner: self.into(), + }) + } + } + + /// Unmap a vmap from the gem object. + /// + /// # Safety + /// + /// - The caller promises that `map` is a valid vmap on this gem objec= t. + /// - The caller promises that the memory pointed to by map will no lo= nger be accesed through + /// this instance. + unsafe fn raw_vunmap(&self, mut map: bindings::iosys_map) { + let _guard =3D DmaResvGuard::new(self); + + // SAFETY: + // - This function is safe to call with the DMA reservation lock h= eld. + // - Our `ARef` is proof that the underlying gem object here is in= itialized and thus safe to + // dereference. + unsafe { bindings::drm_gem_shmem_vunmap_locked(self.as_raw_shmem()= , &mut map) }; + } + + /// Creates and returns a virtual kernel memory mapping for this objec= t. + #[inline] + pub fn vmap(&self) -> Result> { + self.make_vmap() + } + + /// Creates and returns an owned reference to a virtual kernel memory = mapping for this object. + #[inline] + pub fn owned_vmap(&self) -> Result> { + self.make_vmap() + } } =20 impl Deref for Object { @@ -237,7 +319,6 @@ impl driver::AllocImpl for Object { =20 impl<'a, T: DriverObject> DmaResvGuard<'a, T> { #[inline(always)] - #[expect(unused)] fn new(obj: &'a Object) -> Self { // SAFETY: This lock is initialized throughout the lifetime of `ob= ject`. unsafe { bindings::dma_resv_lock(obj.raw_dma_resv(), ptr::null_mut= ()) }; @@ -253,3 +334,223 @@ fn drop(&mut self) { unsafe { bindings::dma_resv_unlock(self.0.raw_dma_resv()) }; } } + +macro_rules! impl_vmap_io_capable { + ($impl:ident, $ty:ty) =3D> { + impl IoCapable<$ty> for $impl + where + D: DriverObject, + R: Deref>, + { + #[inline(always)] + unsafe fn io_read(&self, address: usize) -> $ty { + let ptr =3D address as *mut $ty; + + // SAFETY: The safety contract of `io_read` guarantees tha= t address is a valid + // address within the bounds of `Self` of at least the siz= e of $ty, and is properly + // aligned. + unsafe { ptr::read(ptr) } + } + + #[inline(always)] + unsafe fn io_write(&self, value: $ty, address: usize) { + let ptr =3D address as *mut $ty; + + // SAFETY: The safety contract of `io_write` guarantees th= at address is a valid + // address within the bounds of `Self` of at least the siz= e of $ty, and is properly + // aligned. + unsafe { ptr::write(ptr, value) } + } + } + }; +} + +/// A reference to a virtual mapping for an shmem-based GEM object in kern= el address space. +/// +/// # Invariants +/// +/// - The size of `owner` is >=3D SIZE. +/// - The memory pointed to by addr remains valid at least until this obje= ct is dropped. +pub struct VMap +where + D: DriverObject, + R: Deref>, +{ + addr: *mut c_void, + owner: R, +} + +/// An alias type for a reference to a shmem-based GEM object's VMap. +pub type VMapRef<'a, D, const SIZE: usize =3D 0> =3D VMap= , SIZE>; + +/// An alias type for an owned reference to a shmem-based GEM object's VMa= p. +pub type VMapOwned =3D VMap>= , SIZE>; + +impl VMap +where + D: DriverObject, + R: Deref>, +{ + /// Borrows a reference to the object that owns this virtual mapping. + #[inline(always)] + pub fn owner(&self) -> &Object { + &self.owner + } +} + +impl Drop for VMap +where + D: DriverObject, + R: Deref>, +{ + #[inline(always)] + fn drop(&mut self) { + // SAFETY: + // - Our existence is proof that this map was previously created u= sing self.owner. + // - Since we are in Drop, we are guaranteed that no one will acce= ss the memory + // through this mapping after calling this. + unsafe { + self.owner.raw_vunmap(bindings::iosys_map { + is_iomem: false, + __bindgen_anon_1: bindings::iosys_map__bindgen_ty_1 { vadd= r: self.addr }, + }) + }; + } +} + +impl Io for VMap +where + D: DriverObject, + R: Deref>, +{ + #[inline(always)] + fn addr(&self) -> usize { + self.addr as usize + } + + #[inline(always)] + fn maxsize(&self) -> usize { + self.owner.size() + } +} + +impl IoKnownSize for VMap +where + D: DriverObject, + R: Deref>, +{ + const MIN_SIZE: usize =3D SIZE; +} + +impl_vmap_io_capable!(VMap, u8); +impl_vmap_io_capable!(VMap, u16); +impl_vmap_io_capable!(VMap, u32); +#[cfg(CONFIG_64BIT)] +impl_vmap_io_capable!(VMap, u64); + +#[kunit_tests(rust_drm_gem_shmem)] +mod tests { + use super::*; + use crate::{ + drm, + faux, + page::PAGE_SIZE, // + }; + + // The bare minimum needed to create a fake drm driver for kunit + + #[pin_data] + struct KunitData {} + struct KunitDriver; + struct KunitFile; + #[pin_data] + struct KunitObject {} + + const INFO: drm::DriverInfo =3D drm::DriverInfo { + major: 0, + minor: 0, + patchlevel: 0, + name: c"kunit", + desc: c"Kunit", + }; + + impl drm::file::DriverFile for KunitFile { + type Driver =3D KunitDriver; + + fn open(_dev: &drm::Device) -> Result>= > { + Ok(KBox::new(Self, GFP_KERNEL)?.into()) + } + } + + impl gem::DriverObject for KunitObject { + type Driver =3D KunitDriver; + type Args =3D (); + + fn new( + _dev: &drm::Device, + _size: usize, + _args: Self::Args, + ) -> impl PinInit { + try_pin_init!(KunitObject {}) + } + } + + #[vtable] + impl drm::Driver for KunitDriver { + type Data =3D KunitData; + type File =3D KunitFile; + type Object =3D Object; + + const INFO: drm::DriverInfo =3D INFO; + const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor] =3D &[]; + } + + fn create_drm_dev() -> Result<(faux::Registration, ARef>)> { + // Create a faux DRM device so we can test gem object creation. + let data =3D try_pin_init!(KunitData {}); + let dev =3D faux::Registration::new(c"Kunit", None)?; + let drm =3D drm::Device::::new(dev.as_ref(), data)?; + + Ok((dev, drm)) + } + + #[test] + fn compile_time_vmap_sizes() -> Result { + let (_dev, drm) =3D create_drm_dev()?; + + let obj =3D Object::::new(&drm, PAGE_SIZE, ObjectConf= ig::default(), ())?; + + // Try creating a normal vmap + obj.vmap::()?; + + // Try creating a vmap that's smaller then the size we specified + obj.vmap::<{ PAGE_SIZE - 100 }>()?; + + // Make sure creating a vmap that's too large fails + assert!(obj.vmap::<{ PAGE_SIZE + 200 }>().is_err()); + + Ok(()) + } + + #[test] + fn vmap_io() -> Result { + let (_dev, drm) =3D create_drm_dev()?; + + let obj =3D Object::::new(&drm, PAGE_SIZE, ObjectConf= ig::default(), ())?; + + let vmap =3D obj.vmap::()?; + + vmap.write8(0xDE, 0x0); + assert_eq!(vmap.read8(0x0), 0xDE); + vmap.write32(0xFFFFFFFF, 0x20); + + assert_eq!(vmap.read32(0x20), 0xFFFFFFFF); + + assert_eq!(vmap.read8(0x20), 0xFF); + assert_eq!(vmap.read8(0x21), 0xFF); + assert_eq!(vmap.read8(0x22), 0xFF); + assert_eq!(vmap.read8(0x23), 0xFF); + + Ok(()) + } +} --=20 2.54.0 From nobody Mon Jun 8 06:23:01 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 990513FB07A for ; Tue, 2 Jun 2026 17:28:36 +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=1780421318; cv=none; b=HG8r6VzMnlAj+ZFrK5pGgLgDJ+iGZwwbw7FyRZn9JVPwArUhES7q9ZtgK44vRgBFuK1QaSy4FumnkU2U0CDW+pqbzUPVprrd3T0FmcIA1WuHdI1/sAmrsBSSyC2N19DUgFjcbnZxTDPoebL5cmk5agTqOTB5rDUSK2so3TfXr74= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421318; c=relaxed/simple; bh=umwawEzRaVqGQ58SmcAjEXQ5zooLJBV9oJWhj8xBmeY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Jhed1CqIinDXYCBlB7yIv9LH8RobBROG6pyuXWR8ZPQxE/gP5XlPHeO+jYLAHutkLU4vx0IAS0L2bLa7gOTKl4ZWNnZfoOpKYWyV9jp2tc0r/g/fv4OPJypdwKTZYzy5RJxoc3582lVXYWePoFSgwl0iz6YciHpPf3I4EnV0U5w= 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=flD7AIcj; 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="flD7AIcj" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780421315; 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=ji3R873SgQHyxfzMQgkhE7LmK1MPE9r7ND0eG5Mf4OM=; b=flD7AIcjeFHPQGiz2DSV/RnGX+lG+8KC9pLqQlBp8ELsebnJrUdA0vLG9184Vvlwd+Tec9 lWXXPGyb/1kr4mbdcFHh8OVAj+Vlbyk+EscmCwBn8PrbAQrvNN57OHzsWOncKoPkoSVprt KBbz8H2GV1veH/qzMUzkdWUpcExezBk= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-630-hcXIVyfUOHO65GIIA9MZ-Q-1; Tue, 02 Jun 2026 13:28:31 -0400 X-MC-Unique: hcXIVyfUOHO65GIIA9MZ-Q-1 X-Mimecast-MFC-AGG-ID: hcXIVyfUOHO65GIIA9MZ-Q_1780421308 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E0E1D18005B5; Tue, 2 Jun 2026 17:28:27 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.216]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 90A7219560A7; Tue, 2 Jun 2026 17:28:24 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, nouveau@lists.freedesktop.org Cc: Alexandre Courbot , Gary Guo , =?UTF-8?q?Christian=20K=C3=B6nig?= , driver-core@lists.linux.dev, Miguel Ojeda , Maarten Lankhorst , Alice Ryhl , Simona Vetter , linux-kernel@vger.kernel.org, Sumit Semwal , linux-media@vger.kernel.org, "Rafael J . Wysocki" , Thomas Zimmermann , Maxime Ripard , David Airlie , Benno Lossin , linaro-mm-sig@lists.linaro.org, Danilo Krummrich , Mukesh Kumar Chaurasiya , Asahi Lina , Daniel Almeida , Lyude Paul , Greg Kroah-Hartman Subject: [PATCH v16 3/6] rust: sync: Add SetOnce::reset() Date: Tue, 2 Jun 2026 13:25:02 -0400 Message-ID: <20260602172807.1051806-4-lyude@redhat.com> In-Reply-To: <20260602172807.1051806-1-lyude@redhat.com> References: <20260602172807.1051806-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.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" This function simply drops the contents of the SetOnce, given a mutable reference - since that proves we have exclusive access to the SetOnce. Additionally, update the invariants for SetOnce to make it clear as to why this is safe. Signed-off-by: Lyude Paul --- rust/kernel/sync/set_once.rs | 60 +++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/rust/kernel/sync/set_once.rs b/rust/kernel/sync/set_once.rs index 139cef05e935f..d6e4fc2695673 100644 --- a/rust/kernel/sync/set_once.rs +++ b/rust/kernel/sync/set_once.rs @@ -15,7 +15,7 @@ /// /// # Invariants /// -/// - `init` may only increase in value. +/// - `init` may only increase in value, unless modified through a mutable= reference. /// - `init` may only assume values in the range `0..=3D2`. /// - `init =3D=3D 0` if and only if `value` is uninitialized. /// - `init =3D=3D 1` if and only if there is exactly one thread with excl= usive @@ -110,17 +110,61 @@ pub fn copy(&self) -> Option { self.as_ref().copied() } + + /// # Safety + /// + /// If this function returns `true`, `self` must be freed or `init` mu= st be reset to `0`. + unsafe fn drop_val(&mut self) -> bool { + if *self.init.get_mut() !=3D 2 { + return false; + } + + let value =3D self.value.get_mut(); + // SAFETY: Via our type invariants, `init` =3D=3D 2 means `value` = is initialized. + unsafe { value.assume_init_drop() }; + + true + } + + /// Unset the [`SetOnce`]. + /// + /// After this function is called, the [`SetOnce`] is empty and uninit= ialized. This function is + /// mainly intended for usage in destructors. + /// + /// Returns `true` if `self` was previously initialized. + /// + /// # Example + /// + /// ``` + /// # use kernel::sync::SetOnce; + /// let mut value =3D SetOnce::new(); + /// assert_eq!(value.populate(67), true); + /// + /// assert_eq!(value.reset(), true); + /// assert!(value.as_ref().is_none()); + /// assert_eq!(value.reset(), false); + /// + /// assert_eq!(value.populate(69), true); + /// ``` + pub fn reset(&mut self) -> bool { + // SAFETY: We write `0` to init below if this returns true. + let dropped =3D unsafe { self.drop_val() }; + if dropped { + // INVARIANT: + // - We set `init` back to 0 through a mutable reference. + // - We dropped `value` above. + *self.init.get_mut() =3D 0; + } + + dropped + } } =20 impl Drop for SetOnce { + #[inline(always)] fn drop(&mut self) { - if *self.init.get_mut() =3D=3D 2 { - let value =3D self.value.get_mut(); - // SAFETY: By the type invariants of `Self`, `self.init =3D=3D= 2` means that `self.value` - // contains a valid value. We have exclusive access, as we hol= d a `mut` reference to - // `self`. - unsafe { value.assume_init_drop() }; - } + // SAFETY: We are dropping this value. + unsafe { self.drop_val() }; } } =20 --=20 2.54.0 From nobody Mon Jun 8 06:23:01 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 A8F673FD133 for ; Tue, 2 Jun 2026 17:28:39 +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=1780421320; cv=none; b=SjYCybXiVCCLy0XpuAWdFIE1D8sC9dKFwdwTlhqNZpfscXoiVPhoel/3DcJLRKIfN0ecOr/7C/Youllo33yZRWP3fK6JF3s+R6bcjKDYO66gbAXTHpslrfW+oTyI5lu4NAoB0RhuGiEfUaJpI99mDWOoQk0e2u29uAaw0A4qEfI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421320; c=relaxed/simple; bh=niAHhGwKEZIiX6YNYm4W4nXlIqpIqpg+te/9jcaQdiU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YrvmWvodSl7TnfrDQsVbxMJ3+s3Pm97bH7YhAZXBFOxM2ZUvXVc6/gDnrfMsi7IDbNKZiXtZnoLxHOChafrbS/DcfsIIzcIsrHJL7nCp2SXdmJ2Z/0+szhdXJCRSebUeiJeN44F1SvIe0v9J4NIQ/Ql8ekr2ZSq0JGH104J9B1Y= 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=gEQjP3wB; 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="gEQjP3wB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780421318; 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=n2gylv3DYJqAPYFDxLeYUmhNrr6JQO+YmoPANh0AXF0=; b=gEQjP3wBcjWVNzP85BKDwlWmt5SoDxdQr3CN2iRk/bNYeVd7DYIZ0+hjCWhXdWJGg2hsZ7 +5sCdLu/y4hi6ojG8TGKwHBsHsjR7luiEdyePcRbDFdrn0EcJ7tlm/8lgTTK27JsoRPIV7 abyvSqi1KYKXRPr+7ojHFajcFP68vg0= Received: from mx-prod-mc-03.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-408-MVVaJtVhNfCOyC0yL5awjQ-1; Tue, 02 Jun 2026 13:28:34 -0400 X-MC-Unique: MVVaJtVhNfCOyC0yL5awjQ-1 X-Mimecast-MFC-AGG-ID: MVVaJtVhNfCOyC0yL5awjQ_1780421311 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 76E7519560B5; Tue, 2 Jun 2026 17:28:31 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.216]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1D2DE19560B0; Tue, 2 Jun 2026 17:28:28 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, nouveau@lists.freedesktop.org Cc: Alexandre Courbot , Gary Guo , =?UTF-8?q?Christian=20K=C3=B6nig?= , driver-core@lists.linux.dev, Miguel Ojeda , Maarten Lankhorst , Alice Ryhl , Simona Vetter , linux-kernel@vger.kernel.org, Sumit Semwal , linux-media@vger.kernel.org, "Rafael J . Wysocki" , Thomas Zimmermann , Maxime Ripard , David Airlie , Benno Lossin , linaro-mm-sig@lists.linaro.org, Danilo Krummrich , Mukesh Kumar Chaurasiya , Asahi Lina , Daniel Almeida , Lyude Paul , Greg Kroah-Hartman Subject: [PATCH v16 4/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Date: Tue, 2 Jun 2026 13:25:03 -0400 Message-ID: <20260602172807.1051806-5-lyude@redhat.com> In-Reply-To: <20260602172807.1051806-1-lyude@redhat.com> References: <20260602172807.1051806-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.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" I completely forgot when coming up with this type that #[derive(Default)] only works if all generics mentioned in the type implement Default (and T usually doesn't). This being said: We don't use `T` for anything besides using it for a reference type, so whether or not it implements `Default` shouldn't actually need to matter. So, fix this by just manually implementing Default instead of deriving it. Signed-off-by: Lyude Paul --- rust/kernel/drm/gem/shmem.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index 843869056b1d7..d8bda8c8e2fb2 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -50,7 +50,6 @@ /// /// This is used with [`Object::new()`] to control various properties that= can only be set when /// initially creating a shmem-backed GEM object. -#[derive(Default)] pub struct ObjectConfig<'a, T: DriverObject> { /// Whether to set the write-combine map flag. pub map_wc: bool, @@ -61,6 +60,16 @@ pub struct ObjectConfig<'a, T: DriverObject> { pub parent_resv_obj: Option<&'a Object>, } =20 +impl<'a, T: DriverObject> Default for ObjectConfig<'a, T> { + #[inline(always)] + fn default() -> Self { + Self { + map_wc: false, + parent_resv_obj: None, + } + } +} + /// A shmem-backed GEM object. /// /// # Invariants --=20 2.54.0 From nobody Mon Jun 8 06:23:01 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.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 4E2E63FB7F4 for ; Tue, 2 Jun 2026 17:28:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421326; cv=none; b=i143RzyQ9q9OV7OTcoiOhtaAdgYdRKwo0afRhj1QHc34JrDH+a0olIRXdmsVEIe1qIP1kKi1HkpSwJAX99RBRve0koV1Mj3fzmLI929mAjGfNzcsVmXi8JTCsps1fFVht8CSbX5CqigFQ2ddHulw7JuqIlwboMD5iAZqGkLomiE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421326; c=relaxed/simple; bh=NfValsT13B9XTlXeTicbkDGTa8+Fj2v0hJKR8oGpyBc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QFVG8tR/V222c0Jqp37OHZuwxNJTDGKvhOhTp40gB4p1JH9DqCk/XNtTXWmHTpj9QchxG6dqXGvmefQIjmRS6YUXhxsQyjPnVzjAZGYSkwGXtYf0T89O2s6QrBRAWvgn2V+3Lus77xF833eu560/NSNMbf1nHXCQQ2CbTqeL+Y0= 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=B+tvDs4j; arc=none smtp.client-ip=170.10.129.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="B+tvDs4j" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780421324; 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=cF/fCKGGsVn6l967F1Qq9M9WKaqTKMJ/A9UZOUtdnUs=; b=B+tvDs4jZoYNlGEqBi32O+fJmUTQh1vt9B/cYBQDFhQA14hO/fM5+PqPT3FIp8x0O7BQoA fp6I9DljwIgQLJehUnNyJk560Ca8ZHQI4jiOIxnDDuuBq9lasE6zJgzax9pUWDPC3Qi0R2 i0skPBHZhgiBGjftImBUwTYFFcypd+U= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-39-sPPblZQJNcCS6PCce_xYQw-1; Tue, 02 Jun 2026 13:28:38 -0400 X-MC-Unique: sPPblZQJNcCS6PCce_xYQw-1 X-Mimecast-MFC-AGG-ID: sPPblZQJNcCS6PCce_xYQw_1780421315 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E6C631800617; Tue, 2 Jun 2026 17:28:34 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.216]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A680F19560A7; Tue, 2 Jun 2026 17:28:31 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, nouveau@lists.freedesktop.org Cc: Alexandre Courbot , Gary Guo , =?UTF-8?q?Christian=20K=C3=B6nig?= , driver-core@lists.linux.dev, Miguel Ojeda , Maarten Lankhorst , Alice Ryhl , Simona Vetter , linux-kernel@vger.kernel.org, Sumit Semwal , linux-media@vger.kernel.org, "Rafael J . Wysocki" , Thomas Zimmermann , Maxime Ripard , David Airlie , Benno Lossin , linaro-mm-sig@lists.linaro.org, Danilo Krummrich , Mukesh Kumar Chaurasiya , Asahi Lina , Daniel Almeida , Lyude Paul , Greg Kroah-Hartman Subject: [PATCH v16 5/6] rust: faux: Allow retrieving a bound Device Date: Tue, 2 Jun 2026 13:25:04 -0400 Message-ID: <20260602172807.1051806-6-lyude@redhat.com> In-Reply-To: <20260602172807.1051806-1-lyude@redhat.com> References: <20260602172807.1051806-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.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" When writing up some rust code that used faux devices for unit testing, I noticed that we never actually added the Bound device context to faux::Registration's AsRef implementation. This being said: the Registration object itself is proof that a driver is bound to the device - so this should be safe. Signed-off-by: Lyude Paul --- rust/kernel/faux.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs index 43b4974f48cd2..e0856b2964a2c 100644 --- a/rust/kernel/faux.rs +++ b/rust/kernel/faux.rs @@ -25,7 +25,8 @@ /// /// # Invariants /// -/// `self.0` always holds a valid pointer to an initialized and registered= [`struct faux_device`]. +/// - `self.0` always holds a valid pointer to an initialized and register= ed [`struct faux_device`]. +/// - This object is proof that the object described by this `Registration= ` is bound to a device. /// /// [`struct faux_device`]: srctree/include/linux/device/faux.h pub struct Registration(NonNull); @@ -59,8 +60,8 @@ fn as_raw(&self) -> *mut bindings::faux_device { } } =20 -impl AsRef for Registration { - fn as_ref(&self) -> &device::Device { +impl AsRef> for Registration { + fn as_ref(&self) -> &device::Device { // SAFETY: The underlying `device` in `faux_device` is guaranteed = by the C API to be // a valid initialized `device`. unsafe { device::Device::from_raw(addr_of_mut!((*self.as_raw()).de= v)) } --=20 2.54.0 From nobody Mon Jun 8 06:23:01 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 181CD3FE653 for ; Tue, 2 Jun 2026 17:28:47 +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=1780421328; cv=none; b=kzXZFKORoOSe4pFDFyCkFwLX4Z3zUlTcTwds4u0C25L3mkjbi+n2WYCtZ5ZPQ5xcd4tNlI6C/YMN9XVuYE6EDdeBqb0EQx6bHe/R3FcyHGEYhuZMo5XIS8BMpZAVixfMy3uwMB4pbJhYhMRISP/MFp4freeO6Lr7/PEnwwJ+9gU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780421328; c=relaxed/simple; bh=NmUCp7qslc8XFJkupP69Bn/Zo4ys6RAPgaQ3b6oWJSI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=d/j55KGX1JRTCrHPGFjeyH09/S8NAg6O3tTMYyazTecazfuJBoPJzA1Sd9BuFe2WR167iPWEeDfejXGL2M7sa5rpudH2VmCttmhO05jITxGS9s0ZIrRrw/y1CXFRs4pn/dSmNAXMpYkYvuMakQIpckSGyGAnUU9D+5Zceb+CXz0= 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=NbqbAZlH; 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="NbqbAZlH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780421326; 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=Py8QBULlm1mORqcX9znWUmwgCz4TaZiMBkjWHVTZwr8=; b=NbqbAZlHeeMxQO1inDhBLqh5XRR53l553Y3tKb51ovZH/eZCaRivbZyP8lU/pFrmkXI99X we84KVr7eEdY6VfcfB1t/77UWrIEKU3Gpxre1kqgt8sJyDUeqYjFEVCC0nbo19oDHnhk/L +NPcg/BE9HLyJZwLhocBMNTXJic7xfU= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-622-kbSOoP56M6-VzNXl9JcMTQ-1; Tue, 02 Jun 2026 13:28:42 -0400 X-MC-Unique: kbSOoP56M6-VzNXl9JcMTQ-1 X-Mimecast-MFC-AGG-ID: kbSOoP56M6-VzNXl9JcMTQ_1780421318 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A9F701800451; Tue, 2 Jun 2026 17:28:38 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.216]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2185619560B4; Tue, 2 Jun 2026 17:28:35 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, nouveau@lists.freedesktop.org Cc: Alexandre Courbot , Gary Guo , =?UTF-8?q?Christian=20K=C3=B6nig?= , driver-core@lists.linux.dev, Miguel Ojeda , Maarten Lankhorst , Alice Ryhl , Simona Vetter , linux-kernel@vger.kernel.org, Sumit Semwal , linux-media@vger.kernel.org, "Rafael J . Wysocki" , Thomas Zimmermann , Maxime Ripard , David Airlie , Benno Lossin , linaro-mm-sig@lists.linaro.org, Danilo Krummrich , Mukesh Kumar Chaurasiya , Asahi Lina , Daniel Almeida , Lyude Paul , Greg Kroah-Hartman Subject: [PATCH v16 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Date: Tue, 2 Jun 2026 13:25:05 -0400 Message-ID: <20260602172807.1051806-7-lyude@redhat.com> In-Reply-To: <20260602172807.1051806-1-lyude@redhat.com> References: <20260602172807.1051806-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.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" In order to do this, we need to be careful to ensure that any interface we expose for scatterlists ensures that any mappings created from one are destroyed on driver-unbind. To do this, we introduce a Devres resource into shmem::Object that we use in order to ensure that we release any SGTable mappings on driver-unbind. There's some other slightly unfortunate caveats of this: * Drivers don't have explicit control at the moment over when unmapping happens (which is exactly the same as the C side atm, so it might not be a problem). * We can't just return `SGTableMap` to the user through an Arc to attempt to fix the last caveat - because that implies the gem object would need to hold a reference count to the scatterlist mapping, which just leaves us with the same problem. Signed-off-by: Lyude Paul --- V3: * Rename OwnedSGTable to shmem::SGTable. Since the current version of the SGTable abstractions now has a `Owned` and `Borrowed` variant, I think renaming this to shmem::SGTable makes things less confusing. We do however, keep the name of owned_sg_table() as-is. V4: * Clarify safety comments for SGTable to explain why the object is thread-safe. * Rename from SGTableRef to SGTable V10: * Use Devres in order to ensure that SGTables are revocable, and are unmapped on driver-unbind. V11: * s/create_sg_table()/get_sg_table() * Get rid of extraneous `ret =3D ` in shmem::Object::get_sg_table() V12: * Actually move sgt_res in this patch and not the next one V13: * Use DmaResvGuard suggestion from Alexander * Use Alexander's (much better) solution for get_sg_table() * Use SetOnce instead of UnsafeCell * s/SGTableRef/SGTableMap * Fix typo in SGTableMap documentation * Create fallible constructor for SGTableMap * Don't reuse dma_resv lock for protecting Object contents, just use Mutex + SetOnce * Drop use of drm_gem_shmem_get_pages_sgt_locked(), since we don't need to hold the dma_resv lock ourselves for anything but this function. * Check that the device we receive in the bounds for sg_table() and owned_sg_table() that said Device is in fact, the correct device. * Remove redundant docs in owned_sg_table(), just point it back to sg_table(). * Implement Deborah's suggestion to fix double-free in free_callback() * Restore original order of Object * Fix doc typo for SGTableMap V14: * Use new InitOnce container over the Mutex/SetOnce horror show we had before. * Start using LazyInit container for storing Devres for sgt unmap * Add some kunit tests for sg_table (not sure why I didn't do this before) using some of the boilerplate code leftover from the vmap bindings * Get rid of the owned SGTable variant for now, we'll add it back in a future patch if people actually need it. * Use new LazyInit container from me to get rid of the horrid Mutex> mess. * Add the best we can do for unit tests w/r/t SGTable at the moment V16: * Get rid of LazyInit, go back to SetOnce, use trick that Alice recommended that is a lot cleaner. * Fix horrid rebasing mistake rust/kernel/drm/gem/shmem.rs | 164 +++++++++++++++++++++++++++++++++-- 1 file changed, 155 insertions(+), 9 deletions(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index d8bda8c8e2fb2..5f27e8d59e765 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -11,20 +11,34 @@ =20 use crate::{ container_of, + device::{ + self, + Bound, // + }, + devres::*, drm::{ driver, gem, private::Sealed, Device, // }, - error::to_result, + error::{ + from_err_ptr, + to_result, // + }, io::{ Io, IoCapable, IoKnownSize, // }, prelude::*, - sync::aref::ARef, + scatterlist, + sync::{ + aref::ARef, + new_mutex, + Mutex, + SetOnce, // + }, types::Opaque, // }; use core::{ @@ -83,6 +97,11 @@ pub struct Object { obj: Opaque, /// Parent object that owns this object's DMA reservation object. parent_resv_obj: Option>>, + /// Devres object for unmapping any SGTable on driver-unbind. + sgt_res: SetOnce>>, + #[pin] + /// Lock for protecting initialization of `sgt_res`. + sgt_lock: Mutex<()>, #[pin] inner: T, } @@ -135,6 +154,8 @@ pub fn new( try_pin_init!(Self { obj <- Opaque::init_zeroed(), parent_resv_obj: config.parent_resv_obj.map(|p| p.into()), + sgt_res: SetOnce::new(), + sgt_lock <- new_mutex!(()), inner <- T::new(dev, size, args), }), GFP_KERNEL, @@ -178,18 +199,23 @@ extern "C" fn free_callback(obj: *mut bindings::drm_g= em_object) { // - DRM always passes a valid gem object here // - We used drm_gem_shmem_create() in our create_gem_object callb= ack, so we know that // `obj` is contained within a drm_gem_shmem_object - let this =3D unsafe { container_of!(obj, bindings::drm_gem_shmem_o= bject, base) }; - - // SAFETY: - // - We're in free_callback - so this function is safe to call. - // - We won't be using the gem resources on `this` after this call. - unsafe { bindings::drm_gem_shmem_release(this) }; + let base =3D unsafe { container_of!(obj, bindings::drm_gem_shmem_o= bject, base) }; =20 // SAFETY: // - We verified above that `obj` is valid, which makes `this` val= id // - This function is set in AllocOps, so we know that `this` is c= ontained within a // `Object` - let this =3D unsafe { container_of!(Opaque::cast_from(this), Self,= obj) }.cast_mut(); + let this =3D unsafe { container_of!(Opaque::cast_from(base), Self,= obj) }.cast_mut(); + + // We need to drop `sgt_res` first, since doing so requires that t= he GEM object is still + // alive. + // SAFETY: We verified above that `this` is valid. + unsafe { &mut (*this).sgt_res }.reset(); + + // SAFETY: + // - We're in free_callback - so this function is safe to call. + // - We won't be using the gem resources on `this` after this call. + unsafe { bindings::drm_gem_shmem_release(base) }; =20 // SAFETY: We're recovering the Kbox<> we created in gem_create_ob= ject() let _ =3D unsafe { KBox::from_raw(this) }; @@ -268,6 +294,45 @@ pub fn vmap(&self) -> Result> { pub fn owned_vmap(&self) -> Result> { self.make_vmap() } + + /// Creates (if necessary) and returns an immutable reference to a sca= tter-gather table of DMA + /// pages for this object. + /// + /// This will pin the object in memory. It is expected that `dev` shou= ld be a pointer to the + /// same [`device::Device`] which `self` belongs to, otherwise this fu= nction will return + /// `Err(EINVAL)`. + pub fn sg_table<'a>( + &'a self, + dev: &'a device::Device, + ) -> Result<&'a scatterlist::SGTable> { + if dev.as_raw() !=3D self.dev().as_ref().as_raw() { + return Err(EINVAL); + } + + let sgt_res =3D 'out: { + // Fast path: sgt_res is already initialized + if let Some(sgt_res) =3D self.sgt_res.as_ref() { + break 'out sgt_res; + } + + // Slow path: Grab the lock and see if we need to initialize s= gt_res. + let _guard =3D self.sgt_lock.lock(); + + // If someone initialized it while we were waiting, we can exi= t early. + if let Some(sgt_res) =3D self.sgt_res.as_ref() { + break 'out sgt_res; + } + + // If not, finish initializing and return. + self.sgt_res + .populate(Devres::new(dev, SGTableMap::new(self))?); + + // SAFETY: We just populated sgt_res above. + unsafe { self.sgt_res.as_ref().unwrap_unchecked() } + }; + + Ok(sgt_res.access(dev)?) + } } =20 impl Deref for Object { @@ -457,6 +522,63 @@ impl IoKnownSize for VMap #[cfg(CONFIG_64BIT)] impl_vmap_io_capable!(VMap, u64); =20 +/// A reference to a GEM object that is known to have a mapped [`SGTable`]. +/// +/// This is used by the Rust bindings with [`Devres`] in order to ensure t= hat mappings for SGTables +/// on GEM shmem objects are revoked on driver-unbind. +/// +/// # Invariants +/// +/// - `self.obj` always points to a valid GEM object. +/// - This object is proof that `self.obj.owner.sgt` has an initialized an= d valid +/// [`scatterlist::SGTable`]. +pub struct SGTableMap { + obj: NonNull>, +} + +impl Deref for SGTableMap { + type Target =3D scatterlist::SGTable; + + fn deref(&self) -> &Self::Target { + // SAFETY: + // - The NonNull is guaranteed to be valid via our type invariants. + // - The sgt field is guaranteed to be initialized and valid via o= ur type invariants. + unsafe { scatterlist::SGTable::from_raw((*self.obj.as_ref().as_raw= _shmem()).sgt) } + } +} + +impl Drop for SGTableMap { + fn drop(&mut self) { + // SAFETY: `obj` is always valid via our type invariants + let obj =3D unsafe { self.obj.as_ref() }; + let _lock =3D DmaResvGuard::new(obj); + + // SAFETY: We acquired the lock needed for calling this function a= bove + unsafe { bindings::__drm_gem_shmem_free_sgt_locked(obj.as_raw_shme= m()) }; + } +} + +impl SGTableMap { + fn new(obj: &Object) -> impl Init { + // INVARIANT: + // - We call drm_gem_shmem_get_pages_sgt_locked below and check wh= ether or not it + // succeeds, fulfilling the invariant of SGTableMap that the obj= ect's `sgt` field is + // initialized. + // SAFETY: + // - `obj` is fully initialized, making this function safe to call. + from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as= _raw_shmem()) })?; + + Ok(Self { obj: obj.into() }) + } +} + +// SAFETY: The NonNull in SGTableMap is guaranteed valid by our type invar= iants, and the GEM object +// it points to is guaranteed to be thread-safe. +unsafe impl Send for SGTableMap {} +// SAFETY: The NonNull in SGTableMap is guaranteed valid by our type invar= iants, and the GEM object +// it points to is guaranteed to be thread-safe. +unsafe impl Sync for SGTableMap {} + #[kunit_tests(rust_drm_gem_shmem)] mod tests { use super::*; @@ -562,4 +684,28 @@ fn vmap_io() -> Result { =20 Ok(()) } + + // TODO: I would love to actually test the success paths of sg_table()= , but that would require + // also implementing dummy dma_ops so that trying to create a mapping = doesn't explode. So, leave + // that for someone else. + + // Ensures that passing the wrong device to sg_table() fails as we exp= ect, and also ensure it + // skips initializing `sgt_res` since we could otherwise create `sgt_r= es` with the wrong device + // bound to it. + #[test] + fn fail_sg_table_on_wrong_dev() -> Result { + let (_dev, drm) =3D create_drm_dev()?; + let wrong_dev =3D faux::Registration::new(c"EvilKunit", None)?; + + let obj =3D Object::::new(&drm, PAGE_SIZE, ObjectConf= ig::default(), ())?; + + assert_eq!(obj.sg_table(wrong_dev.as_ref()).err().unwrap(), EINVAL= ); + + // If sgt_res was not initialized mistakenly with the wrong device= , this should still fail. + assert_eq!(obj.sg_table(wrong_dev.as_ref()).err().unwrap(), EINVAL= ); + + // TODO: Someday, we should test that creating an sg_table here st= ill succeeds. + + Ok(()) + } } --=20 2.54.0