From nobody Mon Jun 8 09:48:38 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 4D9A839D6FD for ; Wed, 3 Jun 2026 19:52:31 +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=1780516354; cv=none; b=rpFraRuu9l0iSgw5s3hX1DPDCyt83yRui0n5dNHiMQcMyeLXVYKLr7Obz4hti9al/EoNu358Nf1jM4u06PHphdh8YOybBfrdYTbYHTKc+FaMKkJ26sO5t3sCDiaGcKx/Eq1BE63feJA9AQbzYpi14poI8FqiQtm81dKwWcY+Oz8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780516354; c=relaxed/simple; bh=Y1zcDOXSszlJuofsWKWpt+J9xZGS0l3vKMIEq3in/XI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SG82EoLddk8FzblpdFSem6wz53PdhoPC9wR9uudNSj11dNbVX0DB4n6cYtIcw/CZOnOMWEVGXf7jzgxTjRsidHObU0daFSPnbZrRCxgAE8z63I9eghO77w/uV1Qm76dKqYYR89KYerl4bf8h/UQLiKYC5D/Jv7AxB5Dvq+o3CGE= 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=YfDzvY4r; 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="YfDzvY4r" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780516350; 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=olsmC37uFpzY+y9wtmCt1x1gIahVEJ6Wl0D8b/LZIzs=; b=YfDzvY4rajXrsWmfkcATtsTscbbs1MfLqDJwSw/1sQZvGIeRCu+xtdbGOJqy4y1HkFXqaF r6obl+vE4dRVfXMBsx2T7kcNRz8ZvCY+OB/guh9F8rpUtOPRPpZu42gzLIQIgq5+pxBfIW DkbhuzLlJhUZ/ArAMMcOmzGbcRS7Nx4= 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-56-7TCLGpkIP7OuSlDk4Z0O4A-1; Wed, 03 Jun 2026 15:52:25 -0400 X-MC-Unique: 7TCLGpkIP7OuSlDk4Z0O4A-1 X-Mimecast-MFC-AGG-ID: 7TCLGpkIP7OuSlDk4Z0O4A_1780516342 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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B027718004D4; Wed, 3 Jun 2026 19:52:21 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.203]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2A2601800351; Wed, 3 Jun 2026 19:52:17 +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 v17 1/6] rust: drm: gem: shmem: Fix Default implementation for ObjectConfig Date: Wed, 3 Jun 2026 15:42:30 -0400 Message-ID: <20260603195210.693856-2-lyude@redhat.com> In-Reply-To: <20260603195210.693856-1-lyude@redhat.com> References: <20260603195210.693856-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" 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 --- V17: * Rebase * Fix format of commit message subject 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 34af402899a0e..084b798ce795b 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -42,7 +42,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, C: DeviceContext =3D Register= ed> { /// Whether to set the write-combine map flag. pub map_wc: bool, @@ -53,6 +52,16 @@ pub struct ObjectConfig<'a, T: DriverObject, C: DeviceCo= ntext =3D Registered> { pub parent_resv_obj: Option<&'a Object>, } =20 +impl<'a, T: DriverObject, C: DeviceContext> Default for ObjectConfig<'a, T= , C> { + #[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 09:48:38 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 34AC139B481 for ; Wed, 3 Jun 2026 19:52:34 +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=1780516355; cv=none; b=FV2J9xQt2fyVnzgQAzZu8LVb2HGoqOkkkCA+OX2WzFFX9aHODZJAocVa/SdcRqCAbVaVoOYcovXP2qVeFt8Z18rTgR51xVTPtVgSWMmZ9l0n5SJjhjreEVjBQPWpild4wuKhFckLUfWMMByBmJOgBbNvmWTsZ3vyeTJzOyuaPy0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780516355; c=relaxed/simple; bh=N9Zkr/AWzPMGNFm1Ln4LhJkt/EZGyo53j68P4QRjIxU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Vfb3O0TNcdjk6INw8/iMhNBp3KxCSPOg/2NtuJYI5EJd6VPQmZEuuOxOSVGqy2GjHjff77+SdyX050ZuVhtttBcaZLv9fTBsCxODdo961h0yKRr5bUsAB5EghNGLlpNjR9S4BSiCOhOCvB3Acj67RC2sIGpHelJ9GxyGQUtJwz8= 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=TZgT7zaO; 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="TZgT7zaO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780516353; 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=r7Z/C3WKzX9d11zFSyCLO1QOj5Cg/fxzu0wnbss0mqw=; b=TZgT7zaOY7cG2+R/+YteHlwh4daYqjrLpCTW/VahcaL/pilns+PURqBhw0afYwRGFVN2SA Qr6430CLnfWEu1N70/LXKPSjAmrCOl/K3E9+t0dsIVXpuxpLp3STxKpO1qXhE1P0QpXacT 68X49Bm2hdizt/wsZ6YbqdCzRFXxdx0= 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-357-SY1bvVhgOOuDGB9t24XwPA-1; Wed, 03 Jun 2026 15:52:28 -0400 X-MC-Unique: SY1bvVhgOOuDGB9t24XwPA-1 X-Mimecast-MFC-AGG-ID: SY1bvVhgOOuDGB9t24XwPA_1780516345 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7940C180034C; Wed, 3 Jun 2026 19:52:25 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.203]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E2278180049F; Wed, 3 Jun 2026 19:52:21 +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 v17 2/6] rust: drm: gem: shmem: Add DmaResvGuard helper Date: Wed, 3 Jun 2026 15:42:31 -0400 Message-ID: <20260603195210.693856-3-lyude@redhat.com> In-Reply-To: <20260603195210.693856-1-lyude@redhat.com> References: <20260603195210.693856-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" 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 --- V17: * Fix format of commit message title 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 084b798ce795b..650c34dd8b7a4 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -30,7 +30,10 @@ Deref, DerefMut, // }, - ptr::NonNull, // + ptr::{ + self, + NonNull, // + }, }; use gem::{ BaseObjectPrivate, @@ -244,3 +247,29 @@ impl driver::AllocI= mpl 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, C: DeviceContext =3D Registered>(= &'a Object); + +impl<'a, T: DriverObject, C: DeviceContext> DmaResvGuard<'a, T, C> { + #[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, C: DeviceContext> Drop for DmaResvGuard<'a, T, C= > { + #[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 09:48:38 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 B5FEC39E6F0 for ; Wed, 3 Jun 2026 19:52: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=1780516359; cv=none; b=JIJUf6UFyoqbPsU1pM1SYgVDMw9/dok9tNHsMo08zC9tJ7BMc0wioDkBa5S4a7SvGFMdCmsqPZfv9ig8x9q/BnZL/OJhXHJlr9CPtTBoX6ZTV3KLQRipwseYKeCmDJalKjvAP70vKTN6ng69L0XyIPAKFpHCFizs3QDYG3QWJvM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780516359; c=relaxed/simple; bh=HLDYZP0lehESbsRi+pGlDC6Lfm2TaTyerFCFRIDfqSk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sVre6hfiEv1qtJuO6AUfrcGuSy0+OJ+snB0j3SPH0rd+Q/6SLe8lGci5X6CGW4ofco9GBRMJzBLhcE9J7KpGcsx1FhRhNSHFQ+zoTSFTPczC4qppLFKakDHe21BzFdir8y533qDigWD7pO+6h/+Hd4y3qOycvu3Sw1NXWzVebqY= 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=QEISIfXk; 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="QEISIfXk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780516355; 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=3E5VGwkkVj6EfELSmGE+fCDhpjnsN/r1pe+Wo/sQdVo=; b=QEISIfXkwjtj+Iu129jLI2Ou0tVr3rEyDh6jKLhkPN9ENHXQJct9CdKyhKmQf0pYKvjQmi p7Jda1Rv7vTpA91QRcDWfoJBhBxIAUlHduiuTHRG/koCyhgaU42x8kTjaahbROjyIZMbm8 yyG6NBqgpl9qBZrpziU0oiGl6iFiM5Q= 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-540-W5SpPfZCMaCV51FpJKaIvw-1; Wed, 03 Jun 2026 15:52:32 -0400 X-MC-Unique: W5SpPfZCMaCV51FpJKaIvw-1 X-Mimecast-MFC-AGG-ID: W5SpPfZCMaCV51FpJKaIvw_1780516349 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 33B47180035C; Wed, 3 Jun 2026 19:52:29 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.203]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AA2F91800351; Wed, 3 Jun 2026 19:52:25 +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 v17 3/6] rust: drm: gem: shmem: Add vmap functions Date: Wed, 3 Jun 2026 15:42:32 -0400 Message-ID: <20260603195210.693856-4-lyude@redhat.com> In-Reply-To: <20260603195210.693856-1-lyude@redhat.com> References: <20260603195210.693856-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" 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 V17: * Rebase * Fix format of commit message title rust/kernel/drm/gem/shmem.rs | 312 ++++++++++++++++++++++++++++++++++- 1 file changed, 311 insertions(+), 1 deletion(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index 650c34dd8b7a4..1f05a5bc5fe66 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -20,12 +20,19 @@ Registered, // }, error::to_result, + io::{ + Io, + IoCapable, + IoKnownSize, // + }, prelude::*, sync::aref::ARef, types::Opaque, // }; use core::{ + ffi::c_void, marker::PhantomData, + mem::MaybeUninit, // ops::{ Deref, DerefMut, // @@ -36,6 +43,7 @@ }, }; use gem::{ + BaseObject, BaseObjectPrivate, DriverObject, IntoGEMObject, // @@ -197,6 +205,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 { @@ -257,7 +339,6 @@ impl driver::AllocIm= pl for Object { =20 impl<'a, T: DriverObject, C: DeviceContext> DmaResvGuard<'a, T, C> { #[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= ()) }; @@ -273,3 +354,232 @@ 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, + C: DeviceContext, + 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, + C: DeviceContext, + 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, C, const SIZE: usize =3D 0> =3D VMap, C, SIZE>; + +/// An alias type for an owned reference to a shmem-based GEM object's VMa= p. +pub type VMapOwned =3D VMap>, C, SIZE>; + +impl VMap +where + D: DriverObject, + C: DeviceContext, + 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, + C: DeviceContext, + 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, + C: DeviceContext, + 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, + C: DeviceContext, + 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::{ + self, + UnregisteredDevice, // + }, + 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, UnregisteredDevice<= KunitDriver>)> { + // 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 UnregisteredDevice::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, ObjectC= onfig::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, ObjectC= onfig::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 09:48:38 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 56FA939EF1C for ; Wed, 3 Jun 2026 19:52:40 +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=1780516361; cv=none; b=F/Pu4Hc0t7htkLY3k0oY+mhuCfGMhakJkDBTC9kR0DtchC3oqna1x+yQZqnjkqr7GzfUqj+Fni8uD+1LijeVvL8wFuBVMG0R2tkxQ8xON/dy8btYVsc5SjO7N5JC1UiRhTdQ91L04BJqBiQYnJiKqT1UX16LXHiYv+9GCbuMcCU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780516361; c=relaxed/simple; bh=NfValsT13B9XTlXeTicbkDGTa8+Fj2v0hJKR8oGpyBc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VRqeqpZwBBKalVIu0BLtJE0W3R5OBTOl185yOuCoL/2dySw0JMDp9kmwDOI7xlgfGKTNry+Po9Em7D+iXHrxm+wb60UfNyUJ8AR9mwdIUz/jjkCH3WJWISdlJgdkqL0/Qa0hkua4aQagknKAuLjElVN1poD8Uhpg6O9M+gEO/Ec= 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=VCg7ZMm3; 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="VCg7ZMm3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780516359; 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=VCg7ZMm3QARrmUgWhnJCN9oexahlbb7FnrjqjGwSfnCdVgjfbi7cKK7Rc3e3L3J7VDjTMm 6I704yp6tx1Ph2cqL0cihA9vYPkqGqgImvIbBIG3ViKbRCDrH16xdswkgkRd4xkCaoSFEa pp3jhtnnwDE/5emrpBPd65jCNkSxQkQ= 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-602-JWznmNClPk6VDIrlAHBT7w-1; Wed, 03 Jun 2026 15:52:36 -0400 X-MC-Unique: JWznmNClPk6VDIrlAHBT7w-1 X-Mimecast-MFC-AGG-ID: JWznmNClPk6VDIrlAHBT7w_1780516353 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B735B18004D8; Wed, 3 Jun 2026 19:52:32 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.203]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 64930180049F; Wed, 3 Jun 2026 19:52:29 +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 v17 4/6] rust: faux: Allow retrieving a bound Device Date: Wed, 3 Jun 2026 15:42:33 -0400 Message-ID: <20260603195210.693856-5-lyude@redhat.com> In-Reply-To: <20260603195210.693856-1-lyude@redhat.com> References: <20260603195210.693856-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" 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 09:48:38 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 545C93A1690 for ; Wed, 3 Jun 2026 19:52:41 +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=1780516363; cv=none; b=tErsVx/GtAS+eH6awObFl37XruwOFBL/1nM/nhu9kGcv7zj8a/tIZQZBn8iD4rbsQ2CryRqZR84MK0zfcFBb/Bg7DJpg7RuEnOvNBZJhaVcpkDH3xwjCBgdZr+L6m3P9o+Lg0YcoMLRY0tw4JeUgXgLBH6sAYqBTER9ETBh5ig8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780516363; c=relaxed/simple; bh=umwawEzRaVqGQ58SmcAjEXQ5zooLJBV9oJWhj8xBmeY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TQKnuhpTlghsyAoZQx1409oZSGvMiRUy72yxEC7svCikCQM+1funVAFhMXDjB9caTVgN2yncn3HdohrhXgr3Qv64P7KdPQXPfYZi3kwRTMzJiPJHdQU10GMDEh5k8J0Wa+Tv9YMcaaDJSyRGyr5axvyCImjqeJdarDQ+JJuXu5Q= 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=elVAscaC; 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="elVAscaC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780516360; 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=elVAscaCpuaDawbTzxohPGXtgEV5IDuoydqJun7ZZBGiAoNTvl4rtP5+AIrQvxRTA/8UcX EdD5j8Rq6qIHAv1wd8COYejVVBEGrR2VmuuVwMNeL0N1roc94KeeDcfy7hk+q/vaUvC/cf 5dlwSzBPQbGB9lGJHU7XybPyuI40i3k= 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-488-ThXfEKrpPjuaMtoOn4dIWA-1; Wed, 03 Jun 2026 15:52:39 -0400 X-MC-Unique: ThXfEKrpPjuaMtoOn4dIWA-1 X-Mimecast-MFC-AGG-ID: ThXfEKrpPjuaMtoOn4dIWA_1780516356 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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 146EF1800370; Wed, 3 Jun 2026 19:52:36 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.203]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E7CF61800591; Wed, 3 Jun 2026 19:52:32 +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 v17 5/6] rust: sync: Add SetOnce::reset() Date: Wed, 3 Jun 2026 15:42:34 -0400 Message-ID: <20260603195210.693856-6-lyude@redhat.com> In-Reply-To: <20260603195210.693856-1-lyude@redhat.com> References: <20260603195210.693856-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" 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 09:48:38 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 AC9933A1690 for ; Wed, 3 Jun 2026 19:52:46 +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=1780516368; cv=none; b=UV0QpHm0xMgyKmPe8V/Z9UDG6xv+Lq0mokVamA1TtZLoD6iVR50Fm+A6gqssJ2ADs5VpoSwZncB7PMAXNNhE5djXTy8YwgYO9Rq447C0AIu/wpligsx5i9J6hmTbVbXciSxosfNlQQdVExI3g7dlzNGj45wTCEtgK0TxAtAdYU4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780516368; c=relaxed/simple; bh=eHHfnZVqVtVvzrXbOkr4FCVAebNMUG4+hS9sPsRcVRE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s0ccHH2GqPrKqtXD9BG7ZHRvL62tMiEUHSpS6bjFNSQS6ALwoTzHJ73Quahls4o5Kzjnro5WmUJ2NlfygGljHqc2ILrTRtTZZor6Vv8D6Mnszwrp5aB/+ng4/U2wyAJ88mtAjLM3Kb80qQMKZ0g/gzJqS56UhL++KuYj9YqRUjg= 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=MO5oug1E; 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="MO5oug1E" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780516365; 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=GVITabHFaiXEpM9NcxPN2gSYPs96UTRYW/D9VFzedxk=; b=MO5oug1E+w3xgV/x6dDy9agLjpcl/rhGElwjWkKXT40IQ0N/k1onqP4nnRfM+vRG9N6ElV /wIZABWowMWxq8IwQaH0b6UdLrgjZSNdW8RRR7T45LyMcVUmGKWLr5caX+shO0MEXUK0tg mVayjVa0O/QeIao26YWK3HHIHo5WuxA= 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-601-DhnIDEKSOMKlT7XNGLSDcw-1; Wed, 03 Jun 2026 15:52:42 -0400 X-MC-Unique: DhnIDEKSOMKlT7XNGLSDcw-1 X-Mimecast-MFC-AGG-ID: DhnIDEKSOMKlT7XNGLSDcw_1780516359 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8855E1800586; Wed, 3 Jun 2026 19:52:39 +0000 (UTC) Received: from GoldenWind.lan (unknown [10.22.81.203]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 45F3B1800347; Wed, 3 Jun 2026 19:52:36 +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 v17 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Date: Wed, 3 Jun 2026 15:42:35 -0400 Message-ID: <20260603195210.693856-7-lyude@redhat.com> In-Reply-To: <20260603195210.693856-1-lyude@redhat.com> References: <20260603195210.693856-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" 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 V17: * Rebase * Fix missing safety comment in free_callback() (we forgot to justify why &mut is safe in `unsafe { &mut (*this).sgt_res }.reset()`) rust/kernel/drm/gem/shmem.rs | 166 +++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 9 deletions(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index 1f05a5bc5fe66..dff90771eb34a 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -11,6 +11,11 @@ =20 use crate::{ container_of, + device::{ + self, + Bound, // + }, + devres::*, drm::{ driver, gem, @@ -19,14 +24,23 @@ DeviceContext, Registered, // }, - 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::{ @@ -87,6 +101,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, _ctx: PhantomData, @@ -145,6 +164,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), _ctx: PhantomData::, }), @@ -189,18 +210,25 @@ 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. + // - We are in free_callback, guaranteeing we have exclusive acces= s to `this`. + 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) }; @@ -279,6 +307,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 { @@ -474,6 +541,63 @@ impl IoKnownSize for VMap<= D, R, C, SIZE> #[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::*; @@ -582,4 +706,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, ObjectC= onfig::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