linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] rust: types: Add read_once and write_once
@ 2023-10-25 19:53 Boqun Feng
  2023-10-25 21:51 ` Benno Lossin
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Boqun Feng @ 2023-10-25 19:53 UTC (permalink / raw)
  To: rust-for-linux, linux-kernel, linux-arch, llvm
  Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Alan Stern, Andrea Parri, Will Deacon, Peter Zijlstra,
	Nicholas Piggin, David Howells, Jade Alglave, Luc Maranget,
	Paul E. McKenney, Akira Yokosawa, Daniel Lustig, Joel Fernandes,
	Nathan Chancellor, Nick Desaulniers, Tom Rix, Alexander Viro,
	Christian Brauner, kent.overstreet, Greg Kroah-Hartman, elver,
	Matthew Wilcox, Dave Chinner, linux-fsdevel

In theory, `read_volatile` and `write_volatile` in Rust can have UB in
case of the data races [1]. However, kernel uses volatiles to implement
READ_ONCE() and WRITE_ONCE(), and expects races on these marked accesses
don't cause UB. And they are proven to have a lot of usages in kernel.

To close this gap, `read_once` and `write_once` are introduced, they
have the same semantics as `READ_ONCE` and `WRITE_ONCE` especially
regarding data races under the assumption that `read_volatile` and
`write_volatile` have the same behavior as a volatile pointer in C from
a compiler point of view.

Longer term solution is to work with Rust language side for a better way
to implement `read_once` and `write_once`. But so far, it should be good
enough.

Suggested-by: Alice Ryhl <aliceryhl@google.com>
Link: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html#safety [1]
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
---

Notice I also make the primitives only work on T: Copy, since I don't
think Rust side and C side will use a !Copy type to communicate, but we
can always remove that constrait later.


 rust/kernel/prelude.rs |  2 ++
 rust/kernel/types.rs   | 43 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index ae21600970b3..351ad182bc63 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -38,3 +38,5 @@
 pub use super::init::{InPlaceInit, Init, PinInit};
 
 pub use super::current;
+
+pub use super::types::{read_once, write_once};
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index d849e1979ac7..b0872f751f97 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -432,3 +432,46 @@ pub enum Either<L, R> {
     /// Constructs an instance of [`Either`] containing a value of type `R`.
     Right(R),
 }
+
+/// (Concurrent) Primitives to interact with C side, which are considered as marked access:
+///
+/// tools/memory-memory/Documentation/access-marking.txt
+
+/// The counter part of C `READ_ONCE()`.
+///
+/// The semantics is exactly the same as `READ_ONCE()`, especially when used for intentional data
+/// races.
+///
+/// # Safety
+///
+/// * `src` must be valid for reads.
+/// * `src` must be properly aligned.
+/// * `src` must point to a properly initialized value of value `T`.
+#[inline(always)]
+pub unsafe fn read_once<T: Copy>(src: *const T) -> T {
+    // SAFETY: the read is valid because of the function's safety requirement, plus the assumption
+    // here is that 1) a volatile pointer dereference in C and 2) a `read_volatile` in Rust have the
+    // same semantics, so this function should have the same behavior as `READ_ONCE()` regarding
+    // data races.
+    unsafe { src.read_volatile() }
+}
+
+/// The counter part of C `WRITE_ONCE()`.
+///
+/// The semantics is exactly the same as `WRITE_ONCE()`, especially when used for intentional data
+/// races.
+///
+/// # Safety
+///
+/// * `dst` must be valid for writes.
+/// * `dst` must be properly aligned.
+#[inline(always)]
+pub unsafe fn write_once<T: Copy>(dst: *mut T, value: T) {
+    // SAFETY: the write is valid because of the function's safety requirement, plus the assumption
+    // here is that 1) a write to a volatile pointer dereference in C and 2) a `write_volatile` in
+    // Rust have the same semantics, so this function should have the same behavior as
+    // `WRITE_ONCE()` regarding data races.
+    unsafe {
+        core::ptr::write_volatile(dst, value);
+    }
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2023-10-30 16:36 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-25 19:53 [RFC] rust: types: Add read_once and write_once Boqun Feng
2023-10-25 21:51 ` Benno Lossin
2023-10-25 23:02   ` Boqun Feng
2023-10-26  3:31     ` Boqun Feng
2023-10-26  7:30     ` Benno Lossin
2023-10-30 13:58     ` Alice Ryhl
2023-10-30 16:36       ` Benno Lossin
2023-10-26  8:13 ` Peter Zijlstra
2023-10-26 10:36   ` Gary Guo
2023-10-26 11:16     ` Peter Zijlstra
2023-10-26 14:21       ` Boqun Feng
2023-10-26 14:23         ` Boqun Feng
2023-10-26 17:08       ` Paul E. McKenney
2023-10-26 11:16 ` Marco Elver

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).