# Conflicts:
#	rust/kernel/lib.rs
#	rust/kernel/miscdevice.rs
#	rust/kernel/security.rs
This commit is contained in:
Stephen Rothwell 2025-01-14 15:46:33 +11:00
commit eddb1ca9ee
35 changed files with 423 additions and 215 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

@ -1575,7 +1575,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 @@ impl QrImage<'_> {
/// 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))
@ -2003,8 +2006,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 \
@ -363,10 +365,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
--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 $@
@ -383,7 +385,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)) \
@ -473,7 +475,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 @@ where
A: Allocator,
{
type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T;
fn into_foreign(self) -> *const crate::ffi::c_void {
Box::into_raw(self) as _
fn into_foreign(self) -> *mut crate::ffi::c_void {
Box::into_raw(self).cast()
}
unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self {
unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
unsafe { Box::from_raw(ptr as _) }
unsafe { Box::from_raw(ptr.cast()) }
}
unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T {
unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T {
// SAFETY: The safety requirements of this method ensure that the object remains alive and
// immutable for the duration of 'a.
unsafe { &*ptr.cast() }
}
unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T {
let ptr = ptr.cast();
// SAFETY: The safety requirements of this method ensure that the pointer is valid and that
// nothing else will access the value for the duration of 'a.
unsafe { &mut *ptr }
}
}
impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
@ -377,19 +385,20 @@ where
A: Allocator,
{
type Borrowed<'a> = Pin<&'a T>;
type BorrowedMut<'a> = Pin<&'a mut T>;
fn into_foreign(self) -> *const crate::ffi::c_void {
fn into_foreign(self) -> *mut crate::ffi::c_void {
// SAFETY: We are still treating the box as pinned.
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast()
}
unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self {
unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) }
unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) }
}
unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> {
unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> {
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
@ -399,6 +408,18 @@ where
// SAFETY: This pointer originates from a `Pin<Box<T>>`.
unsafe { Pin::new_unchecked(r) }
}
unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut T> {
let ptr = ptr.cast();
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
// the lifetime of the returned value.
let r = unsafe { &mut *ptr };
// SAFETY: This pointer originates from a `Pin<Box<T>>`.
unsafe { Pin::new_unchecked(r) }
}
}
impl<T, A> Deref for Box<T, A>
@ -427,13 +448,23 @@ where
}
}
impl<T, A> fmt::Display for Box<T, A>
where
T: ?Sized + fmt::Display,
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Display>::fmt(&**self, f)
}
}
impl<T, A> fmt::Debug for Box<T, A>
where
T: ?Sized + fmt::Debug,
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
<T as fmt::Debug>::fmt(&**self, f)
}
}

View File

