diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-09-30 19:12:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-09-30 19:12:49 -0700 |
commit | f4e0ff7e45c30f4665cfbbe2f0538e9c5789bebc (patch) | |
tree | 6703541ef1fec9d20dafc751d2e971879c429884 /rust/kernel/alloc/kbox.rs | |
parent | ae28ed4578e6d5a481e39c5a9827f27048661fdd (diff) | |
parent | f3f6b3664302e16ef1c6b91034a72df5564d6b8a (diff) |
Merge tag 'rust-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull rust updates from Miguel Ojeda:
"Toolchain and infrastructure:
- Derive 'Zeroable' for all structs and unions generated by 'bindgen'
where possible and corresponding cleanups. To do so, add the
'pin-init' crate as a dependency to 'bindings' and 'uapi'.
It also includes its first use in the 'cpufreq' module, with more
to come in the next cycle.
- Add warning to the 'rustdoc' target to detect broken 'srctree/'
links and fix existing cases.
- Remove support for unused (since v6.16) host '#[test]'s,
simplifying the 'rusttest' target. Tests should generally run
within KUnit.
'kernel' crate:
- Add 'ptr' module with a new 'Alignment' type, which is always a
power of two and is used to validate that a given value is a valid
alignment and to perform masking and alignment operations:
// Checked at build time.
assert_eq!(Alignment::new::<16>().as_usize(), 16);
// Checked at runtime.
assert_eq!(Alignment::new_checked(15), None);
assert_eq!(Alignment::of::<u8>().log2(), 0);
assert_eq!(0x25u8.align_down(Alignment::new::<0x10>()), 0x20);
assert_eq!(0x5u8.align_up(Alignment::new::<0x10>()), Some(0x10));
assert_eq!(u8::MAX.align_up(Alignment::new::<0x10>()), None);
It also includes its first use in Nova.
- Add 'core::mem::{align,size}_of{,_val}' to the prelude, matching
Rust 1.80.0.
- Keep going with the steps on our migration to the standard library
'core::ffi::CStr' type (use 'kernel::{fmt, prelude::fmt!}' and use
upstream method names).
- 'error' module: improve 'Error::from_errno' and 'to_result'
documentation, including examples/tests.
- 'sync' module: extend 'aref' submodule documentation now that it
exists, and more updates to complete the ongoing move of 'ARef' and
'AlwaysRefCounted' to 'sync::aref'.
- 'list' module: add an example/test for 'ListLinksSelfPtr' usage.
- 'alloc' module:
- Implement 'Box::pin_slice()', which constructs a pinned slice of
elements.
- Provide information about the minimum alignment guarantees of
'Kmalloc', 'Vmalloc' and 'KVmalloc'.
- Take minimum alignment guarantees of allocators for
'ForeignOwnable' into account.
- Remove the 'allocator_test' (including 'Cmalloc').
- Add doctest for 'Vec::as_slice()'.
- Constify various methods.
- 'time' module:
- Add methods on 'HrTimer' that can only be called with exclusive
access to an unarmed timer, or from timer callback context.
- Add arithmetic operations to 'Instant' and 'Delta'.
- Add a few convenience and access methods to 'HrTimer' and
'Instant'.
'macros' crate:
- Reduce collections in 'quote!' macro.
And a few other cleanups and improvements"
* tag 'rust-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (58 commits)
gpu: nova-core: use Alignment for alignment-related operations
rust: add `Alignment` type
rust: macros: reduce collections in `quote!` macro
rust: acpi: use `core::ffi::CStr` method names
rust: of: use `core::ffi::CStr` method names
rust: net: use `core::ffi::CStr` method names
rust: miscdevice: use `core::ffi::CStr` method names
rust: kunit: use `core::ffi::CStr` method names
rust: firmware: use `core::ffi::CStr` method names
rust: drm: use `core::ffi::CStr` method names
rust: cpufreq: use `core::ffi::CStr` method names
rust: configfs: use `core::ffi::CStr` method names
rust: auxiliary: use `core::ffi::CStr` method names
drm/panic: use `core::ffi::CStr` method names
rust: device: use `kernel::{fmt,prelude::fmt!}`
rust: sync: use `kernel::{fmt,prelude::fmt!}`
rust: seq_file: use `kernel::{fmt,prelude::fmt!}`
rust: kunit: use `kernel::{fmt,prelude::fmt!}`
rust: file: use `kernel::{fmt,prelude::fmt!}`
rust: device: use `kernel::{fmt,prelude::fmt!}`
...
Diffstat (limited to 'rust/kernel/alloc/kbox.rs')
-rw-r--r-- | rust/kernel/alloc/kbox.rs | 92 |
1 files changed, 87 insertions, 5 deletions
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 856d05aa60f1..27c4b5a9b61d 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -7,7 +7,6 @@ use super::allocator::{KVmalloc, Kmalloc, Vmalloc}; use super::{AllocError, Allocator, Flags}; use core::alloc::Layout; use core::borrow::{Borrow, BorrowMut}; -use core::fmt; use core::marker::PhantomData; use core::mem::ManuallyDrop; use core::mem::MaybeUninit; @@ -17,6 +16,7 @@ use core::ptr::NonNull; use core::result::Result; use crate::ffi::c_void; +use crate::fmt; use crate::init::InPlaceInit; use crate::types::ForeignOwnable; use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption}; @@ -290,6 +290,83 @@ where Ok(Self::new(x, flags)?.into()) } + /// Construct a pinned slice of elements `Pin<Box<[T], A>>`. + /// + /// This is a convenient means for creation of e.g. slices of structrures containing spinlocks + /// or mutexes. + /// + /// # Examples + /// + /// ``` + /// use kernel::sync::{new_spinlock, SpinLock}; + /// + /// struct Inner { + /// a: u32, + /// b: u32, + /// } + /// + /// #[pin_data] + /// struct Example { + /// c: u32, + /// #[pin] + /// d: SpinLock<Inner>, + /// } + /// + /// impl Example { + /// fn new() -> impl PinInit<Self, Error> { + /// try_pin_init!(Self { + /// c: 10, + /// d <- new_spinlock!(Inner { a: 20, b: 30 }), + /// }) + /// } + /// } + /// + /// // Allocate a boxed slice of 10 `Example`s. + /// let s = KBox::pin_slice( + /// | _i | Example::new(), + /// 10, + /// GFP_KERNEL + /// )?; + /// + /// assert_eq!(s[5].c, 10); + /// assert_eq!(s[3].d.lock().a, 20); + /// # Ok::<(), Error>(()) + /// ``` + pub fn pin_slice<Func, Item, E>( + mut init: Func, + len: usize, + flags: Flags, + ) -> Result<Pin<Box<[T], A>>, E> + where + Func: FnMut(usize) -> Item, + Item: PinInit<T, E>, + E: From<AllocError>, + { + let mut buffer = super::Vec::<T, A>::with_capacity(len, flags)?; + for i in 0..len { + let ptr = buffer.spare_capacity_mut().as_mut_ptr().cast(); + // SAFETY: + // - `ptr` is a valid pointer to uninitialized memory. + // - `ptr` is not used if an error is returned. + // - `ptr` won't be moved until it is dropped, i.e. it is pinned. + unsafe { init(i).__pinned_init(ptr)? }; + + // SAFETY: + // - `i + 1 <= len`, hence we don't exceed the capacity, due to the call to + // `with_capacity()` above. + // - The new value at index buffer.len() + 1 is the only element being added here, and + // it has been initialized above by `init(i).__pinned_init(ptr)`. + unsafe { buffer.inc_len(1) }; + } + + let (ptr, _, _) = buffer.into_raw_parts(); + let slice = core::ptr::slice_from_raw_parts_mut(ptr, len); + + // SAFETY: `slice` points to an allocation allocated with `A` (`buffer`) and holds a valid + // `[T]`. + Ok(Pin::from(unsafe { Box::from_raw(slice) })) + } + /// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement /// [`Unpin`], then `x` will be pinned in memory and can't be moved. pub fn into_pin(this: Self) -> Pin<Self> { @@ -401,12 +478,17 @@ where } // SAFETY: The pointer returned by `into_foreign` comes from a well aligned -// pointer to `T`. +// pointer to `T` allocated by `A`. unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> where A: Allocator, { - const FOREIGN_ALIGN: usize = core::mem::align_of::<T>(); + const FOREIGN_ALIGN: usize = if core::mem::align_of::<T>() < A::MIN_ALIGN { + A::MIN_ALIGN + } else { + core::mem::align_of::<T>() + }; + type Borrowed<'a> = &'a T; type BorrowedMut<'a> = &'a mut T; @@ -435,12 +517,12 @@ where } // SAFETY: The pointer returned by `into_foreign` comes from a well aligned -// pointer to `T`. +// pointer to `T` allocated by `A`. unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> where A: Allocator, { - const FOREIGN_ALIGN: usize = core::mem::align_of::<T>(); + const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN; type Borrowed<'a> = Pin<&'a T>; type BorrowedMut<'a> = Pin<&'a mut T>; |