1
0
Fork 0
mirror of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-01-22 07:53:11 -05:00

Rust changes for v6.14

Toolchain and infrastructure:
 
  - Finish the move to custom FFI integer types started in the previous
    cycle and finally map 'long' to 'isize' and 'char' to 'u8'. Do a few
    cleanups on top thanks to that.
 
  - Start to use 'derive(CoercePointee)' on Rust >= 1.84.0.
 
    This is a major milestone on the path to build the kernel using only
    stable Rust features. In particular, previously we were using the
    unstable features 'coerce_unsized', 'dispatch_from_dyn' and 'unsize',
    and now we will use the new 'derive_coerce_pointee' one, which is on
    track to stabilization. This new feature is a macro that essentially
    expands into code that internally uses the unstable features that we
    were using before, without having to expose those.
 
    With it, stable Rust users, including the kernel, will be able to
    build custom smart pointers that work with trait objects, e.g.:
 
        fn f(p: &Arc<dyn Display>) {
            pr_info!("{p}\n");
        }
 
        let a: Arc<dyn Display> = Arc::new(42i32, GFP_KERNEL)?;
        let b: Arc<dyn Display> = Arc::new("hello there", GFP_KERNEL)?;
 
        f(&a); // Prints "42".
        f(&b); // Prints "hello there".
 
    Together with the 'arbitrary_self_types' feature that we started
    using in the previous cycle, using our custom smart pointers like
    'Arc' will eventually only rely in stable Rust.
 
  - Introduce 'PROCMACROLDFLAGS' environment variable to allow to link
    Rust proc macros using different flags than those used for linking
    Rust host programs (e.g. when 'rustc' uses a different C library
    than the host programs' one), which Android needs.
 
  - Help kernel builds under macOS with Rust enabled by accomodating
    other naming conventions for dynamic libraries (i.e. '.so' vs.
    '.dylib') which are used for Rust procedural macros. The actual
    support for macOS (i.e. the rest of the pieces needed) is provided
    out-of-tree by others, following the policy used for other parts of
    the kernel by Kbuild.
 
  - Run Clippy for 'rusttest' code too and clean the bits it spotted.
 
  - Provide Clippy with the minimum supported Rust version to improve
    the suggestions it gives.
 
  - Document 'bindgen' 0.71.0 regression.
 
 'kernel' crate:
 
  - 'build_error!': move users of the hidden function to the documented
    macro, prevent such uses in the future by moving the function
    elsewhere and add the macro to the prelude.
 
  - 'types' module: add improved version of 'ForeignOwnable::borrow_mut'
    (which was removed in the past since it was problematic); change
    'ForeignOwnable' pointer type to '*mut'.
 
  - 'alloc' module: implement 'Display' for 'Box' and align the 'Debug'
    implementation to it; add example (doctest) for 'ArrayLayout::new()'.
 
  - 'sync' module: document 'PhantomData' in 'Arc'; use
    'NonNull::new_unchecked' in 'ForeignOwnable for Arc' impl.
 
  - 'uaccess' module: accept 'Vec's with different allocators in
    'UserSliceReader::read_all'.
 
  - 'workqueue' module: enable run-testing a couple more doctests.
 
  - 'error' module: simplify 'from_errno()'.
 
  - 'block' module: fix formatting in code documentation (a lint to catch
    these is being implemented).
 
  - Avoid 'unwrap()'s in doctests, which also improves the examples by
    showing how kernel code is supposed to be written.
 
  - Avoid 'as' casts with 'cast{,_mut}' calls which are a bit safer.
 
 And a few other cleanups.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmeNeRsACgkQGXyLc2ht
 IW0exRAAx3ag/JaiR3n5aDBJqUX/Vi6/u+3fTiHOGp9oMFK4ZYR9rlWIr0ArU8a0
 4PApTR5ozrD+lgD1gCjHikhvpacLoTcz0WD0sP8qWlSqQFiMcTXmmWQfeJc7hheE
 4zyKlxswvbHjnOs/k24i5FS4E/CRpC7TJT5RkybaWVunsIps/im4xTnXfUzMhjVG
 SWcRaJtQA8xze9iiRlqw9EFQL6iT5gIKAe0I2i2J+zYzsY6m23fQ/8IxvglaiSDT
 /GIIqDscMH6drfQFRsvTtkcw0Mq64e6hlyWS9s4b9Q0IhgS0sju0qbQrfLLet75t
 1r+JlBZYhQy+4LXZTgBmQ8mVR8NEurnsOullm2AoTy6EYCPvXExSv4JCXYVvgPh+
 d4j/0pCeKUg9aDUtuEAUPHGQk1j7mORGf4J8jPQXla/7/YfqJvluycpMe54gLZpA
 FU24aqtb5/q3/Gqm8omKe/7FdYsu44E1haiP77bhNeYM3pWJrlIovBCafBtc1mQM
 lMtK6EjiQqrz1kEWutx+RQeeiir1G++GlVNGO2LSdNi/6qfjfBQM9dEqsCc8i3XL
 rsLL368SEKQENhSNJFceg6RX37WPwcyIkHAeZ91ijSz6W4I5HtUZpD3UPcgJoiaS
 xuOi44bR6Lt0zXF7eaXZTUh2gf8o++tsgfc4OZPaZ3azn6Y3pXw=
 =VLNX
 -----END PGP SIGNATURE-----

Merge tag 'rust-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux

Pull rust updates from Miguel Ojeda:
 "Toolchain and infrastructure:

   - Finish the move to custom FFI integer types started in the previous
     cycle and finally map 'long' to 'isize' and 'char' to 'u8'. Do a
     few cleanups on top thanks to that.

   - Start to use 'derive(CoercePointee)' on Rust >= 1.84.0.

     This is a major milestone on the path to build the kernel using
     only stable Rust features. In particular, previously we were using
     the unstable features 'coerce_unsized', 'dispatch_from_dyn' and
     'unsize', and now we will use the new 'derive_coerce_pointee' one,
     which is on track to stabilization. This new feature is a macro
     that essentially expands into code that internally uses the
     unstable features that we were using before, without having to
     expose those.

     With it, stable Rust users, including the kernel, will be able to
     build custom smart pointers that work with trait objects, e.g.:

         fn f(p: &Arc<dyn Display>) {
             pr_info!("{p}\n");
         }

         let a: Arc<dyn Display> = Arc::new(42i32, GFP_KERNEL)?;
         let b: Arc<dyn Display> = Arc::new("hello there", GFP_KERNEL)?;

         f(&a); // Prints "42".
         f(&b); // Prints "hello there".

     Together with the 'arbitrary_self_types' feature that we started
     using in the previous cycle, using our custom smart pointers like
     'Arc' will eventually only rely in stable Rust.

   - Introduce 'PROCMACROLDFLAGS' environment variable to allow to link
     Rust proc macros using different flags than those used for linking
     Rust host programs (e.g. when 'rustc' uses a different C library
     than the host programs' one), which Android needs.

   - Help kernel builds under macOS with Rust enabled by accomodating
     other naming conventions for dynamic libraries (i.e. '.so' vs.
     '.dylib') which are used for Rust procedural macros. The actual
     support for macOS (i.e. the rest of the pieces needed) is provided
     out-of-tree by others, following the policy used for other parts of
     the kernel by Kbuild.

   - Run Clippy for 'rusttest' code too and clean the bits it spotted.

   - Provide Clippy with the minimum supported Rust version to improve
     the suggestions it gives.

   - Document 'bindgen' 0.71.0 regression.

  'kernel' crate:

   - 'build_error!': move users of the hidden function to the documented
     macro, prevent such uses in the future by moving the function
     elsewhere and add the macro to the prelude.

   - 'types' module: add improved version of 'ForeignOwnable::borrow_mut'
     (which was removed in the past since it was problematic); change
     'ForeignOwnable' pointer type to '*mut'.

   - 'alloc' module: implement 'Display' for 'Box' and align the 'Debug'
     implementation to it; add example (doctest) for 'ArrayLayout::new()'

   - 'sync' module: document 'PhantomData' in 'Arc'; use
     'NonNull::new_unchecked' in 'ForeignOwnable for Arc' impl.

   - 'uaccess' module: accept 'Vec's with different allocators in
     'UserSliceReader::read_all'.

   - 'workqueue' module: enable run-testing a couple more doctests.

   - 'error' module: simplify 'from_errno()'.

   - 'block' module: fix formatting in code documentation (a lint to catch
     these is being implemented).

   - Avoid 'unwrap()'s in doctests, which also improves the examples by
     showing how kernel code is supposed to be written.

   - Avoid 'as' casts with 'cast{,_mut}' calls which are a bit safer.

  And a few other cleanups"

* tag 'rust-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (32 commits)
  kbuild: rust: add PROCMACROLDFLAGS
  rust: uaccess: generalize userSliceReader to support any Vec
  rust: kernel: add improved version of `ForeignOwnable::borrow_mut`
  rust: kernel: reorder `ForeignOwnable` items
  rust: kernel: change `ForeignOwnable` pointer to mut
  rust: arc: split unsafe block, add missing comment
  rust: types: avoid `as` casts
  rust: arc: use `NonNull::new_unchecked`
  rust: use derive(CoercePointee) on rustc >= 1.84.0
  rust: alloc: add doctest for `ArrayLayout::new()`
  rust: init: update `stack_try_pin_init` examples
  rust: error: import `kernel`'s `LayoutError` instead of `core`'s
  rust: str: replace unwraps with question mark operators
  rust: page: remove unnecessary helper function from doctest
  rust: rbtree: remove unwrap in asserts
  rust: init: replace unwraps with question mark operators
  rust: use host dylib naming convention to support macOS
  rust: add `build_error!` to the prelude
  rust: kernel: move `build_error` hidden function to prevent mistakes
  rust: use the `build_error!` macro, not the hidden function
  ...
This commit is contained in:
Linus Torvalds 2025-01-21 17:48:03 -08:00
commit e3610441d1
37 changed files with 437 additions and 217 deletions

View file

@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
msrv = "1.78.0"
check-private-items = true
disallowed-macros = [

1
.gitignore vendored
View file

@ -22,6 +22,7 @@
*.dtb.S
*.dtbo.S
*.dwo
*.dylib
*.elf
*.gcno
*.gcda

View file

@ -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.

View file

@ -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
#

View file

@ -931,7 +931,7 @@ fn draw_all(&mut self, data: impl Iterator<Item = u8>) {
/// 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,

View file

@ -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)"
#

View file

@ -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

View file

@ -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;

View file

@ -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.
///

View file

@ -354,22 +354,30 @@ impl<T: 'static, A> ForeignOwnable for Box<T, A>
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 @@ impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
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<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 @@ fn deref_mut(&mut self) -> &mut T {
}
}
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)
}
}