@ -43,6 +43,25 @@ impl<T> ArrayLayout<T> {
/// # Errors
///
/// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`.
///
/// # Examples
///
/// ```
/// # use kernel::alloc::layout::{ArrayLayout, LayoutError};
/// let layout = ArrayLayout::<i32>::new(15)?;
/// assert_eq!(layout.len(), 15);
///
/// // Errors because `len * size_of::<T>()` overflows.
/// let layout = ArrayLayout::<i32>::new(isize::MAX as usize);
/// assert!(layout.is_err());
///
/// // Errors because `len * size_of::<i32>() > isize::MAX`,
/// // even though `len < isize::MAX`.
/// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2);
/// assert!(layout.is_err());
///
/// # Ok::<(), Error>(())
/// ```
pub const fn new(len: usize) -> Result<Self, LayoutError> {
match len.checked_mul(core::mem::size_of::<T>()) {
Some(size) if size <= ISIZE_MAX => {

View File

@ -174,9 +174,9 @@ impl GenDiskBuilder {
///
/// # Invariants
///
/// - `gendisk` must always point to an initialized and valid `struct gendisk`.
/// - `gendisk` was added to the VFS through a call to
/// `bindings::device_add_disk`.
/// - `gendisk` must always point to an initialized and valid `struct gendisk`.
/// - `gendisk` was added to the VFS through a call to
/// `bindings::device_add_disk`.
pub struct GenDisk<T: Operations> {
_tagset: Arc<TagSet<T>>,
gendisk: *mut bindings::gendisk,

View File

@ -9,6 +9,7 @@ use crate::{
block::mq::request::RequestDataWrapper,
block::mq::Request,
error::{from_result, Result},
prelude::*,
types::ARef,
};
use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering};
@ -35,7 +36,7 @@ pub trait Operations: Sized {
/// Called by the kernel to poll the device for completed requests. Only
/// used for poll queues.
fn poll() -> bool {
crate::build_error(crate::error::VTABLE_DEFAULT_ERROR)
build_error!(crate::error::VTABLE_DEFAULT_ERROR)
}
}

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 @@ impl Device {
#[cfg(CONFIG_PRINTK)]
unsafe {
bindings::_dev_printk(
klevel as *const _ as *const core::ffi::c_char,
klevel as *const _ as *const crate::ffi::c_char,
self.as_raw(),
c_str!("%pA").as_char_ptr(),
&msg as *const _ as *const core::ffi::c_void,
&msg as *const _ as *const crate::ffi::c_void,
)
};
}

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 @@ impl Error {
/// Returns the error encoded as a pointer.
pub fn to_ptr<T>(self) -> *mut T {
#[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
// SAFETY: `self.0` is a valid error due to its invariant.
unsafe {
bindings::ERR_PTR(self.0.get().into()) as *mut _
}
unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ }
}
/// Returns a string representing the error, if one exists.

View File

@ -12,7 +12,7 @@ use core::ptr::NonNull;
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
struct FwFunc(
unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32,
unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32,
);
impl FwFunc {

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 @@ where
/// ```rust
/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex};
/// let array: Arc<[Mutex<usize>; 1_000]> =
/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL).unwrap();
/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL)?;
/// assert_eq!(array.len(), 1_000);
/// # Ok::<(), Error>(())
/// ```
pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
mut make_init: impl FnMut(usize) -> I,

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)]
// Stable in Rust 1.83
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_mut_refs)]
@ -37,7 +38,8 @@ pub use ffi;
pub mod alloc;
#[cfg(CONFIG_BLOCK)]
pub mod block;
mod build_assert;
#[doc(hidden)]
pub mod build_assert;
pub mod cred;
pub mod device;
pub mod device_id;
@ -88,9 +90,6 @@ pub use bindings;
pub use macros;
pub use uapi;
#[doc(hidden)]
pub use build_error::build_error;
/// Prefix to appear before log messages printed from within the `kernel` crate.
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";

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 @@ pub use impl_list_arc_safe;
///
/// [`List`]: crate::list::List
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct ListArc<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
@ -443,18 +444,20 @@ where
// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}
// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
// `ListArc<U>`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}

View File

