mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Alloc & DMA changes for v6.18
Allocator:
- 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` incl. `Cmalloc`.
Box:
- Implement Box::pin_slice(), which constructs a pinned slice of
elements.
Vec:
- Simplify KUnit test module name to "rust_kvec".
- Add doc-test for Vec::as_slice().
- Constify various methods.
DMA:
- Update ARef and AlwaysRefCounted imports.
MISC:
- Remove support for unused host `#[test]`s.
- Constify ArrayLayout::new_unchecked().
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQS2q/xV6QjXAdC7k+1FlHeO1qrKLgUCaLnByQAKCRBFlHeO1qrK
Lq1VAP4qZDK6vfjXWOwcDB/vqtSLBLY3bLTceXrtoFtHH7OdqAEAviY19NnGTwb5
gwOfbxjU+/9q1p/3ukmAiUQZiN93rwI=
=SBFK
-----END PGP SIGNATURE-----
Merge tag 'alloc-next-v6.18-2025-09-04' of https://github.com/Rust-for-Linux/linux into rust-next
Pull alloc and DMA updates from Danilo Krummrich:
Allocator:
- 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' incl. 'Cmalloc'.
Box:
- Implement 'Box::pin_slice()', which constructs a pinned slice of
elements.
Vec:
- Simplify KUnit test module name to 'rust_kvec'.
- Add doc-test for 'Vec::as_slice()'.
- Constify various methods.
DMA:
- Update 'ARef' and 'AlwaysRefCounted' imports.
MISC:
- Remove support for unused host '#[test]'s.
- Constify 'ArrayLayout::new_unchecked()'.
* tag 'alloc-next-v6.18-2025-09-04' of https://github.com/Rust-for-Linux/linux:
rust: alloc: remove `allocator_test`
rust: kernel: remove support for unused host `#[test]`s
rust: alloc: implement Box::pin_slice()
rust: alloc: add ARCH_KMALLOC_MINALIGN to bindgen blocklist
rust: dma: Update ARef and AlwaysRefCounted imports from sync::aref
rust: alloc: take the allocator into account for FOREIGN_ALIGN
rust: alloc: specify the minimum alignment of each allocator
rust: make `kvec::Vec` functions `const fn`
rust: make `ArrayLayout::new_unchecked` a `const fn`
rust: alloc: kvec: simplify KUnit test module name to "rust_kvec"
rust: alloc: kvec: add doc example for as_slice method
This commit is contained in:
commit
f1d3703fa3
|
|
@ -248,7 +248,7 @@ quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $<
|
|||
$(objtree)/$(obj)/test/$(subst rusttest-,,$@) $(rust_test_quiet) \
|
||||
$(rustc_test_run_flags)
|
||||
|
||||
rusttest: rusttest-macros rusttest-kernel
|
||||
rusttest: rusttest-macros
|
||||
|
||||
rusttest-macros: private rustc_target_flags = --extern proc_macro \
|
||||
--extern macros --extern kernel --extern pin_init
|
||||
|
|
@ -258,13 +258,6 @@ rusttest-macros: $(src)/macros/lib.rs \
|
|||
+$(call if_changed,rustc_test)
|
||||
+$(call if_changed,rustdoc_test)
|
||||
|
||||
rusttest-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
|
||||
--extern build_error --extern macros --extern bindings --extern uapi
|
||||
rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-ffi rusttestlib-kernel \
|
||||
rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
|
||||
rusttestlib-uapi rusttestlib-pin_init FORCE
|
||||
+$(call if_changed,rustc_test)
|
||||
|
||||
ifdef CONFIG_CC_IS_CLANG
|
||||
bindgen_c_flags = $(c_flags)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -34,3 +34,4 @@
|
|||
# We use const helpers to aid bindgen, to avoid conflicts when constants are
|
||||
# recognized, block generation of the non-helper constants.
|
||||
--blocklist-item ARCH_SLAB_MINALIGN
|
||||
--blocklist-item ARCH_KMALLOC_MINALIGN
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
|
||||
/* `bindgen` gets confused at certain things. */
|
||||
const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
|
||||
const size_t RUST_CONST_HELPER_ARCH_KMALLOC_MINALIGN = ARCH_KMALLOC_MINALIGN;
|
||||
const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;
|
||||
const gfp_t RUST_CONST_HELPER_GFP_ATOMIC = GFP_ATOMIC;
|
||||
const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL;
|
||||
|
|
|
|||
|
|
@ -2,18 +2,11 @@
|
|||
|
||||
//! Implementation of the kernel's memory allocation infrastructure.
|
||||
|
||||
#[cfg(not(any(test, testlib)))]
|
||||
pub mod allocator;
|
||||
pub mod kbox;
|
||||
pub mod kvec;
|
||||
pub mod layout;
|
||||
|
||||
#[cfg(any(test, testlib))]
|
||||
pub mod allocator_test;
|
||||
|
||||
#[cfg(any(test, testlib))]
|
||||
pub use self::allocator_test as allocator;
|
||||
|
||||
pub use self::kbox::Box;
|
||||
pub use self::kbox::KBox;
|
||||
pub use self::kbox::KVBox;
|
||||
|
|
@ -137,6 +130,14 @@ pub mod flags {
|
|||
/// - Implementers must ensure that all trait functions abide by the guarantees documented in the
|
||||
/// `# Guarantees` sections.
|
||||
pub unsafe trait Allocator {
|
||||
/// The minimum alignment satisfied by all allocations from this allocator.
|
||||
///
|
||||
/// # Guarantees
|
||||
///
|
||||
/// Any pointer allocated by this allocator is guaranteed to be aligned to `MIN_ALIGN` even if
|
||||
/// the requested layout has a smaller alignment.
|
||||
const MIN_ALIGN: usize;
|
||||
|
||||
/// Allocate memory based on `layout` and `flags`.
|
||||
///
|
||||
/// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
use crate::bindings;
|
||||
use crate::pr_warn;
|
||||
|
||||
const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN;
|
||||
|
||||
/// The contiguous kernel allocator.
|
||||
///
|
||||
/// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
|
||||
|
|
@ -128,6 +130,8 @@ pub fn aligned_layout(layout: Layout) -> Layout {
|
|||
// - passing a pointer to a valid memory allocation is OK,
|
||||
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
||||
unsafe impl Allocator for Kmalloc {
|
||||
const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(
|
||||
ptr: Option<NonNull<u8>>,
|
||||
|
|
@ -147,6 +151,8 @@ unsafe fn realloc(
|
|||
// - passing a pointer to a valid memory allocation is OK,
|
||||
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
||||
unsafe impl Allocator for Vmalloc {
|
||||
const MIN_ALIGN: usize = kernel::page::PAGE_SIZE;
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(
|
||||
ptr: Option<NonNull<u8>>,
|
||||
|
|
@ -171,6 +177,8 @@ unsafe fn realloc(
|
|||
// - passing a pointer to a valid memory allocation is OK,
|
||||
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
|
||||
unsafe impl Allocator for KVmalloc {
|
||||
const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(
|
||||
ptr: Option<NonNull<u8>>,
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users
|
||||
//! of those types (e.g. `CString`) use kernel allocators for instantiation.
|
||||
//!
|
||||
//! In order to allow userspace test cases to make use of such types as well, implement the
|
||||
//! `Cmalloc` allocator within the `allocator_test` module and type alias all kernel allocators to
|
||||
//! `Cmalloc`. The `Cmalloc` allocator uses libc's `realloc()` function as allocator backend.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use super::{flags::*, AllocError, Allocator, Flags};
|
||||
use core::alloc::Layout;
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// The userspace allocator based on libc.
|
||||
pub struct Cmalloc;
|
||||
|
||||
pub type Kmalloc = Cmalloc;
|
||||
pub type Vmalloc = Kmalloc;
|
||||
pub type KVmalloc = Kmalloc;
|
||||
|
||||
impl Cmalloc {
|
||||
/// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of
|
||||
/// `layout`.
|
||||
pub fn aligned_layout(layout: Layout) -> Layout {
|
||||
// Note that `layout.size()` (after padding) is guaranteed to be a multiple of
|
||||
// `layout.align()` which together with the slab guarantees means that `Kmalloc` will return
|
||||
// a properly aligned object (see comments in `kmalloc()` for more information).
|
||||
layout.pad_to_align()
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "aligned_alloc"]
|
||||
fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void;
|
||||
|
||||
#[link_name = "free"]
|
||||
fn libc_free(ptr: *mut crate::ffi::c_void);
|
||||
}
|
||||
|
||||
// SAFETY:
|
||||
// - memory remains valid until it is explicitly freed,
|
||||
// - passing a pointer to a valid memory allocation created by this `Allocator` is always OK,
|
||||
// - `realloc` provides the guarantees as provided in the `# Guarantees` section.
|
||||
unsafe impl Allocator for Cmalloc {
|
||||
unsafe fn realloc(
|
||||
ptr: Option<NonNull<u8>>,
|
||||
layout: Layout,
|
||||
old_layout: Layout,
|
||||
flags: Flags,
|
||||
) -> Result<NonNull<[u8]>, AllocError> {
|
||||
let src = match ptr {
|
||||
Some(src) => {
|
||||
if old_layout.size() == 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
src.as_ptr()
|
||||
}
|
||||
}
|
||||
None => ptr::null_mut(),
|
||||
};
|
||||
|
||||
if layout.size() == 0 {
|
||||
// SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
|
||||
unsafe { libc_free(src.cast()) };
|
||||
|
||||
return Ok(NonNull::slice_from_raw_parts(
|
||||
crate::alloc::dangling_from_layout(layout),
|
||||
0,
|
||||
));
|
||||
}
|
||||
|
||||
// ISO C (ISO/IEC 9899:2011) defines `aligned_alloc`:
|
||||
//
|
||||
// > The value of alignment shall be a valid alignment supported by the implementation
|
||||
// [...].
|
||||
//
|
||||
// As an example of the "supported by the implementation" requirement, POSIX.1-2001 (IEEE
|
||||
// 1003.1-2001) defines `posix_memalign`:
|
||||
//
|
||||
// > The value of alignment shall be a power of two multiple of sizeof (void *).
|
||||
//
|
||||
// and POSIX-based implementations of `aligned_alloc` inherit this requirement. At the time
|
||||
// of writing, this is known to be the case on macOS (but not in glibc).
|
||||
//
|
||||
// Satisfy the stricter requirement to avoid spurious test failures on some platforms.
|
||||
let min_align = core::mem::size_of::<*const crate::ffi::c_void>();
|
||||
let layout = layout.align_to(min_align).map_err(|_| AllocError)?;
|
||||
let layout = layout.pad_to_align();
|
||||
|
||||
// SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or
|
||||
// exceeds the given size and alignment requirements.
|
||||
let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) }.cast::<u8>();
|
||||
let dst = NonNull::new(dst).ok_or(AllocError)?;
|
||||
|
||||
if flags.contains(__GFP_ZERO) {
|
||||
// SAFETY: The preceding calls to `libc_aligned_alloc` and `NonNull::new`
|
||||
// guarantee that `dst` points to memory of at least `layout.size()` bytes.
|
||||
unsafe { dst.as_ptr().write_bytes(0, layout.size()) };
|
||||
}
|
||||
|
||||
if !src.is_null() {
|
||||
// SAFETY:
|
||||
// - `src` has previously been allocated with this `Allocator`; `dst` has just been
|
||||
// newly allocated, hence the memory regions do not overlap.
|
||||
// - both` src` and `dst` are properly aligned and valid for reads and writes
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
src,
|
||||
dst.as_ptr(),
|
||||
cmp::min(layout.size(), old_layout.size()),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
// SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
|
||||
unsafe { libc_free(src.cast()) };
|
||||
|
||||
Ok(NonNull::slice_from_raw_parts(dst, layout.size()))
|
||||
}
|
||||
}
|
||||
|
|
@ -290,6 +290,83 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
|
|||
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 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
|
|||
}
|
||||
|
||||
// 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 @@ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a mut T {
|
|||
}
|
||||
|
||||
// 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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ const fn is_zst() -> bool {
|
|||
|
||||
/// Returns the number of elements that can be stored within the vector without allocating
|
||||
/// additional memory.
|
||||
pub fn capacity(&self) -> usize {
|
||||
pub const fn capacity(&self) -> usize {
|
||||
if const { Self::is_zst() } {
|
||||
usize::MAX
|
||||
} else {
|
||||
|
|
@ -185,7 +185,7 @@ pub fn capacity(&self) -> usize {
|
|||
|
||||
/// Returns the number of elements stored within the vector.
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
pub const fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ pub fn len(&self) -> usize {
|
|||
/// - `additional` must be less than or equal to `self.capacity - self.len`.
|
||||
/// - All elements within the interval [`self.len`,`self.len + additional`) must be initialized.
|
||||
#[inline]
|
||||
pub unsafe fn inc_len(&mut self, additional: usize) {
|
||||
pub const unsafe fn inc_len(&mut self, additional: usize) {
|
||||
// Guaranteed by the type invariant to never underflow.
|
||||
debug_assert!(additional <= self.capacity() - self.len());
|
||||
// INVARIANT: By the safety requirements of this method this represents the exact number of
|
||||
|
|
@ -224,6 +224,16 @@ unsafe fn dec_len(&mut self, count: usize) -> &mut [T] {
|
|||
}
|
||||
|
||||
/// Returns a slice of the entire vector.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut v = KVec::new();
|
||||
/// v.push(1, GFP_KERNEL)?;
|
||||
/// v.push(2, GFP_KERNEL)?;
|
||||
/// assert_eq!(v.as_slice(), &[1, 2]);
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self
|
||||
|
|
@ -245,7 +255,7 @@ pub fn as_mut_ptr(&mut self) -> *mut T {
|
|||
/// Returns a raw pointer to the vector's backing buffer, or, if `T` is a ZST, a dangling raw
|
||||
/// pointer.
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
pub const fn as_ptr(&self) -> *const T {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +271,7 @@ pub fn as_ptr(&self) -> *const T {
|
|||
/// assert!(!v.is_empty());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
|
|
@ -1294,7 +1304,7 @@ fn drop(&mut self) {
|
|||
}
|
||||
}
|
||||
|
||||
#[macros::kunit_tests(rust_kvec_kunit)]
|
||||
#[macros::kunit_tests(rust_kvec)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ pub const fn new(len: usize) -> Result<Self, LayoutError> {
|
|||
/// # Safety
|
||||
///
|
||||
/// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
|
||||
pub unsafe fn new_unchecked(len: usize) -> Self {
|
||||
pub const unsafe fn new_unchecked(len: usize) -> Self {
|
||||
// INVARIANT: By the safety requirements of this function
|
||||
// `len * size_of::<T>() <= isize::MAX`.
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
device::{Bound, Core},
|
||||
error::{to_result, Result},
|
||||
prelude::*,
|
||||
sync::aref::ARef,
|
||||
transmute::{AsBytes, FromBytes},
|
||||
types::ARef,
|
||||
};
|
||||
|
||||
/// Trait to be implemented by DMA capable bus devices.
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ pub fn to_ptr<T>(self) -> *mut T {
|
|||
}
|
||||
|
||||
/// Returns a string representing the error, if one exists.
|
||||
#[cfg(not(any(test, testlib)))]
|
||||
#[cfg(not(testlib))]
|
||||
pub fn name(&self) -> Option<&'static CStr> {
|
||||
// SAFETY: Just an FFI call, there are no extra safety requirements.
|
||||
let ptr = unsafe { bindings::errname(-self.0.get()) };
|
||||
|
|
@ -175,7 +175,7 @@ pub fn name(&self) -> Option<&'static CStr> {
|
|||
/// When `testlib` is configured, this always returns `None` to avoid the dependency on a
|
||||
/// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
|
||||
/// run in userspace.
|
||||
#[cfg(any(test, testlib))]
|
||||
#[cfg(testlib)]
|
||||
pub fn name(&self) -> Option<&'static CStr> {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ pub const fn as_ptr(&self) -> *mut bindings::module {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(testlib, test)))]
|
||||
#[cfg(not(testlib))]
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
|
||||
pr_emerg!("{}\n", info);
|
||||
|
|
|
|||
|
|
@ -373,10 +373,10 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
|
|||
}
|
||||
}
|
||||
|
||||
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
|
||||
// pointer to `ArcInner<T>`.
|
||||
// SAFETY: The pointer returned by `into_foreign` was originally allocated as an
|
||||
// `KBox<ArcInner<T>>`, so that type is what determines the alignment.
|
||||
unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
|
||||
const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>();
|
||||
const FOREIGN_ALIGN: usize = <KBox<ArcInner<T>> as ForeignOwnable>::FOREIGN_ALIGN;
|
||||
|
||||
type Borrowed<'a> = ArcBorrow<'a, T>;
|
||||
type BorrowedMut<'a> = Self::Borrowed<'a>;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
dma::{CoherentAllocation, Device, DmaMask},
|
||||
pci,
|
||||
prelude::*,
|
||||
types::ARef,
|
||||
sync::aref::ARef,
|
||||
};
|
||||
|
||||
struct DmaSampleDriver {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user