From: Philipp Stanner <phasta@kernel.org>
To: "Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Philipp Stanner" <phasta@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Boris Brezillon" <boris.brezillon@collabora.com>,
John.harrison@igalia.com, da.gomez@kernel.org
Cc: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org,
dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org
Subject: [RFC PATCH v5 5/6] rust: DmaFence: Replace call_rcu() with synchronize_rcu()
Date: Fri, 9 Oct 2026 21:11:23 +0200 [thread overview]
Message-ID: <20261009191124.1022902-7-phasta@kernel.org> (raw)
In-Reply-To: <20261009191124.1022902-2-phasta@kernel.org>
The C dma_fence contract demands that a fence's data disappears no
earlier than 1 RCU grace period after the DriverFence was signaled.
So far, we achieved this with dropping the DriverFence's data in a
deferred manner with a manual, raw binding call to call_rcu().
However, this call_rcu() does not solve one problem: It is conceivable
that some driver data must not drop in atomic context; but call_rcu()'s
payload *can* be executed in atomic context.
Moreover, the current developments in drm::JobQueue, where a DriverFence
is always coupled 1:1 with a Job, allows for dropping job and fence
through a work item.
The undesirable blocking behavior of synchronize_rcu() would, thus, not
be annoying any thread anymore. The direct users of DmaFence could
achieve the same by dropping their DriverFences through work items.
The only conceivable other solution, queue_rcu_work(), would, for many
users, schedule a work_item from another work_item, which seems
undesirable.
Additionally, using the existing synchronize_rcu() abstraction has the
advantage of us getting rid of a raw bindings call.
Replace DriverFence::drop()'s call_rcu() with synchronize_rcu().
Signed-off-by: Philipp Stanner <phasta@kernel.org>
---
rust/kernel/dma_buf/dma_fence.rs | 71 +++++++-------------------------
1 file changed, 14 insertions(+), 57 deletions(-)
diff --git a/rust/kernel/dma_buf/dma_fence.rs b/rust/kernel/dma_buf/dma_fence.rs
index 4e9b4a6a9471..cefcde80bf09 100644
--- a/rust/kernel/dma_buf/dma_fence.rs
+++ b/rust/kernel/dma_buf/dma_fence.rs
@@ -42,7 +42,8 @@
Atomic,
Relaxed, //
},
- rcu::rcu_barrier, //
+ rcu::rcu_barrier,
+ rcu::synchronize_rcu, //
}, //
};
@@ -150,7 +151,6 @@ pub fn new_fence_allocation(
data: T::FenceDataType,
) -> Result<DriverFenceAllocation<'_, T>> {
let fence_data = DriverFenceData {
- rcu_head: Default::default(),
// `inner` remains uninitialized until a `DriverFence` takes over.
inner: Fence {
inner: Opaque::uninit(),
@@ -640,8 +640,6 @@ struct DriverFenceData<'a, T: Send + Sync + FenceContextOps> {
// necessary so that the C backend can free the allocation (coming from our
// Rust code) with kfree_rcu().
inner: Fence,
- /// Callback head for dropping this in a deferred manner through RCU.
- rcu_head: bindings::callback_head,
/// Reference to access the FenceContext.
fctx: &'a FenceContext<T>,
/// The API user's data. It is essential that the data only performs
@@ -1022,59 +1020,18 @@ fn drop(&mut self) {
return;
}
- // SAFETY: Valid because `self` is valid.
- let rcu_head_ptr = unsafe { &raw mut (*self.data.as_ptr()).rcu_head };
+ // Make sure none of the fence backend_ops can access data anymore.
+ //
+ // TODO:
+ // This would not be necessary if the C dma_fence backend were using a
+ // spinlock to properly synchronize its signaled state. Fix it in C and
+ // then remove synchronize_rcu().
+ synchronize_rcu();
- // SAFETY: `call_rcu()` is always safe to be called. `rcu_head_ptr` was
- // created validly above. The module must perform a `synchronize_rcu()`
- // or `rcu_barrier()` call to guard against module unload.
- unsafe { bindings::call_rcu(rcu_head_ptr, Some(drop_driver_fence_data::<T>)) };
+ // SAFETY: Valid because `self` is valid.
+ unsafe { drop_in_place(&raw mut self.data) };
+
+ // SAFETY: The `synchronize_rcu()` above ensures all accessors are gone.
+ unsafe { bindings::dma_fence_put(self.as_raw()) };
}
}
-
-// TODO:
-// The entire call_rcu() mechanism in the drop above and the code below would be
-// unnecessary if C's dma_fence_signal() could be reworked in a way that after it
-// ran, the caller knows that no fence_ops callbacks can be running anymore.
-// In other words, if the dma_fence backend would use its spinlock for full
-// synchronization.
-//
-// Then we could move the drop_in_place() and dma_fence_put() upwards into the
-// drop() implementation and call it a day.
-
-/// Finally really drop this `DriverFence<T>`
-///
-/// # Safety
-///
-/// `head` references the `rcu_head` field of an `DriverFenceData<T>`. All
-/// accessors to that `DriverFenceData<T>` must be gone by now. This must be
-/// ensured by signalling the associated `DriverFence<T>` and then waiting
-/// for a grace period until calling this function here.
-unsafe extern "C" fn drop_driver_fence_data<T: Send + Sync + FenceContextOps>(
- head: *mut bindings::callback_head,
-) {
- // SAFETY: Caller provides a pointer to the `rcu_head` field of a `DriverFenceData<C>`.
- let fence_data = unsafe { container_of!(head, DriverFenceData<'_, T>, rcu_head) };
-
- // SAFETY: `fence_data` was created validly above. All the fence's data will
- // only drop below, but the raw pointer to the raw C `dma_fence` remains
- // valid because the reference count is only decremented at the end of the
- // function.
- let fence = unsafe { (*fence_data).inner.inner.get() };
-
- // SAFETY: `fence_data` was created validly above. The user has already
- // dropped the only conventional accessor to the user data, the `DriverFence`,
- // one grace period ago. All accessors are gone now.
- unsafe { drop_in_place(&raw mut (*fence_data).data) };
-
- // The inner `Fence` explicitly does not get dropped because there may be
- // many more users / consumers, each holding their own reference.
-
- // SAFETY: Once a `DriverFence` is initialized, the inner `fence` is valid
- // and initialized. It is valid until the refcount drops to 0, which can
- // earliest happen once we drop the `DriverFence`'s reference here.
- unsafe { bindings::dma_fence_put(fence) };
-
- // The actual memory the data associated with a `DriverFence` lives in
- // gets freed by the C dma_fence backend once the fence's refcount reaches 0.
-}
--
2.55.0
next prev parent reply other threads:[~2026-10-09 19:14 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 19:11 [RFC PATCH v5 0/6] rust: Add drm::JobQueue Philipp Stanner
2026-10-09 19:11 ` [RFC PATCH v5 1/6] rust: DmaFence: remove static lifetime Philipp Stanner
2026-10-09 19:24 ` sashiko-bot
2026-10-09 19:11 ` [RFC PATCH v5 2/6] rust: DmaFence: Implement Deref for FenceContext Philipp Stanner
2026-10-09 19:19 ` sashiko-bot
2026-10-09 19:11 ` [RFC PATCH v5 3/6] rust: DmaFence: Don't drop on signal Philipp Stanner
2026-10-09 19:26 ` sashiko-bot
2026-10-09 19:11 ` [RFC PATCH v5 4/6] rust: DmaFence: [RFC] Add Signaler Philipp Stanner
2026-10-09 19:23 ` sashiko-bot
2026-10-09 19:11 ` Philipp Stanner [this message]
2026-10-09 19:25 ` [RFC PATCH v5 5/6] rust: DmaFence: Replace call_rcu() with synchronize_rcu() sashiko-bot
2026-10-09 19:11 ` [RFC PATCH v5 6/6] rust: drm: Add JobQueue Philipp Stanner
2026-10-09 19:24 ` sashiko-bot
2026-10-11 0:22 ` [RFC PATCH v5 0/6] rust: Add drm::JobQueue Daniel Almeida
2026-10-12 8:17 ` Philipp Stanner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261009191124.1022902-7-phasta@kernel.org \
--to=phasta@kernel.org \
--cc=John.harrison@igalia.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=boris.brezillon@collabora.com \
--cc=christian.koenig@amd.com \
--cc=da.gomez@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=sumit.semwal@linaro.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.