@ -12,18 +12,14 @@ use crate::{
bindings,
device::Device,
error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
ffi::{c_int, c_long, c_uint, c_ulong},
fs::File,
prelude::*,
seq_file::SeqFile,
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)]
@ -134,7 +130,7 @@ pub trait MiscDevice: Sized {
_cmd: u32,
_arg: usize,
) -> Result<isize> {
kernel::build_error!(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Handler for ioctls.
@ -151,7 +147,7 @@ pub trait MiscDevice: Sized {
_cmd: u32,
_arg: usize,
) -> Result<isize> {
kernel::build_error!(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Show info for this fd.
@ -160,7 +156,7 @@ pub trait MiscDevice: Sized {
_m: &SeqFile,
_file: &File,
) {
kernel::build_error!(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
}
@ -235,7 +231,7 @@ unsafe extern "C" fn fops_open<T: MiscDevice>(
// fops_* methods in this file, which all correctly cast the private data to the new type.
//
// SAFETY: The open call of a file can access the private data.
unsafe { (*raw_file).private_data = ptr.into_foreign().cast_mut() };
unsafe { (*raw_file).private_data = ptr.into_foreign() };
0
}
@ -279,7 +275,7 @@ unsafe extern "C" fn fops_ioctl<T: MiscDevice>(
// * There is no active fdget_pos region on the file on this thread.
let file = unsafe { File::from_raw_file(file) };
match T::ioctl(device, file, cmd, arg as usize) {
match T::ioctl(device, file, cmd, arg) {
Ok(ret) => ret as c_long,
Err(err) => err.to_errno() as c_long,
}
@ -304,7 +300,7 @@ unsafe extern "C" fn fops_compat_ioctl<T: MiscDevice>(
// * There is no active fdget_pos region on the file on this thread.
let file = unsafe { File::from_raw_file(file) };
match T::compat_ioctl(device, file, cmd, arg as usize) {
match T::compat_ioctl(device, file, 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 @@ pub trait Driver {
/// Configures the advertisement and resets auto-negotiation
/// if auto-negotiation is enabled.
fn config_aneg(_dev: &mut Device) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Determines the negotiated speed and duplex.
fn read_status(_dev: &mut Device) -> Result<u16> {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Suspends the hardware, saving state if needed.
fn suspend(_dev: &mut Device) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Resumes the hardware, restoring state if needed.
fn resume(_dev: &mut Device) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Overrides the default MMD read function for reading a MMD register.
fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16> {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Overrides the default MMD write function for writing a MMD register.
fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
build_error!(VTABLE_DEFAULT_ERROR)
}
/// Callback for notification of link change.

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 @@ pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec}
#[doc(no_inline)]
pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
pub use super::build_assert;
pub use super::{build_assert, build_error};
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
#[doc(no_inline)]

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 @@ use core::{
///
/// // Check the nodes we just inserted.
/// {
/// assert_eq!(tree.get(&10).unwrap(), &100);
/// assert_eq!(tree.get(&20).unwrap(), &200);
/// assert_eq!(tree.get(&30).unwrap(), &300);
/// assert_eq!(tree.get(&10), Some(&100));
/// assert_eq!(tree.get(&20), Some(&200));
/// assert_eq!(tree.get(&30), Some(&300));
/// }
///
/// // Iterate over the nodes we just inserted.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&10, &100));
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next().unwrap(), (&30, &300));
/// assert_eq!(iter.next(), Some((&10, &100)));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert_eq!(iter.next(), Some((&30, &300)));
/// assert!(iter.next().is_none());
/// }
///
@ -61,9 +61,9 @@ use core::{
/// // Check that the tree reflects the replacement.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&10, &1000));
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next().unwrap(), (&30, &300));
/// assert_eq!(iter.next(), Some((&10, &1000)));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert_eq!(iter.next(), Some((&30, &300)));
/// assert!(iter.next().is_none());
/// }
///
@ -73,9 +73,9 @@ use core::{
/// // Check that the tree reflects the update.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&10, &1000));
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next().unwrap(), (&30, &3000));
/// assert_eq!(iter.next(), Some((&10, &1000)));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert_eq!(iter.next(), Some((&30, &3000)));
/// assert!(iter.next().is_none());
/// }
///
@ -85,8 +85,8 @@ use core::{
/// // Check that the tree reflects the removal.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next().unwrap(), (&30, &3000));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert_eq!(iter.next(), Some((&30, &3000)));
/// assert!(iter.next().is_none());
/// }
///
@ -128,20 +128,20 @@ use core::{
/// // Check the nodes we just inserted.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&10, &100));
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next().unwrap(), (&30, &300));
/// assert_eq!(iter.next(), Some((&10, &100)));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert_eq!(iter.next(), Some((&30, &300)));
/// assert!(iter.next().is_none());
/// }
///
/// // Remove a node, getting back ownership of it.
/// let existing = tree.remove(&30).unwrap();
/// let existing = tree.remove(&30);
///
/// // Check that the tree reflects the removal.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&10, &100));
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next(), Some((&10, &100)));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert!(iter.next().is_none());
/// }
///
@ -155,9 +155,9 @@ use core::{
/// // Check that the tree reflect the new insertion.
/// {
/// let mut iter = tree.iter();
/// assert_eq!(iter.next().unwrap(), (&10, &100));
/// assert_eq!(iter.next().unwrap(), (&15, &150));
/// assert_eq!(iter.next().unwrap(), (&20, &200));
/// assert_eq!(iter.next(), Some((&10, &100)));
/// assert_eq!(iter.next(), Some((&15, &150)));
/// assert_eq!(iter.next(), Some((&20, &200)));
/// assert!(iter.next().is_none());
/// }
///

View File

@ -36,7 +36,7 @@ impl SeqFile {
bindings::seq_printf(
self.inner.get(),
c_str!("%pA").as_char_ptr(),
&args as *const _ as *const core::ffi::c_void,
&args as *const _ as *const crate::ffi::c_void,
);
}
}

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 @@ impl CStr {
// to a `NUL`-terminated C string.
let len = unsafe { bindings::strlen(ptr) } + 1;
// SAFETY: Lifetime guaranteed by the safety precondition.
let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) };
let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len) };
// SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
// As we have added 1 to `len`, the last byte is known to be `NUL`.
unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
@ -248,7 +250,7 @@ impl CStr {
/// Returns a C pointer to the string.
#[inline]
pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char {
self.0.as_ptr() as _
self.0.as_ptr()
}
/// Convert the string to a byte slice without the trailing `NUL` byte.
@ -273,8 +275,9 @@ impl CStr {
///
/// ```
/// # use kernel::str::CStr;
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
/// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// # Ok::<(), kernel::error::Error>(())
/// ```
#[inline]
pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
@ -384,12 +387,13 @@ impl fmt::Display for CStr {
/// # use kernel::str::CStr;
/// # use kernel::str::CString;
/// let penguin = c_str!("🐧");
/// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
/// let s = CString::try_from_fmt(fmt!("{}", penguin))?;
/// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
///
/// let ascii = c_str!("so \"cool\"");
/// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
/// let s = CString::try_from_fmt(fmt!("{}", ascii))?;
/// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for &c in self.as_bytes() {
@ -413,13 +417,14 @@ impl fmt::Debug for CStr {
/// # use kernel::str::CStr;
/// # use kernel::str::CString;
/// let penguin = c_str!("🐧");
/// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
/// let s = CString::try_from_fmt(fmt!("{:?}", penguin))?;
/// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
///
/// // Embedded double quotes are escaped.
/// let ascii = c_str!("so \"cool\"");
/// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
/// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?;
/// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("\"")?;
@ -522,6 +527,7 @@ macro_rules! c_str {
}
#[cfg(test)]
#[expect(clippy::items_after_test_module)]
mod tests {
use super::*;
@ -547,7 +553,7 @@ mod tests {
})
}
const ALL_ASCII_CHARS: &'static str =
const ALL_ASCII_CHARS: &str =
"\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\
\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f \
!\"#$%&'()*+,-./0123456789:;<=>?@\
@ -581,6 +587,7 @@ mod tests {
fn test_cstr_as_str_unchecked() {
let good_bytes = b"\xf0\x9f\x90\xA7\0";
let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
// SAFETY: The contents come from a string literal which contains valid UTF-8.
let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
assert_eq!(unchecked_str, "🐧");
}
@ -799,16 +806,17 @@ impl fmt::Write for Formatter {
/// ```
/// use kernel::{str::CString, fmt};
///
/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20))?;
/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
///
/// let tmp = "testing";
/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123))?;
/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
///
/// // This fails because it has an embedded `NUL` byte.
/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
/// assert_eq!(s.is_ok(), false);
/// # Ok::<(), kernel::error::Error>(())
/// ```
pub struct CString {
buf: KVec<u8>,
@ -838,7 +846,7 @@ impl CString {
// SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
// (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
// so `f.bytes_written() - 1` doesn't underflow.
let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, f.bytes_written() - 1) };
if !ptr.is_null() {
return Err(EINVAL);
}

View File

@ -26,7 +26,7 @@ use crate::{
use core::{
alloc::Layout,
fmt,
marker::{PhantomData, Unsize},
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
pin::Pin,
@ -125,8 +125,18 @@ mod std_vendor;
/// let coerced: Arc<dyn MyTrait> = obj;
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
// NB: this informs dropck that objects of type `ArcInner<T>` may be used in `<Arc<T> as
// Drop>::drop`. Note that dropck already assumes that objects of type `T` may be used in
// `<Arc<T> as Drop>::drop` and the distinction between `T` and `ArcInner<T>` is not presently
// meaningful with respect to dropck - but this may change in the future so this is left here
// out of an abundance of caution.
//
// See https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking
// for more detail on the semantics of dropck in the presence of `PhantomData`.
_p: PhantomData<ArcInner<T>>,
}
@ -172,10 +182,12 @@ impl<T: ?Sized> ArcInner<T> {
// This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
// This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
// SAFETY: It is safe to send `Arc<T>` to another thread when the underlying `T` is `Sync` because
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
@ -201,10 +213,11 @@ impl<T> Arc<T> {
};
let inner = KBox::new(value, flags)?;
let inner = KBox::leak(inner).into();
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
// `Arc` object.
Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) })
Ok(unsafe { Self::from_inner(inner) })
}
}
@ -331,26 +344,37 @@ impl<T: ?Sized> Arc<T> {
impl<T: 'static> ForeignOwnable for Arc<T> {
type Borrowed<'a> = ArcBorrow<'a, T>;
type BorrowedMut<'a> = Self::Borrowed<'a>;
fn into_foreign(self) -> *const crate::ffi::c_void {
ManuallyDrop::new(self).ptr.as_ptr() as _
fn into_foreign(self) -> *mut crate::ffi::c_void {
ManuallyDrop::new(self).ptr.as_ptr().cast()
}
unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> {
// By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`.
let inner = NonNull::new(ptr as *mut ArcInner<T>).unwrap();
unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
// holds a reference count increment that is transferrable to us.
unsafe { Self::from_inner(inner) }
}
unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
// SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive
// for the lifetime of the returned value.
unsafe { ArcBorrow::new(inner) }
}
unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self {
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
// holds a reference count increment that is transferrable to us.
unsafe { Self::from_inner(NonNull::new(ptr as _).unwrap()) }
unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
// requirements for `borrow`.
unsafe { Self::borrow(ptr) }
}
}
@ -372,10 +396,14 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
impl<T: ?Sized> Clone for Arc<T> {
fn clone(&self) -> Self {
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
// safe to dereference it.
let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
// INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
// safe to increment the refcount.
unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) };
unsafe { bindings::refcount_inc(refcount) };
// SAFETY: We just incremented the refcount. This increment is now owned by the new `Arc`.
unsafe { Self::from_inner(self.ptr) }
@ -471,6 +499,8 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// obj.as_arc_borrow().use_reference();
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
inner: NonNull<ArcInner<T>>,
_p: PhantomData<&'a ()>,
@ -478,7 +508,8 @@ pub struct ArcBorrow<'a, T: ?Sized + 'a> {
// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
// `ArcBorrow<U>`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
for ArcBorrow<'_, T>
{
}

View File

@ -19,35 +19,34 @@ use core::{
/// This trait is meant to be used in cases when Rust objects are stored in C objects and
/// eventually "freed" back to Rust.
pub trait ForeignOwnable: Sized {
/// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and
/// [`ForeignOwnable::from_foreign`].
/// Type used to immutably borrow a value that is currently foreign-owned.
type Borrowed<'a>;
/// Type used to mutably borrow a value that is currently foreign-owned.
type BorrowedMut<'a>;
/// Converts a Rust-owned object to a foreign-owned one.
///
/// The foreign representation is a pointer to void. There are no guarantees for this pointer.
/// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in
/// any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`],
/// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior.
fn into_foreign(self) -> *const crate::ffi::c_void;
/// Borrows a foreign-owned object.
/// 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 @@ pub trait ForeignOwnable: Sized {
unsafe { Some(Self::from_foreign(ptr)) }
}
}
/// Borrows a foreign-owned object immutably.
///
/// This method provides a way to access a foreign-owned value from Rust immutably. It provides
/// you with exactly the same abilities as an `&Self` when the value is Rust-owned.
///
/// # Safety
///
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
/// the lifetime 'a.
///
/// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign
unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>;
/// Borrows a foreign-owned object mutably.
///
/// This method provides a way to access a foreign-owned value from Rust mutably. It provides
/// you with exactly the same abilities as an `&mut Self` when the value is Rust-owned, except
/// that the address of the object must not be changed.
///
/// Note that for types like [`Arc`], an `&mut Arc<T>` only gives you immutable access to the
/// inner value, so this method also only provides immutable access in that case.
///
/// In the case of `Box<T>`, this method gives you the ability to modify the inner `T`, but it
/// does not let you change the box itself. That is, you cannot change which allocation the box
/// points at.
///
/// # Safety
///
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
/// the lifetime 'a.
///
/// The lifetime 'a must not overlap with the lifetime of any other call to [`borrow`] or
/// `borrow_mut` on the same object.
///
/// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign
/// [`borrow`]: Self::borrow
/// [`Arc`]: crate::sync::Arc
unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a>;
}
impl ForeignOwnable for () {
type Borrowed<'a> = ();
type BorrowedMut<'a> = ();
fn into_foreign(self) -> *const crate::ffi::c_void {
fn into_foreign(self) -> *mut crate::ffi::c_void {
core::ptr::NonNull::dangling().as_ptr()
}
unsafe fn borrow<'a>(_: *const crate::ffi::c_void) -> Self::Borrowed<'a> {}
unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {}
unsafe fn from_foreign(_: *const crate::ffi::c_void) -> Self {}
unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {}
unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a> {}
}
/// Runs a cleanup function/closure when dropped.
@ -445,7 +490,7 @@ impl<T: AlwaysRefCounted> ARef<T> {
/// }
///
/// let mut data = Empty {};
/// let ptr = NonNull::<Empty>::new(&mut data as *mut _).unwrap();
/// let ptr = NonNull::<Empty>::new(&mut data).unwrap();
/// # // SAFETY: TODO.
/// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
/// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);

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 @@ impl UserSlice {
/// Reads the entirety of the user slice, appending it to the end of the provided buffer.
///
/// Fails with [`EFAULT`] if the read happens on a bad address.
pub fn read_all(self, buf: &mut KVec<u8>, flags: Flags) -> Result {
pub fn read_all<A: Allocator>(self, buf: &mut Vec<u8, A>, flags: Flags) -> Result {
self.reader().read_all(buf, flags)
}
@ -224,13 +224,9 @@ impl UserSliceReader {
if len > self.length {
return Err(EFAULT);
}
let Ok(len_ulong) = c_ulong::try_from(len) else {
return Err(EFAULT);
};
// SAFETY: `out_ptr` points into a mutable slice of length `len_ulong`, so we may write
// SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write
// that many bytes to it.
let res =
unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len_ulong) };
let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) };
if res != 0 {
return Err(EFAULT);
}
@ -259,9 +255,6 @@ impl UserSliceReader {
if len > self.length {
return Err(EFAULT);
}
let Ok(len_ulong) = c_ulong::try_from(len) else {
return Err(EFAULT);
};
let mut out: MaybeUninit<T> = MaybeUninit::uninit();
// SAFETY: The local variable `out` is valid for writing `size_of::<T>()` bytes.
//
@ -272,7 +265,7 @@ impl UserSliceReader {
bindings::_copy_from_user(
out.as_mut_ptr().cast::<c_void>(),
self.ptr as *const c_void,
len_ulong,
len,
)
};
if res != 0 {
@ -288,7 +281,7 @@ impl UserSliceReader {
/// Reads the entirety of the user slice, appending it to the end of the provided buffer.
///
/// Fails with [`EFAULT`] if the read happens on a bad address.
pub fn read_all(mut self, buf: &mut KVec<u8>, flags: Flags) -> Result {
pub fn read_all<A: Allocator>(mut self, buf: &mut Vec<u8, A>, flags: Flags) -> Result {
let len = self.length;
buf.reserve(len, flags)?;
@ -335,12 +328,9 @@ impl UserSliceWriter {
if len > self.length {
return Err(EFAULT);
}
let Ok(len_ulong) = c_ulong::try_from(len) else {
return Err(EFAULT);
};
// SAFETY: `data_ptr` points into an immutable slice of length `len_ulong`, so we may read
// SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read
// that many bytes from it.
let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len_ulong) };
let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) };
if res != 0 {
return Err(EFAULT);
}
@ -359,9 +349,6 @@ impl UserSliceWriter {
if len > self.length {
return Err(EFAULT);
}
let Ok(len_ulong) = c_ulong::try_from(len) else {
return Err(EFAULT);
};
// SAFETY: The reference points to a value of type `T`, so it is valid for reading
// `size_of::<T>()` bytes.
//
@ -372,7 +359,7 @@ impl UserSliceWriter {
bindings::_copy_to_user(
self.ptr as *mut c_void,
(value as *const T).cast::<c_void>(),
len_ulong,
len,
)
};
if res != 0 {

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 @@ impl Drop for RustPrint {
}
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=$?