View file

@ -43,6 +43,25 @@ pub const fn empty() -> Self {
/// # 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 => {

View file

@ -174,9 +174,9 @@ pub fn build<T: Operations>(
///
/// # 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,

View file

@ -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)
}
}

View file

@ -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);
}
}};
}

View file

@ -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,
)
};
}

View file

@ -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<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.

View file

@ -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 {

View file

@ -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 @@ pub fn init_array_from_fn<I, const N: usize, T, E>(
/// ```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,

View file

@ -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";

View file

@ -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<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
@ -443,18 +444,20 @@ fn as_ref(&self) -> &Arc<T> {
// 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,
{
}

View file

@ -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<isize> {
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<isize> {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
}
@ -193,7 +189,7 @@ impl<T: MiscDevice> VtableHelper<T> {
};
// 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<T: MiscDevice> VtableHelper<T> {
// 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 @@ impl<T: MiscDevice> VtableHelper<T> {
// 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,
}

View file

@ -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<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.

View file

@ -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

View file

@ -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)]

View file

@ -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,
);
}

View file

@ -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());
/// }
///

View file

@ -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,
}

View file

@ -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,
);
}
}

View file

@ -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<u8>,
@ -838,7 +846,7 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
// 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);
}

View file

@ -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<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 @@ unsafe fn container_of(ptr: *const T) -> NonNull<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 @@ pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
};
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<Pin<UniqueArc<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 @@ fn as_ref(&self) -> &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 @@ fn from(item: Pin<UniqueArc<T>>) -> 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<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>
{
}

