diff options
Diffstat (limited to 'rust')
36 files changed, 473 insertions, 235 deletions
diff --git a/rust/Makefile b/rust/Makefile index a40a3936126d..71a05a3c895a 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h obj-$(CONFIG_RUST) += helpers/helpers.o CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations -always-$(CONFIG_RUST) += libmacros.so -no-clean-files += libmacros.so - always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs obj-$(CONFIG_RUST) += bindings.o kernel.o always-$(CONFIG_RUST) += exports_helpers_generated.h \ @@ -38,9 +35,14 @@ obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs -# Avoids running `$(RUSTC)` for the sysroot when it may not be available. +# Avoids running `$(RUSTC)` when it may not be available. ifdef CONFIG_RUST +libmacros_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - </dev/null) +libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name)) + +always-$(CONFIG_RUST) += $(libmacros_name) + # `$(rust_flags)` is passed in case the user added `--sysroot`. rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot) rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2) @@ -109,17 +111,17 @@ rustdoc-ffi: $(src)/ffi.rs rustdoc-core FORCE +$(call if_changed,rustdoc) rustdoc-kernel: private rustc_target_flags = --extern ffi \ - --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \ + --extern build_error --extern macros \ --extern bindings --extern uapi rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \ - rustdoc-compiler_builtins $(obj)/libmacros.so \ + rustdoc-compiler_builtins $(obj)/$(libmacros_name) \ $(obj)/bindings.o FORCE +$(call if_changed,rustdoc) -quiet_cmd_rustc_test_library = RUSTC TL $< +quiet_cmd_rustc_test_library = $(RUSTC_OR_CLIPPY_QUIET) TL $< cmd_rustc_test_library = \ OBJTREE=$(abspath $(objtree)) \ - $(RUSTC) $(rust_common_flags) \ + $(RUSTC_OR_CLIPPY) $(rust_common_flags) \ @$(objtree)/include/generated/rustc_cfg $(rustc_target_flags) \ --crate-type $(if $(rustc_test_library_proc),proc-macro,rlib) \ --out-dir $(objtree)/$(obj)/test --cfg testlib \ @@ -187,10 +189,10 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $< # We cannot use `-Zpanic-abort-tests` because some tests are dynamic, # so for the moment we skip `-Cpanic=abort`. -quiet_cmd_rustc_test = RUSTC T $< +quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $< cmd_rustc_test = \ OBJTREE=$(abspath $(objtree)) \ - $(RUSTC) --test $(rust_common_flags) \ + $(RUSTC_OR_CLIPPY) --test $(rust_common_flags) \ @$(objtree)/include/generated/rustc_cfg \ $(rustc_target_flags) --out-dir $(objtree)/$(obj)/test \ -L$(objtree)/$(obj)/test \ @@ -359,13 +361,13 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@ cmd_rustc_procmacro = \ $(RUSTC_OR_CLIPPY) $(rust_common_flags) \ -Clinker-flavor=gcc -Clinker=$(HOSTCC) \ - -Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \ + -Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \ --emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \ --crate-type proc-macro \ - --crate-name $(patsubst lib%.so,%,$(notdir $@)) $< + --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $< # Procedural macros can only be used with the `rustc` that compiled it. -$(obj)/libmacros.so: $(src)/macros/lib.rs FORCE +$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE +$(call if_changed_dep,rustc_procmacro) quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@ @@ -382,7 +384,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $(cmd_objtool) rust-analyzer: - $(Q)$(srctree)/scripts/generate_rust_analyzer.py \ + $(Q)MAKEFLAGS= $(srctree)/scripts/generate_rust_analyzer.py \ --cfgs='core=$(core-cfgs)' \ $(realpath $(srctree)) $(realpath $(objtree)) \ $(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \ @@ -443,7 +445,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \ $(obj)/kernel.o: private rustc_target_flags = --extern ffi \ --extern build_error --extern macros --extern bindings --extern uapi $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \ - $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE + $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE +$(call if_changed_rule,rustc_library) ifdef CONFIG_JUMP_LABEL diff --git a/rust/ffi.rs b/rust/ffi.rs index be153c4d551b..584f75b49862 100644 --- a/rust/ffi.rs +++ b/rust/ffi.rs @@ -10,4 +10,39 @@ #![no_std] -pub use core::ffi::*; +macro_rules! alias { + ($($name:ident = $ty:ty;)*) => {$( + #[allow(non_camel_case_types, missing_docs)] + pub type $name = $ty; + + // Check size compatibility with `core`. + const _: () = assert!( + core::mem::size_of::<$name>() == core::mem::size_of::<core::ffi::$name>() + ); + )*} +} + +alias! { + // `core::ffi::c_char` is either `i8` or `u8` depending on architecture. In the kernel, we use + // `-funsigned-char` so it's always mapped to `u8`. + c_char = u8; + + c_schar = i8; + c_uchar = u8; + + c_short = i16; + c_ushort = u16; + + c_int = i32; + c_uint = u32; + + // In the kernel, `intptr_t` is defined to be `long` in all platforms, so we can map the type to + // `isize`. + c_long = isize; + c_ulong = usize; + + c_longlong = i64; + c_ulonglong = u64; +} + +pub use core::ffi::c_void; diff --git a/rust/helpers/mutex.c b/rust/helpers/mutex.c index 7e00680958ef..06575553eda5 100644 --- a/rust/helpers/mutex.c +++ b/rust/helpers/mutex.c @@ -12,3 +12,8 @@ void rust_helper___mutex_init(struct mutex *mutex, const char *name, { __mutex_init(mutex, name, key); } + +void rust_helper_mutex_assert_is_held(struct mutex *mutex) +{ + lockdep_assert_held(mutex); +} diff --git a/rust/helpers/security.c b/rust/helpers/security.c index 239e5b4745fe..0c4c2065df28 100644 --- a/rust/helpers/security.c +++ b/rust/helpers/security.c @@ -8,13 +8,13 @@ void rust_helper_security_cred_getsecid(const struct cred *c, u32 *secid) security_cred_getsecid(c, secid); } -int rust_helper_security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +int rust_helper_security_secid_to_secctx(u32 secid, struct lsm_context *cp) { - return security_secid_to_secctx(secid, secdata, seclen); + return security_secid_to_secctx(secid, cp); } -void rust_helper_security_release_secctx(char *secdata, u32 seclen) +void rust_helper_security_release_secctx(struct lsm_context *cp) { - security_release_secctx(secdata, seclen); + security_release_secctx(cp); } #endif diff --git a/rust/helpers/spinlock.c b/rust/helpers/spinlock.c index 5971fdf6f755..42c4bf01a23e 100644 --- a/rust/helpers/spinlock.c +++ b/rust/helpers/spinlock.c @@ -30,3 +30,8 @@ int rust_helper_spin_trylock(spinlock_t *lock) { return spin_trylock(lock); } + +void rust_helper_spin_assert_is_held(spinlock_t *lock) +{ + lockdep_assert_held(lock); +} diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index f2f7f3a53d29..fc9c9c41cd79 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -123,7 +123,7 @@ pub mod flags { /// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on /// an object instance. /// -/// In order to be able to support `#[derive(SmartPointer)]` later on, we need to avoid a design +/// In order to be able to support `#[derive(CoercePointee)]` later on, we need to avoid a design /// that requires an `Allocator` to be instantiated, hence its functions must not contain any kind /// of `self` parameter. /// diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 9ce414361c2c..cb4ebea3b074 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -354,22 +354,30 @@ where A: Allocator, { type Borrowed<'a> = &'a T; + type BorrowedMut<'a> = &'a mut T; - fn into_foreign(self) -> *const crate::ffi::c_void { - Box::into_raw(self) as _ + fn into_foreign(self) -> *mut crate::ffi::c_void { + Box::into_raw(self).cast() } - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr as _) } + unsafe { Box::from_raw(ptr.cast()) } } - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T { + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T { // SAFETY: The safety requirements of this method ensure that the object remains alive and // immutable for the duration of 'a. unsafe { &*ptr.cast() } } + + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T { + let ptr = ptr.cast(); + // SAFETY: The safety requirements of this method ensure that the pointer is valid and that + // nothing else will access the value for the duration of 'a. + unsafe { &mut *ptr } + } } impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> @@ -377,19 +385,20 @@ where A: Allocator, { type Borrowed<'a> = Pin<&'a T>; + type BorrowedMut<'a> = Pin<&'a mut T>; - fn into_foreign(self) -> *const crate::ffi::c_void { + fn into_foreign(self) -> *mut crate::ffi::c_void { // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() } - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } + unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) } } - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> { + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for @@ -399,6 +408,18 @@ where // SAFETY: This pointer originates from a `Pin<Box<T>>`. unsafe { Pin::new_unchecked(r) } } + + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut T> { + let ptr = ptr.cast(); + // SAFETY: The safety requirements for this function ensure that the object is still alive, + // so it is safe to dereference the raw pointer. + // The safety requirements of `from_foreign` also ensure that the object remains alive for + // the lifetime of the returned value. + let r = unsafe { &mut *ptr }; + + // SAFETY: This pointer originates from a `Pin<Box<T>>`. + unsafe { Pin::new_unchecked(r) } + } } impl<T, A> Deref for Box<T, A> @@ -427,13 +448,23 @@ where } } +impl<T, A> fmt::Display for Box<T, A> +where + T: ?Sized + fmt::Display, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <T as fmt::Display>::fmt(&**self, f) + } +} + impl<T, A> fmt::Debug for Box<T, A> where T: ?Sized + fmt::Debug, A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) + <T as fmt::Debug>::fmt(&**self, f) } } diff --git a/rust/kernel/alloc/layout.rs b/rust/kernel/alloc/layout.rs index 4b3cd7fdc816..93ed514f7cc7 100644 --- a/rust/kernel/alloc/layout.rs +++ b/rust/kernel/alloc/layout.rs @@ -43,6 +43,25 @@ impl<T> ArrayLayout<T> { /// # Errors /// /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. + /// + /// # Examples + /// + /// ``` + /// # use kernel::alloc::layout::{ArrayLayout, LayoutError}; + /// let layout = ArrayLayout::<i32>::new(15)?; + /// assert_eq!(layout.len(), 15); + /// + /// // Errors because `len * size_of::<T>()` overflows. + /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize); + /// assert!(layout.is_err()); + /// + /// // Errors because `len * size_of::<i32>() > isize::MAX`, + /// // even though `len < isize::MAX`. + /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2); + /// assert!(layout.is_err()); + /// + /// # Ok::<(), Error>(()) + /// ``` pub const fn new(len: usize) -> Result<Self, LayoutError> { match len.checked_mul(core::mem::size_of::<T>()) { Some(size) if size <= ISIZE_MAX => { diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs index 798c4ae0bded..14806e1997fd 100644 --- a/rust/kernel/block/mq/gen_disk.rs +++ b/rust/kernel/block/mq/gen_disk.rs @@ -174,9 +174,9 @@ impl GenDiskBuilder { /// /// # Invariants /// -/// - `gendisk` must always point to an initialized and valid `struct gendisk`. -/// - `gendisk` was added to the VFS through a call to -/// `bindings::device_add_disk`. +/// - `gendisk` must always point to an initialized and valid `struct gendisk`. +/// - `gendisk` was added to the VFS through a call to +/// `bindings::device_add_disk`. pub struct GenDisk<T: Operations> { _tagset: Arc<TagSet<T>>, gendisk: *mut bindings::gendisk, diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs index c8646d0d9866..864ff379dc91 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -9,6 +9,7 @@ use crate::{ block::mq::request::RequestDataWrapper, block::mq::Request, error::{from_result, Result}, + prelude::*, types::ARef, }; use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering}; @@ -35,7 +36,7 @@ pub trait Operations: Sized { /// Called by the kernel to poll the device for completed requests. Only /// used for poll queues. fn poll() -> bool { - crate::build_error(crate::error::VTABLE_DEFAULT_ERROR) + build_error!(crate::error::VTABLE_DEFAULT_ERROR) } } diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index d7f175a05d99..00ddcc71dfa2 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -52,7 +52,7 @@ impl<T: Operations> TagSet<T> { numa_node: bindings::NUMA_NO_NODE, queue_depth: num_tags, cmd_size, - flags: bindings::BLK_MQ_F_SHOULD_MERGE, + flags: 0, driver_data: core::ptr::null_mut::<crate::ffi::c_void>(), nr_maps: num_maps, ..tag_set diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs index 9e37120bc69c..6331b15d7c4d 100644 --- a/rust/kernel/build_assert.rs +++ b/rust/kernel/build_assert.rs @@ -2,6 +2,9 @@ //! Build-time assert. +#[doc(hidden)] +pub use build_error::build_error; + /// Fails the build if the code path calling `build_error!` can possibly be executed. /// /// If the macro is executed in const context, `build_error!` will panic. @@ -11,7 +14,6 @@ /// # Examples /// /// ``` -/// # use kernel::build_error; /// #[inline] /// fn foo(a: usize) -> usize { /// a.checked_add(1).unwrap_or_else(|| build_error!("overflow")) @@ -23,10 +25,10 @@ #[macro_export] macro_rules! build_error { () => {{ - $crate::build_error("") + $crate::build_assert::build_error("") }}; ($msg:expr) => {{ - $crate::build_error($msg) + $crate::build_assert::build_error($msg) }}; } @@ -73,12 +75,12 @@ macro_rules! build_error { macro_rules! build_assert { ($cond:expr $(,)?) => {{ if !$cond { - $crate::build_error(concat!("assertion failed: ", stringify!($cond))); + $crate::build_assert::build_error(concat!("assertion failed: ", stringify!($cond))); } }}; ($cond:expr, $msg:expr) => {{ if !$cond { - $crate::build_error($msg); + $crate::build_assert::build_error($msg); } }}; } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index c926e0c2b852..d5e6a19ff6b7 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -173,10 +173,10 @@ impl Device { #[cfg(CONFIG_PRINTK)] unsafe { bindings::_dev_printk( - klevel as *const _ as *const core::ffi::c_char, + klevel as *const _ as *const crate::ffi::c_char, self.as_raw(), c_str!("%pA").as_char_ptr(), - &msg as *const _ as *const core::ffi::c_void, + &msg as *const _ as *const crate::ffi::c_void, ) }; } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 52c502432447..f6ecf09cb65f 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -4,9 +4,10 @@ //! //! C header: [`include/uapi/asm-generic/errno-base.h`](srctree/include/uapi/asm-generic/errno-base.h) -use crate::{alloc::AllocError, str::CStr}; - -use core::alloc::LayoutError; +use crate::{ + alloc::{layout::LayoutError, AllocError}, + str::CStr, +}; use core::fmt; use core::num::NonZeroI32; @@ -101,19 +102,16 @@ impl Error { /// It is a bug to pass an out-of-range `errno`. `EINVAL` would /// be returned in such a case. pub fn from_errno(errno: crate::ffi::c_int) -> Error { - if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { + if let Some(error) = Self::try_from_errno(errno) { + error + } else { // TODO: Make it a `WARN_ONCE` once available. crate::pr_warn!( "attempted to create `Error` with out of range `errno`: {}", errno ); - return code::EINVAL; + code::EINVAL } - - // INVARIANT: The check above ensures the type invariant - // will hold. - // SAFETY: `errno` is checked above to be in a valid range. - unsafe { Error::from_errno_unchecked(errno) } } /// Creates an [`Error`] from a kernel error code. @@ -153,11 +151,8 @@ impl Error { /// Returns the error encoded as a pointer. pub fn to_ptr<T>(self) -> *mut T { - #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. - unsafe { - bindings::ERR_PTR(self.0.get().into()) as *mut _ - } + unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ } } /// Returns a string representing the error, if one exists. diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index 13a374a5cdb7..c5162fdc95ff 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -12,7 +12,7 @@ use core::ptr::NonNull; /// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`, /// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`. struct FwFunc( - unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32, + unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32, ); impl FwFunc { diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 347049df556b..3f9236c1c9d5 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -290,9 +290,17 @@ macro_rules! stack_pin_init { /// /// ```rust,ignore /// # #![expect(clippy::disallowed_names)] -/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; +/// # use kernel::{ +/// # init, +/// # pin_init, +/// # stack_try_pin_init, +/// # init::*, +/// # sync::Mutex, +/// # new_mutex, +/// # alloc::AllocError, +/// # }; /// # use macros::pin_data; -/// # use core::{alloc::AllocError, pin::Pin}; +/// # use core::pin::Pin; /// #[pin_data] /// struct Foo { /// #[pin] @@ -316,9 +324,17 @@ macro_rules! stack_pin_init { /// /// ```rust,ignore /// # #![expect(clippy::disallowed_names)] -/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; +/// # use kernel::{ +/// # init, +/// # pin_init, +/// # stack_try_pin_init, +/// # init::*, +/// # sync::Mutex, +/// # new_mutex, +/// # alloc::AllocError, +/// # }; /// # use macros::pin_data; -/// # use core::{alloc::AllocError, pin::Pin}; +/// # use core::pin::Pin; /// #[pin_data] /// struct Foo { /// #[pin] @@ -1076,8 +1092,9 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> { /// ```rust /// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn}; /// let array: KBox<[usize; 1_000]> = -/// KBox::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL).unwrap(); +/// KBox::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL)?; /// assert_eq!(array.len(), 1_000); +/// # Ok::<(), Error>(()) /// ``` pub fn init_array_from_fn<I, const N: usize, T, E>( mut make_init: impl FnMut(usize) -> I, @@ -1120,8 +1137,9 @@ where /// ```rust /// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex}; /// let array: Arc<[Mutex<usize>; 1_000]> = -/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL).unwrap(); +/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL)?; /// assert_eq!(array.len(), 1_000); +/// # Ok::<(), Error>(()) /// ``` pub fn pin_init_array_from_fn<I, const N: usize, T, E>( mut make_init: impl FnMut(usize) -> I, diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index e1065a7551a3..545d1170ee63 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -13,11 +13,12 @@ #![no_std] #![feature(arbitrary_self_types)] -#![feature(coerce_unsized)] -#![feature(dispatch_from_dyn)] +#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(derive_coerce_pointee))] +#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))] +#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))] +#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))] #![feature(inline_const)] #![feature(lint_reasons)] -#![feature(unsize)] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. @@ -32,7 +33,8 @@ pub use ffi; pub mod alloc; #[cfg(CONFIG_BLOCK)] pub mod block; -mod build_assert; +#[doc(hidden)] +pub mod build_assert; pub mod cred; pub mod device; pub mod error; @@ -74,9 +76,6 @@ pub use bindings; pub use macros; pub use uapi; -#[doc(hidden)] -pub use build_error::build_error; - /// Prefix to appear before log messages printed from within the `kernel` crate. const __LOG_PREFIX: &[u8] = b"rust_kernel\0"; diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index 3483d8c232c4..13c50df37b89 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -7,7 +7,7 @@ use crate::alloc::{AllocError, Flags}; use crate::prelude::*; use crate::sync::{Arc, ArcBorrow, UniqueArc}; -use core::marker::{PhantomPinned, Unsize}; +use core::marker::PhantomPinned; use core::ops::Deref; use core::pin::Pin; use core::sync::atomic::{AtomicBool, Ordering}; @@ -159,6 +159,7 @@ pub use impl_list_arc_safe; /// /// [`List`]: crate::list::List #[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct ListArc<T, const ID: u64 = 0> where T: ListArcSafe<ID> + ?Sized, @@ -443,18 +444,20 @@ where // This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the // dynamically-sized type (DST) `U`. +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID> where - T: ListArcSafe<ID> + Unsize<U> + ?Sized, + T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized, U: ListArcSafe<ID> + ?Sized, { } // This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into // `ListArc<U>`. +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID> where - T: ListArcSafe<ID> + Unsize<U> + ?Sized, + T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized, U: ListArcSafe<ID> + ?Sized, { } diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 7e2a79b3ae26..b3a6cc50b240 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -11,16 +11,12 @@ use crate::{ bindings, error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, + ffi::{c_int, c_long, c_uint, c_ulong}, prelude::*, str::CStr, types::{ForeignOwnable, Opaque}, }; -use core::{ - ffi::{c_int, c_long, c_uint, c_ulong}, - marker::PhantomData, - mem::MaybeUninit, - pin::Pin, -}; +use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin}; /// Options for creating a misc device. #[derive(Copy, Clone)] @@ -120,7 +116,7 @@ pub trait MiscDevice { _cmd: u32, _arg: usize, ) -> Result<isize> { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Handler for ioctls. @@ -136,7 +132,7 @@ pub trait MiscDevice { _cmd: u32, _arg: usize, ) -> Result<isize> { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } } @@ -193,7 +189,7 @@ unsafe extern "C" fn fops_open<T: MiscDevice>( }; // SAFETY: The open call of a file owns the private data. - unsafe { (*file).private_data = ptr.into_foreign().cast_mut() }; + unsafe { (*file).private_data = ptr.into_foreign() }; 0 } @@ -229,7 +225,7 @@ unsafe extern "C" fn fops_ioctl<T: MiscDevice>( // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - match T::ioctl(device, cmd, arg as usize) { + match T::ioctl(device, cmd, arg) { Ok(ret) => ret as c_long, Err(err) => err.to_errno() as c_long, } @@ -249,7 +245,7 @@ unsafe extern "C" fn fops_compat_ioctl<T: MiscDevice>( // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - match T::compat_ioctl(device, cmd, arg as usize) { + match T::compat_ioctl(device, cmd, arg) { Ok(ret) => ret as c_long, Err(err) => err.to_errno() as c_long, } diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 2fbfb6a94c11..bb654a28dab3 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -587,17 +587,17 @@ pub trait Driver { /// Issues a PHY software reset. fn soft_reset(_dev: &mut Device) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Sets up device-specific structures during discovery. fn probe(_dev: &mut Device) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Probes the hardware to determine what abilities it has. fn get_features(_dev: &mut Device) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Returns true if this is a suitable driver for the given phydev. @@ -609,32 +609,32 @@ pub trait Driver { /// Configures the advertisement and resets auto-negotiation /// if auto-negotiation is enabled. fn config_aneg(_dev: &mut Device) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Determines the negotiated speed and duplex. fn read_status(_dev: &mut Device) -> Result<u16> { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Suspends the hardware, saving state if needed. fn suspend(_dev: &mut Device) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Resumes the hardware, restoring state if needed. fn resume(_dev: &mut Device) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Overrides the default MMD read function for reading a MMD register. fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16> { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Overrides the default MMD write function for writing a MMD register. fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Callback for notification of link change. @@ -837,7 +837,7 @@ impl DeviceMask { /// [::kernel::net::phy::create_phy_driver::<PhySample>()]; /// /// impl ::kernel::Module for Module { -/// fn init(module: &'static ThisModule) -> Result<Self> { +/// fn init(module: &'static ::kernel::ThisModule) -> Result<Self> { /// let drivers = unsafe { &mut DRIVERS }; /// let mut reg = ::kernel::net::phy::Registration::register( /// module, @@ -903,7 +903,7 @@ macro_rules! module_phy_driver { [$($crate::net::phy::create_phy_driver::<$driver>()),+]; impl $crate::Module for Module { - fn init(module: &'static ThisModule) -> Result<Self> { + fn init(module: &'static $crate::ThisModule) -> Result<Self> { // SAFETY: The anonymous constant guarantees that nobody else can access // the `DRIVERS` static. The array is used only in the C side. let drivers = unsafe { &mut DRIVERS }; diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index fdac6c375fe4..f6126aca33a6 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -57,9 +57,8 @@ impl Page { /// ``` /// use kernel::page::Page; /// - /// # fn dox() -> Result<(), kernel::alloc::AllocError> { /// let page = Page::alloc_page(GFP_KERNEL)?; - /// # Ok(()) } + /// # Ok::<(), kernel::alloc::AllocError>(()) /// ``` /// /// Allocate memory for a page and zero its contents. @@ -67,9 +66,8 @@ impl Page { /// ``` /// use kernel::page::Page; /// - /// # fn dox() -> Result<(), kernel::alloc::AllocError> { /// let page = Page::alloc_page(GFP_KERNEL | __GFP_ZERO)?; - /// # Ok(()) } + /// # Ok::<(), kernel::alloc::AllocError>(()) /// ``` pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> { // SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 9ab4e0b6cbc9..dde2e0649790 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -19,7 +19,7 @@ pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec} #[doc(no_inline)] pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable}; -pub use super::build_assert; +pub use super::{build_assert, build_error}; // `super::std_vendor` is hidden, which makes the macro inline for some reason. #[doc(no_inline)] diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index a28077a7cb30..b19ee490be58 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -107,7 +107,7 @@ pub unsafe fn call_printk( // SAFETY: TODO. unsafe { bindings::_printk( - format_string.as_ptr() as _, + format_string.as_ptr(), module_name.as_ptr(), &args as *const _ as *const c_void, ); @@ -128,7 +128,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) { #[cfg(CONFIG_PRINTK)] unsafe { bindings::_printk( - format_strings::CONT.as_ptr() as _, + format_strings::CONT.as_ptr(), &args as *const _ as *const c_void, ); } diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs index cb4415a12258..ee2731dad72d 100644 --- a/rust/kernel/rbtree.rs +++ b/rust/kernel/rbtree.rs @@ -36,17 +36,17 @@ use core::{ /// /// // Check the nodes we just inserted. /// { -/// assert_eq!(tree.get(&10).unwrap(), &100); -/// assert_eq!(tree.get(&20).unwrap(), &200); -/// assert_eq!(tree.get(&30).unwrap(), &300); +/// assert_eq!(tree.get(&10), Some(&100)); +/// assert_eq!(tree.get(&20), Some(&200)); +/// assert_eq!(tree.get(&30), Some(&300)); /// } /// /// // Iterate over the nodes we just inserted. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&10, &100)); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); -/// assert_eq!(iter.next().unwrap(), (&30, &300)); +/// assert_eq!(iter.next(), Some((&10, &100))); +/// assert_eq!(iter.next(), Some((&20, &200))); +/// assert_eq!(iter.next(), Some((&30, &300))); /// assert!(iter.next().is_none()); /// } /// @@ -61,9 +61,9 @@ use core::{ /// // Check that the tree reflects the replacement. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&10, &1000)); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); -/// assert_eq!(iter.next().unwrap(), (&30, &300)); +/// assert_eq!(iter.next(), Some((&10, &1000))); +/// assert_eq!(iter.next(), Some((&20, &200))); +/// assert_eq!(iter.next(), Some((&30, &300))); /// assert!(iter.next().is_none()); /// } /// @@ -73,9 +73,9 @@ use core::{ /// // Check that the tree reflects the update. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&10, &1000)); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); -/// assert_eq!(iter.next().unwrap(), (&30, &3000)); +/// assert_eq!(iter.next(), Some((&10, &1000))); +/// assert_eq!(iter.next(), Some((&20, &200))); +/// assert_eq!(iter.next(), Some((&30, &3000))); /// assert!(iter.next().is_none()); /// } /// @@ -85,8 +85,8 @@ use core::{ /// // Check that the tree reflects the removal. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); -/// assert_eq!(iter.next().unwrap(), (&30, &3000)); +/// assert_eq!(iter.next(), Some((&20, &200))); +/// assert_eq!(iter.next(), Some((&30, &3000))); /// assert!(iter.next().is_none()); /// } /// @@ -128,20 +128,20 @@ use core::{ /// // Check the nodes we just inserted. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&10, &100)); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); -/// assert_eq!(iter.next().unwrap(), (&30, &300)); +/// assert_eq!(iter.next(), Some((&10, &100))); +/// assert_eq!(iter.next(), Some((&20, &200))); +/// assert_eq!(iter.next(), Some((&30, &300))); /// assert!(iter.next().is_none()); /// } /// /// // Remove a node, getting back ownership of it. -/// let existing = tree.remove(&30).unwrap(); +/// let existing = tree.remove(&30); /// /// // Check that the tree reflects the removal. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&10, &100)); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); +/// assert_eq!(iter.next(), Some((&10, &100))); +/// assert_eq!(iter.next(), Some((&20, &200))); /// assert!(iter.next().is_none()); /// } /// @@ -155,9 +155,9 @@ use core::{ /// // Check that the tree reflect the new insertion. /// { /// let mut iter = tree.iter(); -/// assert_eq!(iter.next().unwrap(), (&10, &100)); -/// assert_eq!(iter.next().unwrap(), (&15, &150)); -/// assert_eq!(iter.next().unwrap(), (&20, &200)); +/// assert_eq!(iter.next(), Some((&10, &100))); +/// assert_eq!(iter.next(), Some((&15, &150))); +/// assert_eq!(iter.next(), Some((&20, &200))); /// assert!(iter.next().is_none()); /// } /// diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs index 2522868862a1..25d2b1ac3833 100644 --- a/rust/kernel/security.rs +++ b/rust/kernel/security.rs @@ -15,60 +15,56 @@ use crate::{ /// /// # Invariants /// -/// The `secdata` and `seclen` fields correspond to a valid security context as returned by a -/// successful call to `security_secid_to_secctx`, that has not yet been destroyed by calling -/// `security_release_secctx`. +/// The `ctx` field corresponds to a valid security context as returned by a successful call to +/// `security_secid_to_secctx`, that has not yet been destroyed by `security_release_secctx`. pub struct SecurityCtx { - secdata: *mut core::ffi::c_char, - seclen: usize, + ctx: bindings::lsm_context, } impl SecurityCtx { /// Get the security context given its id. pub fn from_secid(secid: u32) -> Result<Self> { - let mut secdata = core::ptr::null_mut(); - let mut seclen = 0u32; - // SAFETY: Just a C FFI call. The pointers are valid for writes. - to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut secdata, &mut seclen) })?; + // SAFETY: `struct lsm_context` can be initialized to all zeros. + let mut ctx: bindings::lsm_context = unsafe { core::mem::zeroed() }; + + // SAFETY: Just a C FFI call. The pointer is valid for writes. + to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut ctx) })?; // INVARIANT: If the above call did not fail, then we have a valid security context. - Ok(Self { - secdata, - seclen: seclen as usize, - }) + Ok(Self { ctx }) } /// Returns whether the security context is empty. pub fn is_empty(&self) -> bool { - self.seclen == 0 + self.ctx.len == 0 } /// Returns the length of this security context. pub fn len(&self) -> usize { - self.seclen + self.ctx.len as usize } /// Returns the bytes for this security context. pub fn as_bytes(&self) -> &[u8] { - let ptr = self.secdata; + let ptr = self.ctx.context; if ptr.is_null() { - debug_assert_eq!(self.seclen, 0); + debug_assert_eq!(self.len(), 0); // We can't pass a null pointer to `slice::from_raw_parts` even if the length is zero. return &[]; } // SAFETY: The call to `security_secid_to_secctx` guarantees that the pointer is valid for - // `seclen` bytes. Furthermore, if the length is zero, then we have ensured that the + // `self.len()` bytes. Furthermore, if the length is zero, then we have ensured that the // pointer is not null. - unsafe { core::slice::from_raw_parts(ptr.cast(), self.seclen) } + unsafe { core::slice::from_raw_parts(ptr.cast(), self.len()) } } } impl Drop for SecurityCtx { fn drop(&mut self) { - // SAFETY: By the invariant of `Self`, this frees a pointer that came from a successful + // SAFETY: By the invariant of `Self`, this frees a context that came from a successful // call to `security_secid_to_secctx` and has not yet been destroyed by // `security_release_secctx`. - unsafe { bindings::security_release_secctx(self.secdata, self.seclen as u32) }; + unsafe { bindings::security_release_secctx(&mut self.ctx) }; } } diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs index 6ca29d576d02..04947c672979 100644 --- a/rust/kernel/seq_file.rs +++ b/rust/kernel/seq_file.rs @@ -36,7 +36,7 @@ impl SeqFile { bindings::seq_printf( self.inner.get(), c_str!("%pA").as_char_ptr(), - &args as *const _ as *const core::ffi::c_void, + &args as *const _ as *const crate::ffi::c_void, ); } } diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index d04c12a1426d..28e2201604d6 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -39,12 +39,13 @@ impl fmt::Display for BStr { /// ``` /// # use kernel::{fmt, b_str, str::{BStr, CString}}; /// let ascii = b_str!("Hello, BStr!"); - /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{}", ascii))?; /// assert_eq!(s.as_bytes(), "Hello, BStr!".as_bytes()); /// /// let non_ascii = b_str!("🦀"); - /// let s = CString::try_from_fmt(fmt!("{}", non_ascii)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{}", non_ascii))?; /// assert_eq!(s.as_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes()); + /// # Ok::<(), kernel::error::Error>(()) /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for &b in &self.0 { @@ -70,12 +71,13 @@ impl fmt::Debug for BStr { /// # use kernel::{fmt, b_str, str::{BStr, CString}}; /// // Embedded double quotes are escaped. /// let ascii = b_str!("Hello, \"BStr\"!"); - /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?; /// assert_eq!(s.as_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes()); /// /// let non_ascii = b_str!("😺"); - /// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii))?; /// assert_eq!(s.as_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes()); + /// # Ok::<(), kernel::error::Error>(()) /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_char('"')?; @@ -189,7 +191,7 @@ impl CStr { // to a `NUL`-terminated C string. let len = unsafe { bindings::strlen(ptr) } + 1; // SAFETY: Lifetime guaranteed by the safety precondition. - let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; + let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len) }; // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. // As we have added 1 to `len`, the last byte is known to be `NUL`. unsafe { Self::from_bytes_with_nul_unchecked(bytes) } @@ -248,7 +250,7 @@ impl CStr { /// Returns a C pointer to the string. #[inline] pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char { - self.0.as_ptr() as _ + self.0.as_ptr() } /// Convert the string to a byte slice without the trailing `NUL` byte. @@ -273,8 +275,9 @@ impl CStr { /// /// ``` /// # use kernel::str::CStr; - /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?; /// assert_eq!(cstr.to_str(), Ok("foo")); + /// # Ok::<(), kernel::error::Error>(()) /// ``` #[inline] pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { @@ -384,12 +387,13 @@ impl fmt::Display for CStr { /// # use kernel::str::CStr; /// # use kernel::str::CString; /// let penguin = c_str!("🐧"); - /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{}", penguin))?; /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); /// /// let ascii = c_str!("so \"cool\""); - /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{}", ascii))?; /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); + /// # Ok::<(), kernel::error::Error>(()) /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for &c in self.as_bytes() { @@ -413,13 +417,14 @@ impl fmt::Debug for CStr { /// # use kernel::str::CStr; /// # use kernel::str::CString; /// let penguin = c_str!("🐧"); - /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{:?}", penguin))?; /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); /// /// // Embedded double quotes are escaped. /// let ascii = c_str!("so \"cool\""); - /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); + /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?; /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); + /// # Ok::<(), kernel::error::Error>(()) /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("\"")?; @@ -522,6 +527,7 @@ macro_rules! c_str { } #[cfg(test)] +#[expect(clippy::items_after_test_module)] mod tests { use super::*; @@ -547,7 +553,7 @@ mod tests { }) } - const ALL_ASCII_CHARS: &'static str = + const ALL_ASCII_CHARS: &str = "\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\ \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f \ !\"#$%&'()*+,-./0123456789:;<=>?@\ @@ -581,6 +587,7 @@ mod tests { fn test_cstr_as_str_unchecked() { let good_bytes = b"\xf0\x9f\x90\xA7\0"; let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); + // SAFETY: The contents come from a string literal which contains valid UTF-8. let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; assert_eq!(unchecked_str, "🐧"); } @@ -799,16 +806,17 @@ impl fmt::Write for Formatter { /// ``` /// use kernel::{str::CString, fmt}; /// -/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap(); +/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20))?; /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); /// /// let tmp = "testing"; -/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap(); +/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123))?; /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); /// /// // This fails because it has an embedded `NUL` byte. /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); /// assert_eq!(s.is_ok(), false); +/// # Ok::<(), kernel::error::Error>(()) /// ``` pub struct CString { buf: KVec<u8>, @@ -838,7 +846,7 @@ impl CString { // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) // so `f.bytes_written() - 1` doesn't underflow. - let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) }; + let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, f.bytes_written() - 1) }; if !ptr.is_null() { return Err(EINVAL); } diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 1eab7ebf25fd..dffdaad972ce 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -16,8 +16,8 @@ pub mod poll; pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; -pub use lock::mutex::{new_mutex, Mutex}; -pub use lock::spinlock::{new_spinlock, SpinLock}; +pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; +pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; pub use locked_by::LockedBy; /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index fa4509406ee9..3cefda7a4372 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -26,7 +26,7 @@ use crate::{ use core::{ alloc::Layout, fmt, - marker::{PhantomData, Unsize}, + marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, @@ -125,8 +125,18 @@ mod std_vendor; /// let coerced: Arc<dyn MyTrait> = obj; /// # Ok::<(), Error>(()) /// ``` +#[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct Arc<T: ?Sized> { ptr: NonNull<ArcInner<T>>, + // NB: this informs dropck that objects of type `ArcInner<T>` may be used in `<Arc<T> as + // Drop>::drop`. Note that dropck already assumes that objects of type `T` may be used in + // `<Arc<T> as Drop>::drop` and the distinction between `T` and `ArcInner<T>` is not presently + // meaningful with respect to dropck - but this may change in the future so this is left here + // out of an abundance of caution. + // + // See https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking + // for more detail on the semantics of dropck in the presence of `PhantomData`. _p: PhantomData<ArcInner<T>>, } @@ -172,10 +182,12 @@ impl<T: ?Sized> ArcInner<T> { // This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the // dynamically-sized type (DST) `U`. -impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {} +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {} // This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`. -impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {} +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {} // SAFETY: It is safe to send `Arc<T>` to another thread when the underlying `T` is `Sync` because // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs @@ -201,10 +213,11 @@ impl<T> Arc<T> { }; let inner = KBox::new(value, flags)?; + let inner = KBox::leak(inner).into(); // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new // `Arc` object. - Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) }) + Ok(unsafe { Self::from_inner(inner) }) } } @@ -331,26 +344,37 @@ impl<T: ?Sized> Arc<T> { impl<T: 'static> ForeignOwnable for Arc<T> { type Borrowed<'a> = ArcBorrow<'a, T>; + type BorrowedMut<'a> = Self::Borrowed<'a>; - fn into_foreign(self) -> *const crate::ffi::c_void { - ManuallyDrop::new(self).ptr.as_ptr() as _ + fn into_foreign(self) -> *mut crate::ffi::c_void { + ManuallyDrop::new(self).ptr.as_ptr().cast() } - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> { - // By the safety requirement of this function, we know that `ptr` came from - // a previous call to `Arc::into_foreign`. - let inner = NonNull::new(ptr as *mut ArcInner<T>).unwrap(); + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) }; + + // SAFETY: By the safety requirement of this function, we know that `ptr` came from + // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and + // holds a reference count increment that is transferrable to us. + unsafe { Self::from_inner(inner) } + } + + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) }; // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { - // SAFETY: By the safety requirement of this function, we know that `ptr` came from - // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and - // holds a reference count increment that is transferrable to us. - unsafe { Self::from_inner(NonNull::new(ptr as _).unwrap()) } + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety + // requirements for `borrow`. + unsafe { Self::borrow(ptr) } } } @@ -372,10 +396,14 @@ impl<T: ?Sized> AsRef<T> for Arc<T> { impl<T: ?Sized> Clone for Arc<T> { fn clone(&self) -> Self { + // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is + // safe to dereference it. + let refcount = unsafe { self.ptr.as_ref() }.refcount.get(); + // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero. // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is // safe to increment the refcount. - unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) }; + unsafe { bindings::refcount_inc(refcount) }; // SAFETY: We just incremented the refcount. This increment is now owned by the new `Arc`. unsafe { Self::from_inner(self.ptr) } @@ -471,6 +499,8 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> { /// obj.as_arc_borrow().use_reference(); /// # Ok::<(), Error>(()) /// ``` +#[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct ArcBorrow<'a, T: ?Sized + 'a> { inner: NonNull<ArcInner<T>>, _p: PhantomData<&'a ()>, @@ -478,7 +508,8 @@ pub struct ArcBorrow<'a, T: ?Sized + 'a> { // This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into // `ArcBorrow<U>`. -impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>> +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>> for ArcBorrow<'_, T> { } diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 41dcddac69e2..eb80048e0110 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -90,12 +90,20 @@ pub unsafe trait Backend { // SAFETY: The safety requirements ensure that the lock is initialised. *guard_state = unsafe { Self::lock(ptr) }; } + + /// Asserts that the lock is held using lockdep. + /// + /// # Safety + /// + /// Callers must ensure that [`Backend::init`] has been previously called. + unsafe fn assert_is_held(ptr: *mut Self::State); } /// A mutual exclusion primitive. /// /// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock /// [`Backend`] specified as the generic parameter `B`. +#[repr(C)] #[pin_data] pub struct Lock<T: ?Sized, B: Backend> { /// The kernel lock object. @@ -134,6 +142,28 @@ impl<T, B: Backend> Lock<T, B> { } } +impl<B: Backend> Lock<(), B> { + /// Constructs a [`Lock`] from a raw pointer. + /// + /// This can be useful for interacting with a lock which was initialised outside of Rust. + /// + /// # Safety + /// + /// The caller promises that `ptr` points to a valid initialised instance of [`State`] during + /// the whole lifetime of `'a`. + /// + /// [`State`]: Backend::State + pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a Self { + // SAFETY: + // - By the safety contract `ptr` must point to a valid initialised instance of `B::State` + // - Since the lock data type is `()` which is a ZST, `state` is the only non-ZST member of + // the struct + // - Combined with `#[repr(C)]`, this guarantees `Self` has an equivalent data layout to + // `B::State`. + unsafe { &*ptr.cast() } + } +} + impl<T: ?Sized, B: Backend> Lock<T, B> { /// Acquires the lock and gives the caller access to the data protected by it. pub fn lock(&self) -> Guard<'_, T, B> { @@ -211,7 +241,10 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { /// # Safety /// /// The caller must ensure that it owns the lock. - pub(crate) unsafe fn new(lock: &'a Lock<T, B>, state: B::GuardState) -> Self { + pub unsafe fn new(lock: &'a Lock<T, B>, state: B::GuardState) -> Self { + // SAFETY: The caller can only hold the lock if `Backend::init` has already been called. + unsafe { B::assert_is_held(lock.state.get()) }; + Self { lock, state, diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 0e946ebefce1..70cadbc2e8e2 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -86,6 +86,14 @@ pub use new_mutex; /// [`struct mutex`]: srctree/include/linux/mutex.h pub type Mutex<T> = super::Lock<T, MutexBackend>; +/// A [`Guard`] acquired from locking a [`Mutex`]. +/// +/// This is simply a type alias for a [`Guard`] returned from locking a [`Mutex`]. It will unlock +/// the [`Mutex`] upon being dropped. +/// +/// [`Guard`]: super::Guard +pub type MutexGuard<'a, T> = super::Guard<'a, T, MutexBackend>; + /// A kernel `struct mutex` lock backend. pub struct MutexBackend; @@ -126,4 +134,9 @@ unsafe impl super::Backend for MutexBackend { None } } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + unsafe { bindings::mutex_assert_is_held(ptr) } + } } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index 9f4d128bed98..ab2f8d075311 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -87,6 +87,14 @@ pub type SpinLock<T> = super::Lock<T, SpinLockBackend>; /// A kernel `spinlock_t` lock backend. pub struct SpinLockBackend; +/// A [`Guard`] acquired from locking a [`SpinLock`]. +/// +/// This is simply a type alias for a [`Guard`] returned from locking a [`SpinLock`]. It will unlock +/// the [`SpinLock`] upon being dropped. +/// +/// [`Guard`]: super::Guard +pub type SpinLockGuard<'a, T> = super::Guard<'a, T, SpinLockBackend>; + // SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. `relock` uses the // default implementation that always calls the same locking method. unsafe impl super::Backend for SpinLockBackend { @@ -125,4 +133,9 @@ unsafe impl super::Backend for SpinLockBackend { None } } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + unsafe { bindings::spin_assert_is_held(ptr) } + } } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index ec6457bb3084..0dfaf45a755c 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -19,35 +19,34 @@ use core::{ /// This trait is meant to be used in cases when Rust objects are stored in C objects and /// eventually "freed" back to Rust. pub trait ForeignOwnable: Sized { - /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and - /// [`ForeignOwnable::from_foreign`]. + /// Type used to immutably borrow a value that is currently foreign-owned. type Borrowed<'a>; + /// Type used to mutably borrow a value that is currently foreign-owned. + type BorrowedMut<'a>; + /// Converts a Rust-owned object to a foreign-owned one. /// /// The foreign representation is a pointer to void. There are no guarantees for this pointer. /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in - /// any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], - /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. - fn into_foreign(self) -> *const crate::ffi::c_void; - - /// Borrows a foreign-owned object. - /// - /// # Safety + /// any way except for [`from_foreign`], [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can + /// result in undefined behavior. /// - /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for - /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Self::Borrowed<'a>; + /// [`from_foreign`]: Self::from_foreign + /// [`try_from_foreign`]: Self::try_from_foreign + /// [`borrow`]: Self::borrow + /// [`borrow_mut`]: Self::borrow_mut + fn into_foreign(self) -> *mut crate::ffi::c_void; /// Converts a foreign-owned object back to a Rust-owned one. /// /// # Safety /// - /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for - /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for - /// this object must have been dropped. - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self; + /// The provided pointer must have been returned by a previous call to [`into_foreign`], and it + /// must not be passed to `from_foreign` more than once. + /// + /// [`into_foreign`]: Self::into_foreign + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self; /// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -56,9 +55,10 @@ pub trait ForeignOwnable: Sized { /// /// # Safety /// - /// `ptr` must either be null or satisfy the safety requirements for - /// [`ForeignOwnable::from_foreign`]. - unsafe fn try_from_foreign(ptr: *const crate::ffi::c_void) -> Option<Self> { + /// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`]. + /// + /// [`from_foreign`]: Self::from_foreign + unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option<Self> { if ptr.is_null() { None } else { @@ -67,18 +67,63 @@ pub trait ForeignOwnable: Sized { unsafe { Some(Self::from_foreign(ptr)) } } } + + /// Borrows a foreign-owned object immutably. + /// + /// This method provides a way to access a foreign-owned value from Rust immutably. It provides + /// you with exactly the same abilities as an `&Self` when the value is Rust-owned. + /// + /// # Safety + /// + /// The provided pointer must have been returned by a previous call to [`into_foreign`], and if + /// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of + /// the lifetime 'a. + /// + /// [`into_foreign`]: Self::into_foreign + /// [`from_foreign`]: Self::from_foreign + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; + + /// Borrows a foreign-owned object mutably. + /// + /// This method provides a way to access a foreign-owned value from Rust mutably. It provides + /// you with exactly the same abilities as an `&mut Self` when the value is Rust-owned, except + /// that the address of the object must not be changed. + /// + /// Note that for types like [`Arc`], an `&mut Arc<T>` only gives you immutable access to the + /// inner value, so this method also only provides immutable access in that case. + /// + /// In the case of `Box<T>`, this method gives you the ability to modify the inner `T`, but it + /// does not let you change the box itself. That is, you cannot change which allocation the box + /// points at. + /// + /// # Safety + /// + /// The provided pointer must have been returned by a previous call to [`into_foreign`], and if + /// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of + /// the lifetime 'a. + /// + /// The lifetime 'a must not overlap with the lifetime of any other call to [`borrow`] or + /// `borrow_mut` on the same object. + /// + /// [`into_foreign`]: Self::into_foreign + /// [`from_foreign`]: Self::from_foreign + /// [`borrow`]: Self::borrow + /// [`Arc`]: crate::sync::Arc + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a>; } impl ForeignOwnable for () { type Borrowed<'a> = (); + type BorrowedMut<'a> = (); - fn into_foreign(self) -> *const crate::ffi::c_void { + fn into_foreign(self) -> *mut crate::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } - unsafe fn borrow<'a>(_: *const crate::ffi::c_void) -> Self::Borrowed<'a> {} + unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} - unsafe fn from_foreign(_: *const crate::ffi::c_void) -> Self {} + unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} + unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a> {} } /// Runs a cleanup function/closure when dropped. @@ -434,7 +479,7 @@ impl<T: AlwaysRefCounted> ARef<T> { /// } /// /// let mut data = Empty {}; - /// let ptr = NonNull::<Empty>::new(&mut data as *mut _).unwrap(); + /// let ptr = NonNull::<Empty>::new(&mut data).unwrap(); /// # // SAFETY: TODO. /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref); diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index 05b0b8d13b10..719b0a48ff55 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -5,10 +5,10 @@ //! C header: [`include/linux/uaccess.h`](srctree/include/linux/uaccess.h) use crate::{ - alloc::Flags, + alloc::{Allocator, Flags}, bindings, error::Result, - ffi::{c_ulong, c_void}, + ffi::c_void, prelude::*, transmute::{AsBytes, FromBytes}, }; @@ -127,7 +127,7 @@ impl UserSlice { /// Reads the entirety of the user slice, appending it to the end of the provided buffer. /// /// Fails with [`EFAULT`] if the read happens on a bad address. - pub fn read_all(self, buf: &mut KVec<u8>, flags: Flags) -> Result { + pub fn read_all<A: Allocator>(self, buf: &mut Vec<u8, A>, flags: Flags) -> Result { self.reader().read_all(buf, flags) } @@ -224,13 +224,9 @@ impl UserSliceReader { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `out_ptr` points into a mutable slice of length `len_ulong`, so we may write + // SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write // that many bytes to it. - let res = - unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len_ulong) }; + let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) }; if res != 0 { return Err(EFAULT); } @@ -259,9 +255,6 @@ impl UserSliceReader { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; let mut out: MaybeUninit<T> = MaybeUninit::uninit(); // SAFETY: The local variable `out` is valid for writing `size_of::<T>()` bytes. // @@ -272,7 +265,7 @@ impl UserSliceReader { bindings::_copy_from_user( out.as_mut_ptr().cast::<c_void>(), self.ptr as *const c_void, - len_ulong, + len, ) }; if res != 0 { @@ -288,7 +281,7 @@ impl UserSliceReader { /// Reads the entirety of the user slice, appending it to the end of the provided buffer. /// /// Fails with [`EFAULT`] if the read happens on a bad address. - pub fn read_all(mut self, buf: &mut KVec<u8>, flags: Flags) -> Result { + pub fn read_all<A: Allocator>(mut self, buf: &mut Vec<u8, A>, flags: Flags) -> Result { let len = self.length; buf.reserve(len, flags)?; @@ -335,12 +328,9 @@ impl UserSliceWriter { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `data_ptr` points into an immutable slice of length `len_ulong`, so we may read + // SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read // that many bytes from it. - let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len_ulong) }; + let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) }; if res != 0 { return Err(EFAULT); } @@ -359,9 +349,6 @@ impl UserSliceWriter { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; // SAFETY: The reference points to a value of type `T`, so it is valid for reading // `size_of::<T>()` bytes. // @@ -372,7 +359,7 @@ impl UserSliceWriter { bindings::_copy_to_user( self.ptr as *mut c_void, (value as *const T).cast::<c_void>(), - len_ulong, + len, ) }; if res != 0 { diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index fd3e97192ed8..0cd100d2aefb 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -69,6 +69,7 @@ //! fn print_later(val: Arc<MyStruct>) { //! let _ = workqueue::system().enqueue(val); //! } +//! # print_later(MyStruct::new(42).unwrap()); //! ``` //! //! The following example shows how multiple `work_struct` fields can be used: @@ -126,6 +127,8 @@ //! fn print_2_later(val: Arc<MyStruct>) { //! let _ = workqueue::system().enqueue::<Arc<MyStruct>, 2>(val); //! } +//! # print_1_later(MyStruct::new(24, 25).unwrap()); +//! # print_2_later(MyStruct::new(41, 42).unwrap()); //! ``` //! //! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h) diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 4ab94e44adfe..d61bc6a56425 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -123,12 +123,12 @@ pub fn module(ts: TokenStream) -> TokenStream { /// used on the Rust side, it should not be possible to call the default /// implementation. This is done to ensure that we call the vtable methods /// through the C vtable, and not through the Rust vtable. Therefore, the -/// default implementation should call `kernel::build_error`, which prevents +/// default implementation should call `build_error!`, which prevents /// calls to this function at compile time: /// /// ```compile_fail /// # // Intentionally missing `use`s to simplify `rusttest`. -/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// build_error!(VTABLE_DEFAULT_ERROR) /// ``` /// /// Note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`]. @@ -145,11 +145,11 @@ pub fn module(ts: TokenStream) -> TokenStream { /// #[vtable] /// pub trait Operations: Send + Sync + Sized { /// fn foo(&self) -> Result<()> { -/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// build_error!(VTABLE_DEFAULT_ERROR) /// } /// /// fn bar(&self) -> Result<()> { -/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// build_error!(VTABLE_DEFAULT_ERROR) /// } /// } /// |