From 8b3d955f72f999ccce26aabdeb09939964d05a61 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Thu, 29 May 2025 10:10:23 +0200 Subject: [PATCH 01/14] rust: pin-init: improve safety documentation for `impl [Pin]Init for T` The inner SAFETY comments were missing since commit 5cfe7bef6751 ("rust: enable `clippy::undocumented_unsafe_blocks` lint"). Also rework the implementation of `__pinned_init` to better justify the SAFETY comment. Link: https://github.com/Rust-for-Linux/pin-init/pull/62/commits/df925b2e27d499b7144df7e62b01acb00d4b94b8 Reviewed-by: Boqun Feng Link: https://lore.kernel.org/all/20250529081027.297648-1-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 9ab34036e6bc..d1c3ca5cfff4 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1390,20 +1390,22 @@ where unsafe { pin_init_from_closure(init) } } -// SAFETY: Every type can be initialized by-value. +// SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. unsafe impl Init for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: TODO. + // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) } } -// SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. +// SAFETY: the `__pinned_init` function always returns `Ok(())` and initializes every field of +// `slot`. Additionally, all pinning invariants of `T` are upheld. unsafe impl PinInit for T { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: TODO. - unsafe { self.__init(slot) } + // SAFETY: `slot` is valid for writes by the safety requirements of this function. + unsafe { slot.write(self) }; + Ok(()) } } From e832374ccadf4d1ce7bd40a85b9320bd7fbb3628 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Thu, 29 May 2025 10:10:24 +0200 Subject: [PATCH 02/14] rust: pin-init: change blanket impls for `[Pin]Init` and add one for `Result` Remove the error from the blanket implementations `impl Init for T` (and also for `PinInit`). Add implementations for `Result`. This allows one to easily construct (un)conditional failing initializers. It also improves the compatibility with APIs that do not use pin-init, because users can supply a `Result` to a function taking an `impl PinInit`. Suggested-by: Alice Ryhl Link: https://github.com/Rust-for-Linux/pin-init/pull/62/commits/58612514b256c6f4a4a0718be25298410e67387a [ Also fix a compile error in block. - Benno ] Reviewed-by: Boqun Feng Link: https://lore.kernel.org/all/20250529081027.297648-2-lossin@kernel.org [ Add title prefix `rust: pin-init`. - Benno ] Signed-off-by: Benno Lossin --- rust/kernel/block/mq/tag_set.rs | 12 +++++++----- rust/pin-init/src/lib.rs | 30 ++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index bcf4214ad149..c3cf56d52bee 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -9,7 +9,7 @@ use core::pin::Pin; use crate::{ bindings, block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations}, - error, + error::{self, Result}, prelude::try_pin_init, types::Opaque, }; @@ -41,7 +41,7 @@ impl TagSet { // SAFETY: `blk_mq_tag_set` only contains integers and pointers, which // all are allowed to be 0. let tag_set: bindings::blk_mq_tag_set = unsafe { core::mem::zeroed() }; - let tag_set = core::mem::size_of::() + let tag_set: Result<_> = core::mem::size_of::() .try_into() .map(|cmd_size| { bindings::blk_mq_tag_set { @@ -56,12 +56,14 @@ impl TagSet { nr_maps: num_maps, ..tag_set } - }); + }) + .map(Opaque::new) + .map_err(|e| e.into()); try_pin_init!(TagSet { - inner <- PinInit::<_, error::Error>::pin_chain(Opaque::new(tag_set?), |tag_set| { + inner <- tag_set.pin_chain(|tag_set| { // SAFETY: we do not move out of `tag_set`. - let tag_set = unsafe { Pin::get_unchecked_mut(tag_set) }; + let tag_set: &mut Opaque<_> = unsafe { Pin::get_unchecked_mut(tag_set) }; // SAFETY: `tag_set` is a reference to an initialized `blk_mq_tag_set`. error::to_result( unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())}) }), diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index d1c3ca5cfff4..f4e034497cdd 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1391,8 +1391,8 @@ where } // SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. -unsafe impl Init for T { - unsafe fn __init(self, slot: *mut T) -> Result<(), E> { +unsafe impl Init for T { + unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) @@ -1401,14 +1401,36 @@ unsafe impl Init for T { // SAFETY: the `__pinned_init` function always returns `Ok(())` and initializes every field of // `slot`. Additionally, all pinning invariants of `T` are upheld. -unsafe impl PinInit for T { - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { +unsafe impl PinInit for T { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) } } +// SAFETY: when the `__init` function returns with +// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. +// - `Err(err)`, slot was not written to. +unsafe impl Init for Result { + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `slot` is valid for writes by the safety requirements of this function. + unsafe { slot.write(self?) }; + Ok(()) + } +} + +// SAFETY: when the `__pinned_init` function returns with +// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. +// - `Err(err)`, slot was not written to. +unsafe impl PinInit for Result { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `slot` is valid for writes by the safety requirements of this function. + unsafe { slot.write(self?) }; + Ok(()) + } +} + /// Smart pointer containing uninitialized memory and that can write a value. pub trait InPlaceWrite { /// The type `Self` turns into when the contents are initialized. From 58cebd68882edd407c7f65ebb4a42034bc1ffc6d Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 14:54:11 +0200 Subject: [PATCH 03/14] rust: pin-init: examples, tests: add conditional compilation in order to compile under any feature combination In the CI, all examples & tests should be run under all feature combinations. Currently several examples & tests use `std` without conditionally enabling it. Thus make them all compile under any feature combination by conditionally disabling the code that uses e.g. `std`. Link: https://github.com/Rust-for-Linux/pin-init/pull/50/commits/fdfb70efddbc711b4543c850ee38a2f5a8d17cb6 Link: https://lore.kernel.org/all/20250523125424.192843-2-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/examples/big_struct_in_place.rs | 26 ++--- rust/pin-init/examples/linked_list.rs | 10 +- rust/pin-init/examples/mutex.rs | 97 +++++++++++-------- rust/pin-init/examples/pthread_mutex.rs | 3 + rust/pin-init/examples/static_init.rs | 75 +++++++------- 5 files changed, 121 insertions(+), 90 deletions(-) diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs index 30d44a334ffd..b0ee793a0a0c 100644 --- a/rust/pin-init/examples/big_struct_in_place.rs +++ b/rust/pin-init/examples/big_struct_in_place.rs @@ -4,6 +4,7 @@ use pin_init::*; // Struct with size over 1GiB #[derive(Debug)] +#[allow(dead_code)] pub struct BigStruct { buf: [u8; 1024 * 1024 * 1024], a: u64, @@ -25,15 +26,18 @@ impl ManagedBuf { } fn main() { - // we want to initialize the struct in-place, otherwise we would get a stackoverflow - let buf: Box = Box::init(init!(BigStruct { - buf <- zeroed(), - a: 7, - b: 186, - c: 7789, - d: 34, - managed_buf <- ManagedBuf::new(), - })) - .unwrap(); - println!("{}", core::mem::size_of_val(&*buf)); + #[cfg(any(feature = "std", feature = "alloc"))] + { + // we want to initialize the struct in-place, otherwise we would get a stackoverflow + let buf: Box = Box::init(init!(BigStruct { + buf <- zeroed(), + a: 7, + b: 186, + c: 7789, + d: 34, + managed_buf <- ManagedBuf::new(), + })) + .unwrap(); + println!("{}", core::mem::size_of_val(&*buf)); + } } diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs index 0bbc7b8d83a1..f9e117c7dfe0 100644 --- a/rust/pin-init/examples/linked_list.rs +++ b/rust/pin-init/examples/linked_list.rs @@ -14,8 +14,9 @@ use core::{ use pin_init::*; -#[expect(unused_attributes)] +#[allow(unused_attributes)] mod error; +#[allow(unused_imports)] use error::Error; #[pin_data(PinnedDrop)] @@ -39,6 +40,7 @@ impl ListHead { } #[inline] + #[allow(dead_code)] pub fn insert_next(list: &ListHead) -> impl PinInit + '_ { try_pin_init!(&this in Self { prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}), @@ -112,6 +114,7 @@ impl Link { } #[inline] + #[allow(dead_code)] fn prev(&self) -> &Link { unsafe { &(*self.0.get().as_ptr()).prev } } @@ -137,8 +140,13 @@ impl Link { } } +#[allow(dead_code)] +#[cfg(not(any(feature = "std", feature = "alloc")))] +fn main() {} + #[allow(dead_code)] #[cfg_attr(test, test)] +#[cfg(any(feature = "std", feature = "alloc"))] fn main() -> Result<(), Error> { let a = Box::pin_init(ListHead::new())?; stack_pin_init!(let b = ListHead::insert_next(&a)); diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs index 3e3630780c96..9f295226cd64 100644 --- a/rust/pin-init/examples/mutex.rs +++ b/rust/pin-init/examples/mutex.rs @@ -12,14 +12,15 @@ use core::{ pin::Pin, sync::atomic::{AtomicBool, Ordering}, }; +#[cfg(feature = "std")] use std::{ sync::Arc, - thread::{self, park, sleep, Builder, Thread}, + thread::{self, sleep, Builder, Thread}, time::Duration, }; use pin_init::*; -#[expect(unused_attributes)] +#[allow(unused_attributes)] #[path = "./linked_list.rs"] pub mod linked_list; use linked_list::*; @@ -36,6 +37,7 @@ impl SpinLock { .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) .is_err() { + #[cfg(feature = "std")] while self.inner.load(Ordering::Relaxed) { thread::yield_now(); } @@ -94,7 +96,8 @@ impl CMutex { // println!("wait list length: {}", self.wait_list.size()); while self.locked.get() { drop(sguard); - park(); + #[cfg(feature = "std")] + thread::park(); sguard = self.spin_lock.acquire(); } // This does have an effect, as the ListHead inside wait_entry implements Drop! @@ -131,8 +134,11 @@ impl Drop for CMutexGuard<'_, T> { let sguard = self.mtx.spin_lock.acquire(); self.mtx.locked.set(false); if let Some(list_field) = self.mtx.wait_list.next() { - let wait_entry = list_field.as_ptr().cast::(); - unsafe { (*wait_entry).thread.unpark() }; + let _wait_entry = list_field.as_ptr().cast::(); + #[cfg(feature = "std")] + unsafe { + (*_wait_entry).thread.unpark() + }; } drop(sguard); } @@ -159,52 +165,61 @@ impl DerefMut for CMutexGuard<'_, T> { struct WaitEntry { #[pin] wait_list: ListHead, + #[cfg(feature = "std")] thread: Thread, } impl WaitEntry { #[inline] fn insert_new(list: &ListHead) -> impl PinInit + '_ { - pin_init!(Self { - thread: thread::current(), - wait_list <- ListHead::insert_prev(list), - }) + #[cfg(feature = "std")] + { + pin_init!(Self { + thread: thread::current(), + wait_list <- ListHead::insert_prev(list), + }) + } + #[cfg(not(feature = "std"))] + { + pin_init!(Self { + wait_list <- ListHead::insert_prev(list), + }) + } } } -#[cfg(not(any(feature = "std", feature = "alloc")))] -fn main() {} - -#[allow(dead_code)] #[cfg_attr(test, test)] -#[cfg(any(feature = "std", feature = "alloc"))] +#[allow(dead_code)] fn main() { - let mtx: Pin>> = Arc::pin_init(CMutex::new(0)).unwrap(); - let mut handles = vec![]; - let thread_count = 20; - let workload = if cfg!(miri) { 100 } else { 1_000 }; - for i in 0..thread_count { - let mtx = mtx.clone(); - handles.push( - Builder::new() - .name(format!("worker #{i}")) - .spawn(move || { - for _ in 0..workload { - *mtx.lock() += 1; - } - println!("{i} halfway"); - sleep(Duration::from_millis((i as u64) * 10)); - for _ in 0..workload { - *mtx.lock() += 1; - } - println!("{i} finished"); - }) - .expect("should not fail"), - ); + #[cfg(feature = "std")] + { + let mtx: Pin>> = Arc::pin_init(CMutex::new(0)).unwrap(); + let mut handles = vec![]; + let thread_count = 20; + let workload = if cfg!(miri) { 100 } else { 1_000 }; + for i in 0..thread_count { + let mtx = mtx.clone(); + handles.push( + Builder::new() + .name(format!("worker #{i}")) + .spawn(move || { + for _ in 0..workload { + *mtx.lock() += 1; + } + println!("{i} halfway"); + sleep(Duration::from_millis((i as u64) * 10)); + for _ in 0..workload { + *mtx.lock() += 1; + } + println!("{i} finished"); + }) + .expect("should not fail"), + ); + } + for h in handles { + h.join().expect("thread panicked"); + } + println!("{:?}", &*mtx.lock()); + assert_eq!(*mtx.lock(), workload * thread_count * 2); } - for h in handles { - h.join().expect("thread panicked"); - } - println!("{:?}", &*mtx.lock()); - assert_eq!(*mtx.lock(), workload * thread_count * 2); } diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs index 5acc5108b954..c709dabba7eb 100644 --- a/rust/pin-init/examples/pthread_mutex.rs +++ b/rust/pin-init/examples/pthread_mutex.rs @@ -44,6 +44,7 @@ mod pthread_mtx { pub enum Error { #[allow(dead_code)] IO(std::io::Error), + #[allow(dead_code)] Alloc, } @@ -61,6 +62,7 @@ mod pthread_mtx { } impl PThreadMutex { + #[allow(dead_code)] pub fn new(data: T) -> impl PinInit { fn init_raw() -> impl PinInit, Error> { let init = |slot: *mut UnsafeCell| { @@ -103,6 +105,7 @@ mod pthread_mtx { }? Error) } + #[allow(dead_code)] pub fn lock(&self) -> PThreadMutexGuard<'_, T> { // SAFETY: raw is always initialized unsafe { libc::pthread_mutex_lock(self.raw.get()) }; diff --git a/rust/pin-init/examples/static_init.rs b/rust/pin-init/examples/static_init.rs index 48531413ab94..0e165daa9798 100644 --- a/rust/pin-init/examples/static_init.rs +++ b/rust/pin-init/examples/static_init.rs @@ -3,6 +3,7 @@ #![allow(clippy::undocumented_unsafe_blocks)] #![cfg_attr(feature = "alloc", feature(allocator_api))] #![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))] +#![allow(unused_imports)] use core::{ cell::{Cell, UnsafeCell}, @@ -12,12 +13,13 @@ use core::{ time::Duration, }; use pin_init::*; +#[cfg(feature = "std")] use std::{ sync::Arc, thread::{sleep, Builder}, }; -#[expect(unused_attributes)] +#[allow(unused_attributes)] mod mutex; use mutex::*; @@ -82,42 +84,41 @@ unsafe impl PinInit> for CountInit { pub static COUNT: StaticInit, CountInit> = StaticInit::new(CountInit); -#[cfg(not(any(feature = "std", feature = "alloc")))] -fn main() {} - -#[cfg(any(feature = "std", feature = "alloc"))] fn main() { - let mtx: Pin>> = Arc::pin_init(CMutex::new(0)).unwrap(); - let mut handles = vec![]; - let thread_count = 20; - let workload = 1_000; - for i in 0..thread_count { - let mtx = mtx.clone(); - handles.push( - Builder::new() - .name(format!("worker #{i}")) - .spawn(move || { - for _ in 0..workload { - *COUNT.lock() += 1; - std::thread::sleep(std::time::Duration::from_millis(10)); - *mtx.lock() += 1; - std::thread::sleep(std::time::Duration::from_millis(10)); - *COUNT.lock() += 1; - } - println!("{i} halfway"); - sleep(Duration::from_millis((i as u64) * 10)); - for _ in 0..workload { - std::thread::sleep(std::time::Duration::from_millis(10)); - *mtx.lock() += 1; - } - println!("{i} finished"); - }) - .expect("should not fail"), - ); + #[cfg(feature = "std")] + { + let mtx: Pin>> = Arc::pin_init(CMutex::new(0)).unwrap(); + let mut handles = vec![]; + let thread_count = 20; + let workload = 1_000; + for i in 0..thread_count { + let mtx = mtx.clone(); + handles.push( + Builder::new() + .name(format!("worker #{i}")) + .spawn(move || { + for _ in 0..workload { + *COUNT.lock() += 1; + std::thread::sleep(std::time::Duration::from_millis(10)); + *mtx.lock() += 1; + std::thread::sleep(std::time::Duration::from_millis(10)); + *COUNT.lock() += 1; + } + println!("{i} halfway"); + sleep(Duration::from_millis((i as u64) * 10)); + for _ in 0..workload { + std::thread::sleep(std::time::Duration::from_millis(10)); + *mtx.lock() += 1; + } + println!("{i} finished"); + }) + .expect("should not fail"), + ); + } + for h in handles { + h.join().expect("thread panicked"); + } + println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock()); + assert_eq!(*mtx.lock(), workload * thread_count * 2); } - for h in handles { - h.join().expect("thread panicked"); - } - println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock()); - assert_eq!(*mtx.lock(), workload * thread_count * 2); } From 2408678d700c4db6c54749a272d42a964f5f3418 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 14:54:12 +0200 Subject: [PATCH 04/14] rust: pin-init: examples: pthread_mutex: disable the main test for miri `miri` takes a long time to execute the test, so disable it. Link: https://github.com/Rust-for-Linux/pin-init/pull/50/commits/e717a9eec85024c11e79e8bd9dcb664ad0de8f94 Link: https://lore.kernel.org/all/20250523125424.192843-3-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/examples/pthread_mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs index c709dabba7eb..6c4d18238956 100644 --- a/rust/pin-init/examples/pthread_mutex.rs +++ b/rust/pin-init/examples/pthread_mutex.rs @@ -139,7 +139,7 @@ mod pthread_mtx { } } -#[cfg_attr(test, test)] +#[cfg_attr(all(test, not(miri)), test)] fn main() { #[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))] { From b3b4f760ccf2d08ff3db0f094c32ce70bba2eb15 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Mon, 9 Jun 2025 16:17:35 +0200 Subject: [PATCH 05/14] rust: pin-init: feature-gate the `stack_init_reuse` test on the `std` feature When trying to run `cargo check --all-targets --no-default-features`, an error is reported by the test, as it cannot find the `std` crate. This is to be expected, since the `--no-default-features` flag enables the `no-std` behavior of the crate. Thus exclude the test in that scenario. Link: https://github.com/Rust-for-Linux/pin-init/pull/50/commits/2813729ccacdedee9dbfcab1ed285b8721a0391b Link: https://lore.kernel.org/all/20250523125424.192843-4-lossin@kernel.org [ Changed my author email address to @kernel.org. - Benno ] Signed-off-by: Benno Lossin --- rust/pin-init/src/__internal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs index 557b5948cddc..90f18e9a2912 100644 --- a/rust/pin-init/src/__internal.rs +++ b/rust/pin-init/src/__internal.rs @@ -188,6 +188,7 @@ impl StackInit { } #[test] +#[cfg(feature = "std")] fn stack_init_reuse() { use ::std::{borrow::ToOwned, println, string::String}; use core::pin::pin; From 101b7cf006d4b4b98652bd15dc36e63ede8f8ad8 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 16:50:57 +0200 Subject: [PATCH 06/14] rust: pin-init: rename `zeroed` to `init_zeroed` The name `zeroed` is a much better fit for a function that returns the type by-value. Link: https://github.com/Rust-for-Linux/pin-init/pull/56/commits/7dbe38682c9725405bab91dcabe9c4d8893d2f5e [ also rename uses in `rust/kernel/init.rs` - Benno] Link: https://lore.kernel.org/all/20250523145125.523275-2-lossin@kernel.org [ Fix wrong replacement of `mem::zeroed` in the definition of `trait Zeroable`. - Benno ] [ Also change occurrences of `zeroed` in `configfs.rs` - Benno ] Acked-by: Andreas Hindborg Signed-off-by: Benno Lossin --- rust/kernel/configfs.rs | 4 +-- rust/kernel/init.rs | 8 +++--- rust/pin-init/README.md | 2 +- rust/pin-init/examples/big_struct_in_place.rs | 4 +-- rust/pin-init/src/lib.rs | 26 +++++++++---------- rust/pin-init/src/macros.rs | 16 ++++++------ 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs index 34d0bea4f9a5..6d566a8bde74 100644 --- a/rust/kernel/configfs.rs +++ b/rust/kernel/configfs.rs @@ -151,7 +151,7 @@ impl Subsystem { data: impl PinInit, ) -> impl PinInit { try_pin_init!(Self { - subsystem <- pin_init::zeroed().chain( + subsystem <- pin_init::init_zeroed().chain( |place: &mut Opaque| { // SAFETY: We initialized the required fields of `place.group` above. unsafe { @@ -261,7 +261,7 @@ impl Group { data: impl PinInit, ) -> impl PinInit { try_pin_init!(Self { - group <- pin_init::zeroed().chain(|v: &mut Opaque| { + group <- pin_init::init_zeroed().chain(|v: &mut Opaque| { let place = v.get(); let name = name.as_bytes_with_nul().as_ptr(); // SAFETY: It is safe to initialize a group once it has been zeroed. diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 8d228c237954..15a1c5e397d8 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -206,7 +206,7 @@ pub trait InPlaceInit: Sized { /// /// ```rust /// use kernel::error::Error; -/// use pin_init::zeroed; +/// use pin_init::init_zeroed; /// struct BigBuf { /// big: KBox<[u8; 1024 * 1024 * 1024]>, /// small: [u8; 1024 * 1024], @@ -215,7 +215,7 @@ pub trait InPlaceInit: Sized { /// impl BigBuf { /// fn new() -> impl Init { /// try_init!(Self { -/// big: KBox::init(zeroed(), GFP_KERNEL)?, +/// big: KBox::init(init_zeroed(), GFP_KERNEL)?, /// small: [0; 1024 * 1024], /// }? Error) /// } @@ -264,7 +264,7 @@ macro_rules! try_init { /// ```rust /// # #![feature(new_uninit)] /// use kernel::error::Error; -/// use pin_init::zeroed; +/// use pin_init::init_zeroed; /// #[pin_data] /// struct BigBuf { /// big: KBox<[u8; 1024 * 1024 * 1024]>, @@ -275,7 +275,7 @@ macro_rules! try_init { /// impl BigBuf { /// fn new() -> impl PinInit { /// try_pin_init!(Self { -/// big: KBox::init(zeroed(), GFP_KERNEL)?, +/// big: KBox::init(init_zeroed(), GFP_KERNEL)?, /// small: [0; 1024 * 1024], /// ptr: core::ptr::null_mut(), /// }? Error) diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md index 2d0cda961d45..a4c01a8d78b2 100644 --- a/rust/pin-init/README.md +++ b/rust/pin-init/README.md @@ -125,7 +125,7 @@ impl DriverData { fn new() -> impl PinInit { try_pin_init!(Self { status <- CMutex::new(0), - buffer: Box::init(pin_init::zeroed())?, + buffer: Box::init(pin_init::init_zeroed())?, }? Error) } } diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs index b0ee793a0a0c..c05139927486 100644 --- a/rust/pin-init/examples/big_struct_in_place.rs +++ b/rust/pin-init/examples/big_struct_in_place.rs @@ -21,7 +21,7 @@ pub struct ManagedBuf { impl ManagedBuf { pub fn new() -> impl Init { - init!(ManagedBuf { buf <- zeroed() }) + init!(ManagedBuf { buf <- init_zeroed() }) } } @@ -30,7 +30,7 @@ fn main() { { // we want to initialize the struct in-place, otherwise we would get a stackoverflow let buf: Box = Box::init(init!(BigStruct { - buf <- zeroed(), + buf <- init_zeroed(), a: 7, b: 186, c: 7789, diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index f4e034497cdd..2f7ca94451e6 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -148,7 +148,7 @@ //! fn new() -> impl PinInit { //! try_pin_init!(Self { //! status <- CMutex::new(0), -//! buffer: Box::init(pin_init::zeroed())?, +//! buffer: Box::init(pin_init::init_zeroed())?, //! }? Error) //! } //! } @@ -742,7 +742,7 @@ macro_rules! stack_try_pin_init { /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. /// - In front of the initializer you can write `&this in` to have access to a [`NonNull`] /// pointer named `this` inside of the initializer. -/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the +/// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the /// struct, this initializes every field with 0 and then runs all initializers specified in the /// body. This can only be done if [`Zeroable`] is implemented for the struct. /// @@ -769,7 +769,7 @@ macro_rules! stack_try_pin_init { /// }); /// let init = pin_init!(Buf { /// buf: [1; 64], -/// ..Zeroable::zeroed() +/// ..Zeroable::init_zeroed() /// }); /// ``` /// @@ -805,7 +805,7 @@ macro_rules! pin_init { /// ```rust /// # #![feature(allocator_api)] /// # #[path = "../examples/error.rs"] mod error; use error::Error; -/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed}; +/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed}; /// /// #[pin_data] /// struct BigBuf { @@ -817,7 +817,7 @@ macro_rules! pin_init { /// impl BigBuf { /// fn new() -> impl PinInit { /// try_pin_init!(Self { -/// big: Box::init(zeroed())?, +/// big: Box::init(init_zeroed())?, /// small: [0; 1024 * 1024], /// ptr: core::ptr::null_mut(), /// }? Error) @@ -866,7 +866,7 @@ macro_rules! try_pin_init { /// # #[path = "../examples/error.rs"] mod error; use error::Error; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; /// # use pin_init::InPlaceInit; -/// use pin_init::{init, Init, zeroed}; +/// use pin_init::{init, Init, init_zeroed}; /// /// struct BigBuf { /// small: [u8; 1024 * 1024], @@ -875,7 +875,7 @@ macro_rules! try_pin_init { /// impl BigBuf { /// fn new() -> impl Init { /// init!(Self { -/// small <- zeroed(), +/// small <- init_zeroed(), /// }) /// } /// } @@ -913,7 +913,7 @@ macro_rules! init { /// # #![feature(allocator_api)] /// # use core::alloc::AllocError; /// # use pin_init::InPlaceInit; -/// use pin_init::{try_init, Init, zeroed}; +/// use pin_init::{try_init, Init, init_zeroed}; /// /// struct BigBuf { /// big: Box<[u8; 1024 * 1024 * 1024]>, @@ -923,7 +923,7 @@ macro_rules! init { /// impl BigBuf { /// fn new() -> impl Init { /// try_init!(Self { -/// big: Box::init(zeroed())?, +/// big: Box::init(init_zeroed())?, /// small: [0; 1024 * 1024], /// }? AllocError) /// } @@ -1170,7 +1170,7 @@ pub unsafe trait Init: PinInit { /// /// ```rust /// # #![expect(clippy::disallowed_names)] - /// use pin_init::{init, zeroed, Init}; + /// use pin_init::{init, init_zeroed, Init}; /// /// struct Foo { /// buf: [u8; 1_000_000], @@ -1183,7 +1183,7 @@ pub unsafe trait Init: PinInit { /// } /// /// let foo = init!(Foo { - /// buf <- zeroed() + /// buf <- init_zeroed() /// }).chain(|foo| { /// foo.setup(); /// Ok(()) @@ -1508,11 +1508,11 @@ pub unsafe trait ZeroableOption {} // SAFETY: by the safety requirement of `ZeroableOption`, this is valid. unsafe impl Zeroable for Option {} -/// Create a new zeroed T. +/// Create an initializer for a zeroed `T`. /// /// The returned initializer will write `0x00` to every byte of the given `slot`. #[inline] -pub fn zeroed() -> impl Init { +pub fn init_zeroed() -> impl Init { // SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T` // and because we write all zeroes, the memory is initialized. unsafe { diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index 935d77745d1d..9ced630737b8 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -1030,7 +1030,7 @@ macro_rules! __pin_data { /// /// This macro has multiple internal call configurations, these are always the very first ident: /// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros. -/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled. +/// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax has been handled. /// - `init_slot`: recursively creates the code that initializes all fields in `slot`. /// - `make_initializer`: recursively create the struct initializer that guarantees that every /// field has been initialized exactly once. @@ -1059,7 +1059,7 @@ macro_rules! __init_internal { @data($data, $($use_data)?), @has_data($has_data, $get_data), @construct_closure($construct_closure), - @zeroed(), // Nothing means default behavior. + @init_zeroed(), // Nothing means default behavior. ) }; ( @@ -1074,7 +1074,7 @@ macro_rules! __init_internal { @has_data($has_data:ident, $get_data:ident), // `pin_init_from_closure` or `init_from_closure`. @construct_closure($construct_closure:ident), - @munch_fields(..Zeroable::zeroed()), + @munch_fields(..Zeroable::init_zeroed()), ) => { $crate::__init_internal!(with_update_parsed: @this($($this)?), @@ -1084,7 +1084,7 @@ macro_rules! __init_internal { @data($data, $($use_data)?), @has_data($has_data, $get_data), @construct_closure($construct_closure), - @zeroed(()), // `()` means zero all fields not mentioned. + @init_zeroed(()), // `()` means zero all fields not mentioned. ) }; ( @@ -1124,7 +1124,7 @@ macro_rules! __init_internal { @has_data($has_data:ident, $get_data:ident), // `pin_init_from_closure` or `init_from_closure`. @construct_closure($construct_closure:ident), - @zeroed($($init_zeroed:expr)?), + @init_zeroed($($init_zeroed:expr)?), ) => {{ // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return // type and shadow it later when we insert the arbitrary user code. That way there will be @@ -1196,7 +1196,7 @@ macro_rules! __init_internal { @data($data:ident), @slot($slot:ident), @guards($($guards:ident,)*), - @munch_fields($(..Zeroable::zeroed())? $(,)?), + @munch_fields($(..Zeroable::init_zeroed())? $(,)?), ) => { // Endpoint of munching, no fields are left. If execution reaches this point, all fields // have been initialized. Therefore we can now dismiss the guards by forgetting them. @@ -1300,11 +1300,11 @@ macro_rules! __init_internal { (make_initializer: @slot($slot:ident), @type_name($t:path), - @munch_fields(..Zeroable::zeroed() $(,)?), + @munch_fields(..Zeroable::init_zeroed() $(,)?), @acc($($acc:tt)*), ) => { // Endpoint, nothing more to munch, create the initializer. Since the users specified - // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have + // `..Zeroable::init_zeroed()`, the slot will already have been zeroed and all field that have // not been overwritten are thus zero and initialized. We still check that all fields are // actually accessible by using the struct update syntax ourselves. // We are inside of a closure that is never executed and thus we can abuse `slot` to From c47024ba198b01cab6bb6e3e5a69b73ed2f2aa16 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 16:50:58 +0200 Subject: [PATCH 07/14] rust: pin-init: add `Zeroable::init_zeroed` The trait function delegates to the already existing `init_zeroed` function that returns a zeroing initializer for `Self`. The syntax `..Zeroable::init_zeroed()` is already used by the initialization macros to initialize all fields that are not mentioned in the initializer with zero. Therefore it is expected that the function also exists on the trait. Link: https://github.com/Rust-for-Linux/pin-init/pull/56/commits/a424a6c9af5a4418a8e5e986a3db26a4432e2f1a Link: https://lore.kernel.org/all/20250523145125.523275-3-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 2f7ca94451e6..ef7e5a1e1c48 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1495,7 +1495,18 @@ pub unsafe trait PinnedDrop: __internal::HasPinData { /// ```rust,ignore /// let val: Self = unsafe { core::mem::zeroed() }; /// ``` -pub unsafe trait Zeroable {} +pub unsafe trait Zeroable { + /// Create a new zeroed `Self`. + /// + /// The returned initializer will write `0x00` to every byte of the given `slot`. + #[inline] + fn init_zeroed() -> impl Init + where + Self: Sized, + { + init_zeroed() + } +} /// Marker trait for types that allow `Option` to be set to all zeroes in order to write /// `None` to that location. From d67b37012080cf1978b5fd36f040a53f92152243 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 16:50:59 +0200 Subject: [PATCH 08/14] rust: pin-init: add `zeroed()` & `Zeroable::zeroed()` functions `zeroed()` returns a zeroed out value of a sized type implementing `Zeroable`. The function is added as a free standing function, in addition to an associated function on `Zeroable`, because then it can be marked `const` (functions in traits can't be const at the moment). Link: https://github.com/Rust-for-Linux/pin-init/pull/56/commits/809e4ec160579c1601dce5d78b432a5b6c8e4e40 Link: https://lore.kernel.org/all/20250523145125.523275-4-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index ef7e5a1e1c48..a5bb3939b58b 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1506,6 +1506,33 @@ pub unsafe trait Zeroable { { init_zeroed() } + + /// Create a `Self` consisting of all zeroes. + /// + /// Whenever a type implements [`Zeroable`], this function should be preferred over + /// [`core::mem::zeroed()`] or using `MaybeUninit::zeroed().assume_init()`. + /// + /// # Examples + /// + /// ``` + /// use pin_init::{Zeroable, zeroed}; + /// + /// #[derive(Zeroable)] + /// struct Point { + /// x: u32, + /// y: u32, + /// } + /// + /// let point: Point = zeroed(); + /// assert_eq!(point.x, 0); + /// assert_eq!(point.y, 0); + /// ``` + fn zeroed() -> Self + where + Self: Sized, + { + zeroed() + } } /// Marker trait for types that allow `Option` to be set to all zeroes in order to write @@ -1534,6 +1561,31 @@ pub fn init_zeroed() -> impl Init { } } +/// Create a `T` consisting of all zeroes. +/// +/// Whenever a type implements [`Zeroable`], this function should be preferred over +/// [`core::mem::zeroed()`] or using `MaybeUninit::zeroed().assume_init()`. +/// +/// # Examples +/// +/// ``` +/// use pin_init::{Zeroable, zeroed}; +/// +/// #[derive(Zeroable)] +/// struct Point { +/// x: u32, +/// y: u32, +/// } +/// +/// let point: Point = zeroed(); +/// assert_eq!(point.x, 0); +/// assert_eq!(point.y, 0); +/// ``` +pub const fn zeroed() -> T { + // SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`. + unsafe { core::mem::zeroed() } +} + macro_rules! impl_zeroable { ($($({$($generics:tt)*})? $t:ty, )*) => { // SAFETY: Safety comments written in the macro invocation. From e93a238605348bc40fed77ba5582e311376d113b Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 16:51:00 +0200 Subject: [PATCH 09/14] rust: pin-init: implement `ZeroableOption` for `&T` and `&mut T` `Option<&T>` and `Option<&mut T>` are documented [1] to have the `None` variant be all zeroes. Link: https://doc.rust-lang.org/stable/std/option/index.html#representation [1] Link: https://github.com/Rust-for-Linux/pin-init/pull/56/commits/5ef1638c79e019d3dc0c62db5905601644c2e60a Link: https://lore.kernel.org/all/20250523145125.523275-5-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index a5bb3939b58b..298a3e675b7f 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1546,6 +1546,13 @@ pub unsafe trait ZeroableOption {} // SAFETY: by the safety requirement of `ZeroableOption`, this is valid. unsafe impl Zeroable for Option {} +// SAFETY: `Option<&T>` is part of the option layout optimization guarantee: +// . +unsafe impl ZeroableOption for &T {} +// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: +// . +unsafe impl ZeroableOption for &mut T {} + /// Create an initializer for a zeroed `T`. /// /// The returned initializer will write `0x00` to every byte of the given `slot`. From 9f473538706b9fb5e82c9864b04089d35e4f93d5 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 16:51:01 +0200 Subject: [PATCH 10/14] rust: pin-init: change `impl Zeroable for Option>` to `ZeroableOption for NonNull` This brings it in line with references. It too is listed in [1]. Link: https://doc.rust-lang.org/stable/std/option/index.html#representation Link: https://github.com/Rust-for-Linux/pin-init/pull/56/commits/8e52bf56ddc2190ce901d2f7c008ab8a64f653a9 Link: https://lore.kernel.org/all/20250523145125.523275-6-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 298a3e675b7f..a4656e7976c7 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1552,6 +1552,9 @@ unsafe impl ZeroableOption for &T {} // SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: // . unsafe impl ZeroableOption for &mut T {} +// SAFETY: `Option>` is part of the option layout optimization guarantee: +// . +unsafe impl ZeroableOption for NonNull {} /// Create an initializer for a zeroed `T`. /// @@ -1630,7 +1633,6 @@ impl_zeroable! { Option, Option, Option, Option, Option, Option, Option, Option, - {} Option>, // SAFETY: `null` pointer is valid. // From ec87ec35ca8bd61bfc1200224d332b4573b9dafa Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 16:51:02 +0200 Subject: [PATCH 11/14] rust: pin-init: implement `ZeroableOption` for function pointers with up to 20 arguments `Option<[unsafe] [extern "abi"] fn(...args...) -> ret>` is documented [1] to also have the `None` variant equal all zeroes. Link: https://doc.rust-lang.org/stable/std/option/index.html#representation [1] Link: https://github.com/Rust-for-Linux/pin-init/pull/56/commits/b6c1ab4fb3699765f81ae512ecac5a2f032d8d51 Link: https://lore.kernel.org/all/20250523145125.523275-7-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index a4656e7976c7..3e5fe84ae547 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1662,6 +1662,22 @@ macro_rules! impl_tuple_zeroable { impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); +macro_rules! impl_fn_zeroable_option { + ([$($abi:literal),* $(,)?] $args:tt) => { + $(impl_fn_zeroable_option!({extern $abi} $args);)* + $(impl_fn_zeroable_option!({unsafe extern $abi} $args);)* + }; + ({$($prefix:tt)*} {$(,)?}) => {}; + ({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => { + // SAFETY: function pointers are part of the option layout optimization: + // . + unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {} + impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,}); + }; +} + +impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U }); + /// This trait allows creating an instance of `Self` which contains exactly one /// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning). /// From d2b7313fa21bbe7ce3c4147d84c1ccbc6d69b9db Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 26 May 2025 17:29:13 +0200 Subject: [PATCH 12/14] rust: init: re-enable doctests Commit a30e94c29673 ("rust: init: make doctests compilable/testable") made these tests buildable among others, but eventually the pin-init crate was made into its own crate [1] and the tests were marked as `ignore` in commit 206dea39e559 ("rust: init: disable doctests"). A few other bits got changed in that reorganization, e.g. the `clippy::missing_safety_doc` was removed and the `expect` use. Since there is no reason not to build/test them, re-enable them. In order to do so, tweak a few bits to keep the build clean, and also use again `expect` since this is one of those places where we can actually do so. Link: https://lore.kernel.org/all/20250308110339.2997091-1-benno.lossin@proton.me/ [1] Signed-off-by: Miguel Ojeda Link: https://lore.kernel.org/all/20250526152914.2453949-1-ojeda@kernel.org Signed-off-by: Benno Lossin --- rust/kernel/init.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 15a1c5e397d8..49b949720886 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -29,15 +29,15 @@ //! //! ## General Examples //! -//! ```rust,ignore -//! # #![allow(clippy::disallowed_names)] +//! ```rust +//! # #![expect(clippy::disallowed_names, clippy::undocumented_unsafe_blocks)] //! use kernel::types::Opaque; //! use pin_init::pin_init_from_closure; //! //! // assume we have some `raw_foo` type in C: //! #[repr(C)] //! struct RawFoo([u8; 16]); -//! extern { +//! extern "C" { //! fn init_foo(_: *mut RawFoo); //! } //! @@ -66,12 +66,12 @@ //! }); //! ``` //! -//! ```rust,ignore -//! # #![allow(unreachable_pub, clippy::disallowed_names)] +//! ```rust +//! # #![expect(unreachable_pub, clippy::disallowed_names)] //! use kernel::{prelude::*, types::Opaque}; //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! # mod bindings { -//! # #![allow(non_camel_case_types)] +//! # #![expect(non_camel_case_types, clippy::missing_safety_doc)] //! # pub struct foo; //! # pub unsafe fn init_foo(_ptr: *mut foo) {} //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} From f744a5b68eead2cc73691e91182522c7d800245e Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 26 May 2025 17:29:14 +0200 Subject: [PATCH 13/14] rust: init: remove doctest's `Error::from_errno` workaround Since commit 5ed147473458 ("rust: error: make conversion functions public"), `Error::from_errno` is public. Thus remove the workaround added in commit a30e94c29673 ("rust: init: make doctests compilable/testable"). Suggested-by: Benno Lossin Signed-off-by: Miguel Ojeda Link: https://lore.kernel.org/all/20250526152914.2453949-2-ojeda@kernel.org Signed-off-by: Benno Lossin --- rust/kernel/init.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 49b949720886..49a61fa3dee8 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -77,14 +77,6 @@ //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} //! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 } //! # } -//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround. -//! # trait FromErrno { -//! # fn from_errno(errno: core::ffi::c_int) -> Error { -//! # // Dummy error that can be constructed outside the `kernel` crate. -//! # Error::from(core::fmt::Error) -//! # } -//! # } -//! # impl FromErrno for Error {} //! /// # Invariants //! /// //! /// `foo` is always initialized From fc3870dc5cadb701b4122e4a8daa85f9fa2f57b9 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Thu, 5 Jun 2025 17:52:54 +0200 Subject: [PATCH 14/14] rust: pin-init: examples, tests: use `ignore` instead of conditionally compiling tests Change `#[cfg(cond)]` to `#[cfg_attr(not(cond), ignore)]` on tests. Ignoring tests instead of disabling them still makes them appear in the test list, but with `ignored`. It also still compiles the code in those cases. Some tests still need to be ignore, because they use types that are not present when the condition is false. For example the condition is `feature = std` and then it uses `std::thread::Thread`. Suggested-by: Alice Ryhl Link: https://lore.kernel.org/all/aDC9y829vZZBzZ2p@google.com Link: https://github.com/Rust-for-Linux/pin-init/pull/58/commits/b004dd8e64d4cbe219a4eff0d25f0a5f5bc750ca Reviewed-by: Christian Schrefl Link: https://lore.kernel.org/all/20250605155258.573391-1-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/examples/pthread_mutex.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs index 6c4d18238956..49b004c8c137 100644 --- a/rust/pin-init/examples/pthread_mutex.rs +++ b/rust/pin-init/examples/pthread_mutex.rs @@ -139,7 +139,8 @@ mod pthread_mtx { } } -#[cfg_attr(all(test, not(miri)), test)] +#[cfg_attr(test, test)] +#[cfg_attr(all(test, miri), ignore)] fn main() { #[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))] {