View file

@ -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<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 @@ unsafe fn try_from_foreign(ptr: *const crate::ffi::c_void) -> Option<Self> {
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 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
/// }
///
/// 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);

View file

@ -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<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 @@ pub fn read_raw(&mut self, out: &mut [MaybeUninit<u8>]) -> 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<T: FromBytes>(&mut self) -> Result<T> {
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 @@ pub fn read<T: FromBytes>(&mut self) -> Result<T> {
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 @@ pub fn read<T: FromBytes>(&mut self) -> Result<T> {
/// 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 @@ 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<T: AsBytes>(&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::<T>()` bytes.
//
@ -372,7 +359,7 @@ pub fn write<T: AsBytes>(&mut self, value: &T) -> Result {
bindings::_copy_to_user(
self.ptr as *mut c_void,
(value as *const T).cast::<c_void>(),
len_ulong,
len,
)
};
if res != 0 {

View file

@ -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)

View file

@ -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)
/// }
/// }
///

View file

@ -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<dyn Display>`.
use core::fmt::Display;
fn arc_dyn_print(arc: &Arc<dyn Display>) {
pr_info!("Arc<dyn Display> says {arc}");
}
let a_i32_display: Arc<dyn Display> = Arc::new(42i32, GFP_KERNEL)?;
let a_str_display: Arc<dyn Display> = 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

View file

@ -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",

View file

@ -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=$?