diff --git a/.clippy.toml b/.clippy.toml index e4c4eef10b28..815c94732ed7 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +msrv = "1.78.0" + check-private-items = true disallowed-macros = [ diff --git a/.gitignore b/.gitignore index 6839cf84acda..5937c74d3dc1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ *.dtb.S *.dtbo.S *.dwo +*.dylib *.elf *.gcno *.gcda diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst index 17c9f920f03d..3388a10f2dcc 100644 --- a/Documentation/kbuild/kbuild.rst +++ b/Documentation/kbuild/kbuild.rst @@ -91,6 +91,17 @@ HOSTRUSTFLAGS ------------- Additional flags to be passed to $(HOSTRUSTC) when building host programs. +PROCMACROLDFLAGS +---------------- +Flags to be passed when linking Rust proc macros. Since proc macros are loaded +by rustc at build time, they must be linked in a way that is compatible with +the rustc toolchain being used. + +For instance, it can be useful when rustc uses a different C library than +the one the user wants to use for host programs. + +If unset, it defaults to the flags passed when linking host programs. + HOSTLDFLAGS ----------- Additional flags to be passed when linking host programs. diff --git a/Makefile b/Makefile index b9464c88ac72..6a98b8c6a5f5 100644 --- a/Makefile +++ b/Makefile @@ -497,6 +497,7 @@ KBUILD_HOSTRUSTFLAGS := $(rust_common_flags) -O -Cstrip=debuginfo \ -Zallow-features= $(HOSTRUSTFLAGS) KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS) KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS) +KBUILD_PROCMACROLDFLAGS := $(or $(PROCMACROLDFLAGS),$(KBUILD_HOSTLDFLAGS)) # Make variables (CC, etc...) CPP = $(CC) -E @@ -621,7 +622,7 @@ export HOSTRUSTC KBUILD_HOSTRUSTFLAGS export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD -export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE +export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS KBUILD_PROCMACROLDFLAGS LDFLAGS_MODULE export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS @@ -1571,7 +1572,7 @@ MRPROPER_FILES += include/config include/generated \ certs/x509.genkey \ vmlinux-gdb.py \ rpmbuild \ - rust/libmacros.so + rust/libmacros.so rust/libmacros.dylib # clean - Delete most, but leave enough to build external modules # diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index ef2d490965ba..bcf248f69252 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -931,7 +931,7 @@ fn draw_all(&mut self, data: impl Iterator) { /// They must remain valid for the duration of the function call. #[no_mangle] pub unsafe extern "C" fn drm_panic_qr_generate( - url: *const i8, + url: *const kernel::ffi::c_char, data: *mut u8, data_len: usize, data_size: usize, diff --git a/init/Kconfig b/init/Kconfig index 5e5328506138..7fe82a46e88c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -129,6 +129,9 @@ config CC_HAS_COUNTED_BY # https://github.com/llvm/llvm-project/pull/112636 depends on !(CC_IS_CLANG && CLANG_VERSION < 190103) +config RUSTC_HAS_COERCE_POINTEE + def_bool RUSTC_VERSION >= 108400 + config PAHOLE_VERSION int default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE)) @@ -2000,8 +2003,10 @@ config BINDGEN_VERSION_TEXT string depends on RUST # The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0 - # (https://github.com/rust-lang/rust-bindgen/pull/2678). It can be removed when - # the minimum version is upgraded past that (0.69.1 already fixed the issue). + # (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0 + # (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed + # when the minimum version is upgraded past the latter (0.69.1 and 0.71.1 + # both fixed the issue). default "$(shell,$(BINDGEN) --version workaround-for-0.69.0 2>/dev/null)" # 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 - {$( + #[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::() + ); + )*} +} + +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/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 @@ impl ForeignOwnable for Box 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 ForeignOwnable for Pin> @@ -377,19 +385,20 @@ impl ForeignOwnable for Pin> 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 @@ unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> { // SAFETY: This pointer originates from a `Pin>`. 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>`. + unsafe { Pin::new_unchecked(r) } + } } impl Deref for Box @@ -427,13 +448,23 @@ fn deref_mut(&mut self) -> &mut T { } } +impl fmt::Display for Box +where + T: ?Sized + fmt::Display, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(&**self, f) + } +} + impl fmt::Debug for Box where T: ?Sized + fmt::Debug, A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) + ::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 @@ pub const fn empty() -> Self { /// # Errors /// /// When `len * size_of::()` overflows or when `len * size_of::() > isize::MAX`. + /// + /// # Examples + /// + /// ``` + /// # use kernel::alloc::layout::{ArrayLayout, LayoutError}; + /// let layout = ArrayLayout::::new(15)?; + /// assert_eq!(layout.len(), 15); + /// + /// // Errors because `len * size_of::()` overflows. + /// let layout = ArrayLayout::::new(isize::MAX as usize); + /// assert!(layout.is_err()); + /// + /// // Errors because `len * size_of::() > isize::MAX`, + /// // even though `len < isize::MAX`. + /// let layout = ArrayLayout::::new(isize::MAX as usize / 2); + /// assert!(layout.is_err()); + /// + /// # Ok::<(), Error>(()) + /// ``` pub const fn new(len: usize) -> Result { match len.checked_mul(core::mem::size_of::()) { 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 @@ pub fn build( /// /// # 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 { _tagset: Arc>, 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 @@ 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/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 @@ unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) { #[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 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t { /// Returns the error encoded as a pointer. pub fn to_ptr(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 @@ /// 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() -> impl Init, E> { /// ```rust /// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn}; /// let array: KBox<[usize; 1_000]> = -/// KBox::init::(init_array_from_fn(|i| i), GFP_KERNEL).unwrap(); +/// KBox::init::(init_array_from_fn(|i| i), GFP_KERNEL)?; /// assert_eq!(array.len(), 1_000); +/// # Ok::<(), Error>(()) /// ``` pub fn init_array_from_fn( mut make_init: impl FnMut(usize) -> I, @@ -1120,8 +1137,9 @@ pub fn init_array_from_fn( /// ```rust /// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex}; /// let array: Arc<[Mutex; 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( 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 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 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 @@ fn try_new_list_arc(&self) -> bool { /// /// [`List`]: crate::list::List #[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct ListArc where T: ListArcSafe + ?Sized, @@ -443,18 +444,20 @@ fn as_ref(&self) -> &Arc { // This is to allow coercion from `ListArc` to `ListArc` if `T` can be converted to the // dynamically-sized type (DST) `U`. +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] impl core::ops::CoerceUnsized> for ListArc where - T: ListArcSafe + Unsize + ?Sized, + T: ListArcSafe + core::marker::Unsize + ?Sized, U: ListArcSafe + ?Sized, { } // This is to allow `ListArc` to be dispatched on when `ListArc` can be coerced into // `ListArc`. +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] impl core::ops::DispatchFromDyn> for ListArc where - T: ListArcSafe + Unsize + ?Sized, + T: ListArcSafe + core::marker::Unsize + ?Sized, U: ListArcSafe + ?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 @@ fn ioctl( _cmd: u32, _arg: usize, ) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } /// Handler for ioctls. @@ -136,7 +132,7 @@ fn compat_ioctl( _cmd: u32, _arg: usize, ) -> Result { - kernel::build_error(VTABLE_DEFAULT_ERROR) + build_error!(VTABLE_DEFAULT_ERROR) } } @@ -193,7 +189,7 @@ impl VtableHelper { }; // 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 @@ impl VtableHelper { // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { ::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 @@ impl VtableHelper { // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { ::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..3ca36348a61b 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 @@ fn match_phy_device(_dev: &Device) -> bool { /// 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 { - 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 { - 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. 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 { // 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 @@ #[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 @@ /// /// // 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 @@ /// // 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 @@ /// // 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 @@ /// // 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 @@ /// // 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 @@ /// // 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..ea4c58c81703 100644 --- a/rust/kernel/security.rs +++ b/rust/kernel/security.rs @@ -19,7 +19,7 @@ /// successful call to `security_secid_to_secctx`, that has not yet been destroyed by calling /// `security_release_secctx`. pub struct SecurityCtx { - secdata: *mut core::ffi::c_char, + secdata: *mut crate::ffi::c_char, seclen: usize, } 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 @@ pub fn call_printf(&self, args: core::fmt::Arguments<'_>) { 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 @@ pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self { // 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 @@ pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut 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 @@ pub const fn as_bytes_with_nul(&self) -> &[u8] { /// /// ``` /// # 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 @@ macro_rules! format { }) } - 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 @@ fn test_cstr_to_str_panic() { 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 @@ fn write_str(&mut self, s: &str) -> fmt::Result { /// ``` /// 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, @@ -838,7 +846,7 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result { // 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/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 core::{ alloc::Layout, fmt, - marker::{PhantomData, Unsize}, + marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, @@ -125,8 +125,18 @@ /// let coerced: Arc = obj; /// # Ok::<(), Error>(()) /// ``` +#[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct Arc { ptr: NonNull>, + // NB: this informs dropck that objects of type `ArcInner` may be used in ` as + // Drop>::drop`. Note that dropck already assumes that objects of type `T` may be used in + // ` as Drop>::drop` and the distinction between `T` and `ArcInner` 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>, } @@ -172,10 +182,12 @@ unsafe fn container_of(ptr: *const T) -> NonNull> { // This is to allow coercion from `Arc` to `Arc` if `T` can be converted to the // dynamically-sized type (DST) `U`. -impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} // This is to allow `Arc` to be dispatched on when `Arc` can be coerced into `Arc`. -impl, U: ?Sized> core::ops::DispatchFromDyn> for Arc {} +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::DispatchFromDyn> for Arc {} // SAFETY: It is safe to send `Arc` 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 @@ pub fn new(contents: T, flags: Flags) -> Result { }; 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 @@ pub fn into_unique_or_drop(self) -> Option>> { impl ForeignOwnable for Arc { 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).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::>()) }; + + // 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::>()) }; // 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 @@ fn as_ref(&self) -> &T { impl Clone for Arc { 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 @@ fn from(item: Pin>) -> Self { /// 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>, _p: PhantomData<&'a ()>, @@ -478,7 +508,8 @@ pub struct ArcBorrow<'a, T: ?Sized + 'a> { // This is to allow `ArcBorrow` to be dispatched on when `ArcBorrow` can be coerced into // `ArcBorrow`. -impl, U: ?Sized> core::ops::DispatchFromDyn> +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::DispatchFromDyn> for ArcBorrow<'_, T> { } 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 @@ /// 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. + /// any way except for [`from_foreign`], [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can + /// result in undefined behavior. /// - /// # 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. - 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 { + /// `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 { if ptr.is_null() { None } else { @@ -67,18 +67,63 @@ unsafe fn try_from_foreign(ptr: *const crate::ffi::c_void) -> Option { 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` 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`, 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 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// } /// /// let mut data = Empty {}; - /// let ptr = NonNull::::new(&mut data as *mut _).unwrap(); + /// let ptr = NonNull::::new(&mut data).unwrap(); /// # // SAFETY: TODO. /// let data_ref: ARef = unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull = 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 @@ pub fn new(ptr: UserPtr, length: usize) -> Self { /// 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, flags: Flags) -> Result { + pub fn read_all(self, buf: &mut Vec, flags: Flags) -> Result { self.reader().read_all(buf, flags) } @@ -224,13 +224,9 @@ pub fn read_raw(&mut self, out: &mut [MaybeUninit]) -> Result { 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 @@ pub fn read(&mut self) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; let mut out: MaybeUninit = MaybeUninit::uninit(); // SAFETY: The local variable `out` is valid for writing `size_of::()` bytes. // @@ -272,7 +265,7 @@ pub fn read(&mut self) -> Result { bindings::_copy_from_user( out.as_mut_ptr().cast::(), self.ptr as *const c_void, - len_ulong, + len, ) }; if res != 0 { @@ -288,7 +281,7 @@ pub fn read(&mut self) -> Result { /// 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, flags: Flags) -> Result { + pub fn read_all(mut self, buf: &mut Vec, flags: Flags) -> Result { let len = self.length; buf.reserve(len, flags)?; @@ -335,12 +328,9 @@ pub fn write_slice(&mut self, data: &[u8]) -> Result { 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 @@ pub fn write(&mut self, value: &T) -> Result { 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::()` bytes. // @@ -372,7 +359,7 @@ pub fn write(&mut self, value: &T) -> Result { bindings::_copy_to_user( self.ptr as *mut c_void, (value as *const T).cast::(), - 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) { //! 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) { //! let _ = workqueue::system().enqueue::, 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) /// } /// } /// diff --git a/samples/rust/rust_print_main.rs b/samples/rust/rust_print_main.rs index aed90a6feecf..7e8af5f176a3 100644 --- a/samples/rust/rust_print_main.rs +++ b/samples/rust/rust_print_main.rs @@ -34,6 +34,24 @@ fn arc_print() -> Result { // Uses `dbg` to print, will move `c` (for temporary debugging purposes). dbg!(c); + { + // `Arc` can be used to delegate dynamic dispatch and the following is an example. + // Both `i32` and `&str` implement `Display`. This enables us to express a unified + // behaviour, contract or protocol on both `i32` and `&str` into a single `Arc` of + // type `Arc`. + + use core::fmt::Display; + fn arc_dyn_print(arc: &Arc) { + pr_info!("Arc says {arc}"); + } + + let a_i32_display: Arc = Arc::new(42i32, GFP_KERNEL)?; + let a_str_display: Arc = a.clone(); + + arc_dyn_print(&a_i32_display); + arc_dyn_print(&a_str_display); + } + // Pretty-prints the debug formatting with lower-case hexadecimal integers. pr_info!("{:#x?}", a); @@ -83,7 +101,7 @@ fn drop(&mut self) { } mod trace { - use core::ffi::c_int; + use kernel::ffi::c_int; kernel::declare_trace! { /// # Safety diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 09e1d166d8d2..aa8ea1a4dbe5 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -8,6 +8,7 @@ import json import logging import os import pathlib +import subprocess import sys def args_crates_cfgs(cfgs): @@ -35,8 +36,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): crates_cfgs = args_crates_cfgs(cfgs) def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): - crates_indexes[display_name] = len(crates) - crates.append({ + crate = { "display_name": display_name, "root_module": str(root_module), "is_workspace_member": is_workspace_member, @@ -47,7 +47,15 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): "env": { "RUST_MODFILE": "This is only for rust-analyzer" } - }) + } + if is_proc_macro: + proc_macro_dylib_name = subprocess.check_output( + [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"], + stdin=subprocess.DEVNULL, + ).decode('utf-8').strip() + crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}" + crates_indexes[display_name] = len(crates) + crates.append(crate) # First, the ones in `rust/` since they are a bit special. append_crate( @@ -70,7 +78,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): [], is_proc_macro=True, ) - crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so" append_crate( "build_error", diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh index 93c0ef7fb3fb..d2323de0692c 100755 --- a/scripts/rust_is_available.sh +++ b/scripts/rust_is_available.sh @@ -123,8 +123,10 @@ fi # Non-stable and distributions' versions may have a version suffix, e.g. `-dev`. # # The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0 -# (https://github.com/rust-lang/rust-bindgen/pull/2678). It can be removed when -# the minimum version is upgraded past that (0.69.1 already fixed the issue). +# (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0 +# (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed when +# the minimum version is upgraded past the latter (0.69.1 and 0.71.1 both fixed +# the issue). rust_bindings_generator_output=$( \ LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null ) || rust_bindings_generator_code=$?