From: Markus Probst <markus.probst@posteo.de>
To: "Ayush Singh" <ayush@beagleboard.org>,
"Johan Hovold" <johan@kernel.org>,
"Alex Elder" <elder@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.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>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"Eric Biggers" <ebiggers@kernel.org>,
"Ard Biesheuvel" <ardb@kernel.org>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Vlastimil Babka" <vbabka@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
"Uladzislau Rezki" <urezki@gmail.com>
Cc: greybus-dev@lists.linaro.org, linux-serial@vger.kernel.org,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
Markus Probst <markus.probst@posteo.de>
Subject: [PATCH] rust: serdev: Synchronize receive callback before calling unbind
Date: Thu, 03 Sep 2026 22:03:39 +0000 [thread overview]
Message-ID: <20260904-rust_serdev_ref_mut-v1-1-245db7eb09af@posteo.de> (raw)
The receive callback and unbind callback now have exclusive access to
the drivers private data. Provide mutable references in callbacks to
avoid the need for locks in the private data. Remove the Sync
requirement.
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
This patch avoids the need for a SpinLock in the patch series
https://lore.kernel.org/rust-for-linux/20260827-gb-uart-transport-v2-7-a03bb1f5fbd1@beagleboard.org/
.
---
rust/kernel/serdev.rs | 51 ++++++++++++++++++++++----------------
samples/rust/rust_driver_serdev.rs | 2 +-
2 files changed, 31 insertions(+), 22 deletions(-)
diff --git a/rust/kernel/serdev.rs b/rust/kernel/serdev.rs
index 17ca504b7f8d..44f029ed93fd 100644
--- a/rust/kernel/serdev.rs
+++ b/rust/kernel/serdev.rs
@@ -106,7 +106,7 @@ pub struct PrivateData<'bound, T: Driver> {
/// Whether `receive_buf_callback` is allowed to call `Driver::receive`.
///
/// If locked, the receive_buf_callback will be blocked on data reception.
- /// This is the case while the driver is being probed or while [`PrivateData`] is being dropped.
+ /// This is the case while the driver is being probed or removed.
/// This is necessary, because we need to open the serdev device before the driver has been
/// probed in order to allow it to be configured, which allows `receive_buf_callback` to be
/// called. Thus we need to block data until probe completes and the driver data becomes
@@ -127,16 +127,6 @@ pub struct PrivateData<'bound, T: Driver> {
#[pinned_drop]
impl<T: Driver> PinnedDrop for PrivateData<'_, T> {
fn drop(self: Pin<&mut Self>) {
- let mut active = self.active.lock();
- if *active {
- // SAFETY:
- // - We have exclusive access to `self.driver`.
- // - `self.driver` is guaranteed to be initialized.
- unsafe { (*self.driver.get()).assume_init_drop() };
- *active = false;
- }
- drop(active);
-
// SAFETY: We have exclusive access to `self.open`.
if unsafe { *self.open.get() } {
// SAFETY: `self.sdev.as_raw()` is guaranteed to be a pointer to a valid
@@ -176,7 +166,20 @@ extern "C" fn probe_callback(sdev: *mut bindings::serdev_device) -> kernel::ffi:
let private_data = unsafe { sdev.as_ref().drvdata_borrow::<PrivateData<'_, T>>() };
let private_data = ScopeGuard::new_with_data(private_data, |_| {
// SAFETY: We just set drvdata to `PrivateData<'_, T>`.
- drop(unsafe { sdev.as_ref().drvdata_obtain::<PrivateData<'_, T>>() });
+ let private_data = unsafe {
+ sdev.as_ref()
+ .drvdata_obtain::<PrivateData<'_, T>>()
+ .unwrap_unchecked()
+ };
+
+ let mut active = private_data.active.lock();
+ if *active {
+ // SAFETY:
+ // - We have exclusive access to `private_data.driver`.
+ // - `private_data.driver` is guaranteed to be initialized.
+ unsafe { (*private_data.driver.get()).assume_init_drop() };
+ *active = false;
+ }
});
let mut active = private_data.active.lock();
@@ -222,15 +225,21 @@ extern "C" fn remove_callback(sdev: *mut bindings::serdev_device) {
// and stored a `Pin<KBox<PrivateData<'_, T>>>`.
let private_data = unsafe { sdev.as_ref().drvdata_borrow::<PrivateData<'_, T>>() };
- // SAFETY: No one has exclusive access to `private_data.driver`.
- let data = unsafe { &*private_data.driver.get() };
+ let mut active = private_data.active.lock();
+
+ // SAFETY: We have exclusive access to `private_data.driver`.
+ let data = unsafe { &mut *private_data.driver.get() };
// SAFETY:
// - `private_data.driver` is pinned.
// - `remove_callback` is only ever called after a successful call to `probe_callback`,
// hence it's guaranteed that `private_data.driver` was initialized.
- let data_pinned = unsafe { Pin::new_unchecked(data.assume_init_ref()) };
+ let data_pinned = unsafe { Pin::new_unchecked(data.assume_init_mut()) };
T::unbind(sdev, data_pinned);
+
+ // SAFETY: We already established that `data` is guaranteed to be initialized.
+ unsafe { data.assume_init_drop() };
+ *active = false;
}
extern "C" fn receive_buf_callback(
@@ -254,13 +263,13 @@ extern "C" fn receive_buf_callback(
return length;
}
- // SAFETY: No one has exclusive access to `private_data.driver`.
- let data = unsafe { &*private_data.driver.get() };
+ // SAFETY: We have exclusive access to `private_data.driver`.
+ let data = unsafe { &mut *private_data.driver.get() };
// SAFETY:
// - `private_data.driver` is pinned.
// - `receive_buf_callback` is only ever called after a successful call to `probe_callback`,
// hence it's guaranteed that `private_data.driver` was initialized.
- let data_pinned = unsafe { Pin::new_unchecked(data.assume_init_ref()) };
+ let data_pinned = unsafe { Pin::new_unchecked(data.assume_init_mut()) };
// SAFETY: `buf` is guaranteed to be non-null and has the size of `length`.
let buf = unsafe { core::slice::from_raw_parts(buf, length) };
@@ -365,7 +374,7 @@ pub trait Driver {
type IdInfo: 'static;
/// The type of the driver's bus device private data.
- type Data<'bound>: Send + Sync + 'bound;
+ type Data<'bound>: Send + 'bound;
/// The table of OF device ids supported by the driver.
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
@@ -391,7 +400,7 @@ fn probe<'bound>(
/// `&Device<Core>` or `&Device<Bound>` reference. For instance.
///
/// Otherwise, release operations for driver resources should be performed in `Drop`.
- fn unbind<'bound>(sdev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) {
+ fn unbind<'bound>(sdev: &'bound Device<device::Core<'_>>, this: Pin<&mut Self::Data<'bound>>) {
let _ = (sdev, this);
}
@@ -402,7 +411,7 @@ fn unbind<'bound>(sdev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<
/// Returns the number of bytes accepted.
fn receive<'bound>(
sdev: &'bound Device<device::Bound>,
- this: Pin<&Self::Data<'bound>>,
+ this: Pin<&mut Self::Data<'bound>>,
data: &[u8],
) -> usize {
let _ = (sdev, this, data);
diff --git a/samples/rust/rust_driver_serdev.rs b/samples/rust/rust_driver_serdev.rs
index 51b4898cd855..d00d547234c8 100644
--- a/samples/rust/rust_driver_serdev.rs
+++ b/samples/rust/rust_driver_serdev.rs
@@ -63,7 +63,7 @@ fn probe<'bound>(
fn receive<'bound>(
sdev: &'bound serdev::Device<Bound>,
- _this: Pin<&Self>,
+ _this: Pin<&mut Self>,
data: &[u8],
) -> usize {
sdev.write(data).unwrap_or_default() as usize
---
base-commit: e5e04726cdd043e309677071ab1b65a4b18f422b
change-id: 20260903-rust_serdev_ref_mut-4d2285776ae1
next reply other threads:[~2026-09-03 22:03 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-03 22:03 Markus Probst [this message]
2026-09-03 22:34 ` Markus Probst
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=20260904-rust_serdev_ref_mut-v1-1-245db7eb09af@posteo.de \
--to=markus.probst@posteo.de \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=ardb@kernel.org \
--cc=ayush@beagleboard.org \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=ebiggers@kernel.org \
--cc=elder@kernel.org \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=greybus-dev@lists.linaro.org \
--cc=johan@kernel.org \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=urezki@gmail.com \
--cc=vbabka@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®