summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-13 09:54:20 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-13 09:54:20 -0700
commit26ff969926a08eee069767ddbbbc301adbcd9676 (patch)
treef54b18cf585550612ac9301bbae82c006978733f /rust
parent28483203f7d7fe4f123ed08266c381fac96b0701 (diff)
parent8a23051ed8584215b22368e9501f771ef98f0c1d (diff)
Merge tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Bump the minimum Rust version to 1.85.0 (and 'bindgen' to 0.71.1). As proposed in LPC 2025 and the Maintainers Summit [1], we are going to follow Debian Stable's Rust versions as our minimum versions. Debian Trixie was released on 2025-08-09 with a Rust 1.85.0 and 'bindgen' 0.71.1 toolchain, which is a fair amount of time for e.g. kernel developers to upgrade. Other major distributions support a Rust version that is high enough as well, including: + Arch Linux. + Fedora Linux. + Gentoo Linux. + Nix. + openSUSE Slowroll and openSUSE Tumbleweed. + Ubuntu 25.10 and 26.04 LTS. In addition, 24.04 LTS using their versioned packages. The merged patch series comes with the associated cleanups and simplifications treewide that can be performed thanks to both bumps, as well as documentation updates. In addition, start using 'bindgen''s '--with-attribute-custom-enum' feature to set the 'cfi_encoding' attribute for the 'lru_status' enum used in Binder. Link: https://lwn.net/Articles/1050174/ [1] - Add experimental Kconfig option ('CONFIG_RUST_INLINE_HELPERS') that inlines C helpers into Rust. Essentially, it performs a step similar to LTO, but just for the helpers, i.e. very local and fast. It relies on 'llvm-link' and its '--internalize' flag, and requires a compatible LLVM between Clang and 'rustc' (i.e. same major version, 'CONFIG_RUSTC_CLANG_LLVM_COMPATIBLE'). It is only enabled for two architectures for now. The result is a measurable speedup in different workloads that different users have tested. For instance, for the null block driver, it amounts to a 2%. - Support global per-version flags. While we already have per-version flags in many places, we didn't have a place to set global ones that depend on the compiler version, i.e. in 'rust_common_flags', which sometimes is needed to e.g. tweak the lints set per version. Use that to allow the 'clippy::precedence' lint for Rust < 1.86.0, since it had a change in behavior. - Support overriding the crate name and apply it to Rust Binder, which wanted the module to be called 'rust_binder'. - Add the remaining '__rust_helper' annotations (started in the previous cycle). 'kernel' crate: - Introduce the 'const_assert!' macro: a more powerful version of 'static_assert!' that can refer to generics inside functions or implementation bodies, e.g.: fn f<const N: usize>() { const_assert!(N > 1); } fn g<T>() { const_assert!(size_of::<T>() > 0, "T cannot be ZST"); } In addition, reorganize our set of build-time assertion macros ('{build,const,static_assert}!') to live in the 'build_assert' module. Finally, improve the docs as well to clarify how these are different from one another and how to pick the right one to use, and their equivalence (if any) to the existing C ones for extra clarity. - 'sizes' module: add 'SizeConstants' trait. This gives us typed 'SZ_*' constants (avoiding casts) for use in device address spaces where the address width depends on the hardware (e.g. 32-bit MMIO windows, 64-bit GPU framebuffers, etc.), e.g.: let gpu_heap = 14 * u64::SZ_1M; let mmio_window = u32::SZ_16M; - 'clk' module: implement 'Send' and 'Sync' for 'Clk' and thus simplify the users in Tyr and PWM. - 'ptr' module: add 'const_align_up'. - 'str' module: improve the documentation of the 'c_str!' macro to explain that one should only use it for non-literal cases (for the other case we instead use C string literals, e.g. 'c"abc"'). - Disallow the use of 'CStr::{as_ptr,from_ptr}' and clean one such use in the 'task' module. - 'sync' module: finish the move of 'ARef' and 'AlwaysRefCounted' outside of the 'types' module, i.e. update the last remaining instances and finally remove the re-exports. - 'error' module: clarify that 'from_err_ptr' can return 'Ok(NULL)', including runtime-tested examples. The intention is to hopefully prevent UB that assumes the result of the function is not 'NULL' if successful. This originated from a case of UB I noticed in 'regulator' that created a 'NonNull' on it. Timekeeping: - Expand the example section in the 'HrTimer' documentation. - Mark the 'ClockSource' trait as unsafe to ensure valid values for 'ktime_get()'. - Add 'Delta::from_nanos()'. 'pin-init' crate: - Replace the 'Zeroable' impls for 'Option<NonZero*>' with impls of 'ZeroableOption' for 'NonZero*'. - Improve feature gate handling for unstable features. - Declutter the documentation of implementations of 'Zeroable' for tuples. - Replace uses of 'addr_of[_mut]!' with '&raw [mut]'. rust-analyzer: - Add type annotations to 'generate_rust_analyzer.py'. - Add support for scripts written in Rust ('generate_rust_target.rs', 'rustdoc_test_builder.rs', 'rustdoc_test_gen.rs'). - Refactor 'generate_rust_analyzer.py' to explicitly identify host and target crates, improve readability, and reduce duplication. And some other fixes, cleanups and improvements" * tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (79 commits) rust: sizes: add SizeConstants trait for device address space constants rust: kernel: update `file_with_nul` comment rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0 rust: kbuild: support global per-version flags rust: declare cfi_encoding for lru_status docs: rust: general-information: use real example docs: rust: general-information: simplify Kconfig example docs: rust: quick-start: remove GDB/Binutils mention docs: rust: quick-start: remove Nix "unstable channel" note docs: rust: quick-start: remove Gentoo "testing" note docs: rust: quick-start: add Ubuntu 26.04 LTS and remove subsection title docs: rust: quick-start: update minimum Ubuntu version docs: rust: quick-start: update Ubuntu versioned packages docs: rust: quick-start: openSUSE provides `rust-src` package nowadays rust: kbuild: remove "dummy parameter" workaround for `bindgen` < 0.71.1 rust: kbuild: update `bindgen --rust-target` version and replace comment rust: rust_is_available: remove warning for `bindgen` < 0.69.5 && libclang >= 19.1 rust: rust_is_available: remove warning for `bindgen` 0.66.[01] rust: bump `bindgen` minimum supported version to 0.71.1 (Debian Trixie) rust: block: update `const_refs_to_static` MSRV TODO comment ...
Diffstat (limited to 'rust')
-rw-r--r--rust/Makefile69
-rw-r--r--rust/bindgen_parameters8
-rw-r--r--rust/bindings/bindings_helper.h1
-rw-r--r--rust/bindings/lib.rs5
-rw-r--r--rust/exports.c5
-rw-r--r--rust/helpers/clk.c24
-rw-r--r--rust/helpers/helpers.c29
-rw-r--r--rust/helpers/jump_label.c2
-rw-r--r--rust/kernel/alloc/allocator/iter.rs8
-rw-r--r--rust/kernel/alloc/kbox.rs29
-rw-r--r--rust/kernel/alloc/kvec/errors.rs3
-rw-r--r--rust/kernel/block/mq/gen_disk.rs4
-rw-r--r--rust/kernel/build_assert.rs183
-rw-r--r--rust/kernel/clk.rs7
-rw-r--r--rust/kernel/error.rs37
-rw-r--r--rust/kernel/i2c.rs13
-rw-r--r--rust/kernel/lib.rs38
-rw-r--r--rust/kernel/list.rs22
-rw-r--r--rust/kernel/list/arc.rs23
-rw-r--r--rust/kernel/list/arc_field.rs1
-rw-r--r--rust/kernel/list/impl_list_item_mod.rs3
-rw-r--r--rust/kernel/num/bounded.rs24
-rw-r--r--rust/kernel/prelude.rs110
-rw-r--r--rust/kernel/ptr.rs42
-rw-r--r--rust/kernel/sizes.rs172
-rw-r--r--rust/kernel/slice.rs49
-rw-r--r--rust/kernel/static_assert.rs39
-rw-r--r--rust/kernel/str.rs27
-rw-r--r--rust/kernel/sync/arc.rs21
-rw-r--r--rust/kernel/task.rs7
-rw-r--r--rust/kernel/time.rs32
-rw-r--r--rust/kernel/time/hrtimer.rs336
-rw-r--r--rust/kernel/transmute.rs35
-rw-r--r--rust/kernel/types.rs2
-rw-r--r--rust/kernel/usb.rs6
-rw-r--r--rust/kernel/xarray.rs1
-rw-r--r--rust/macros/helpers.rs1
-rw-r--r--rust/macros/kunit.rs9
-rw-r--r--rust/macros/lib.rs3
-rw-r--r--rust/macros/module.rs9
-rw-r--r--rust/pin-init/README.md3
-rw-r--r--rust/pin-init/examples/big_struct_in_place.rs3
-rw-r--r--rust/pin-init/examples/linked_list.rs3
-rw-r--r--rust/pin-init/examples/mutex.rs3
-rw-r--r--rust/pin-init/examples/pthread_mutex.rs3
-rw-r--r--rust/pin-init/examples/static_init.rs3
-rw-r--r--rust/pin-init/internal/src/init.rs14
-rw-r--r--rust/pin-init/internal/src/lib.rs2
-rw-r--r--rust/pin-init/src/lib.rs73
-rw-r--r--rust/uapi/lib.rs5
50 files changed, 1062 insertions, 489 deletions
diff --git a/rust/Makefile b/rust/Makefile
index 9801af2e1e02..b361bfedfdf0 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -6,15 +6,19 @@ rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h
+ifdef CONFIG_RUST_INLINE_HELPERS
+always-$(CONFIG_RUST) += helpers/helpers.bc helpers/helpers_module.bc
+else
+obj-$(CONFIG_RUST) += helpers/helpers.o
+always-$(CONFIG_RUST) += exports_helpers_generated.h
+endif
# Missing prototypes are expected in the helpers since these are exported
# for Rust only, thus there is no header nor prototypes.
-obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += bindings.o pin_init.o kernel.o
-always-$(CONFIG_RUST) += exports_helpers_generated.h \
- exports_bindings_generated.h exports_kernel_generated.h
+always-$(CONFIG_RUST) += exports_bindings_generated.h exports_kernel_generated.h
always-$(CONFIG_RUST) += uapi/uapi_generated.rs
obj-$(CONFIG_RUST) += uapi.o
@@ -71,8 +75,7 @@ core-edition := $(if $(call rustc-min-version,108700),2024,2021)
core-skip_flags := \
--edition=2021 \
- -Wunreachable_pub \
- -Wrustdoc::unescaped_backticks
+ -Wunreachable_pub
core-flags := \
--edition=$(core-edition) \
@@ -83,10 +86,8 @@ proc_macro2-cfgs := \
wrap_proc_macro \
$(if $(call rustc-min-version,108800),proc_macro_span_file proc_macro_span_location)
-# Stable since Rust 1.79.0: `feature(proc_macro_byte_character,proc_macro_c_str_literals)`.
proc_macro2-flags := \
--cap-lints=allow \
- -Zcrate-attr='feature(proc_macro_byte_character,proc_macro_c_str_literals)' \
$(call cfgs-to-flags,$(proc_macro2-cfgs))
quote-cfgs := \
@@ -118,7 +119,7 @@ syn-flags := \
$(call cfgs-to-flags,$(syn-cfgs))
pin_init_internal-cfgs := \
- kernel
+ kernel USE_RUSTC_FEATURES
pin_init_internal-flags := \
--extern proc_macro2 \
@@ -127,7 +128,7 @@ pin_init_internal-flags := \
$(call cfgs-to-flags,$(pin_init_internal-cfgs))
pin_init-cfgs := \
- kernel
+ kernel USE_RUSTC_FEATURES
pin_init-flags := \
--extern pin_init_internal \
@@ -141,15 +142,10 @@ rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-a
# Similarly, for doctests (https://github.com/rust-lang/rust/issues/146465).
doctests_modifiers_workaround := $(rustdoc_modifiers_workaround)$(if $(call rustc-min-version,109100),$(comma)sanitizer)
-# `rustc` recognizes `--remap-path-prefix` since 1.26.0, but `rustdoc` only
-# since Rust 1.81.0. Moreover, `rustdoc` ICEs on out-of-tree builds since Rust
-# 1.82.0 (https://github.com/rust-lang/rust/issues/138520). Thus workaround both
-# issues skipping the flag. The former also applies to `RUSTDOC TK`.
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --remap-path-scope=%, \
- $(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
+ $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj) \
-Zunstable-options --generate-link-to-definition \
--output $(rustdoc_output) \
@@ -210,8 +206,6 @@ rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
rustdoc-quote rustdoc-syn FORCE
+$(call if_changed,rustdoc)
-# Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
-# not be needed -- see https://github.com/rust-lang/rust/pull/128307.
rustdoc-core: private skip_flags = $(core-skip_flags)
rustdoc-core: private rustc_target_flags = $(core-flags)
rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs rustdoc-clean FORCE
@@ -335,7 +329,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) --test $(filter-out --remap-path-prefix=% --remap-path-scope=%,$(rust_flags)) \
+ $(RUSTDOC) --test $(filter-out --remap-path-scope=%,$(rust_flags)) \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
--extern bindings --extern uapi \
@@ -447,22 +441,10 @@ endif
# architecture instead of generating `usize`.
bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__
-# Each `bindgen` release may upgrade the list of Rust target versions. By
-# default, the highest stable release in their list is used. Thus we need to set
-# a `--rust-target` to avoid future `bindgen` releases emitting code that
-# `rustc` may not understand. On top of that, `bindgen` does not support passing
-# an unknown Rust target version.
-#
-# Therefore, the Rust target for `bindgen` can be only as high as the minimum
-# Rust version the kernel supports and only as high as the greatest stable Rust
-# target supported by the minimum `bindgen` version the kernel supports (that
-# is, if we do not test the actual `rustc`/`bindgen` versions running).
-#
-# Starting with `bindgen` 0.71.0, we will be able to set any future Rust version
-# instead, i.e. we will be able to set here our minimum supported Rust version.
+# `--rust-target` points to our minimum supported Rust version.
quiet_cmd_bindgen = BINDGEN $@
cmd_bindgen = \
- $(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.68 \
+ $(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.85 \
--use-core --with-derive-default --ctypes-prefix ffi --no-layout-tests \
--no-debug '.*' --enable-function-attribute-detection \
-o $@ -- $(bindgen_c_flags_final) -DMODULE \
@@ -496,6 +478,16 @@ $(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_extra = ;
$(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers/helpers.c FORCE
$(call if_changed_dep,bindgen)
+quiet_cmd_rust_helper = HELPER $@
+ cmd_rust_helper = \
+ $(CC) $(filter-out $(CFLAGS_REMOVE_helpers/helpers.o), $(c_flags)) \
+ -c -g0 $< -emit-llvm -o $@
+
+$(obj)/helpers/helpers.bc: private part-of-builtin := y
+$(obj)/helpers/helpers_module.bc: private part-of-module := y
+$(obj)/helpers/helpers.bc $(obj)/helpers/helpers_module.bc: $(src)/helpers/helpers.c FORCE
+ +$(call if_changed_dep,rust_helper)
+
rust_exports = $(NM) -p --defined-only $(1) | awk '$$2~/(T|R|D|B)/ && $$3!~/__(pfx|cfi|odr_asan)/ { printf $(2),$$3 }'
quiet_cmd_exports = EXPORTS $@
@@ -576,12 +568,16 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
OBJTREE=$(abspath $(objtree)) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_flags)) $(rustc_target_flags) \
- --emit=dep-info=$(depfile) --emit=obj=$@ \
+ --emit=dep-info=$(depfile) --emit=$(if $(link_helper),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) \
--emit=metadata=$(dir $@)$(patsubst %.o,lib%.rmeta,$(notdir $@)) \
--crate-type rlib -L$(objtree)/$(obj) \
--crate-name $(patsubst %.o,%,$(notdir $@)) $< \
--sysroot=/dev/null \
-Zunstable-options \
+ $(if $(link_helper),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
+ $(obj)/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
+ $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
+ $(cmd_ld_single)) \
$(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) \
$(cmd_objtool)
@@ -591,6 +587,8 @@ rust-analyzer:
--cfgs='proc_macro2=$(proc_macro2-cfgs)' \
--cfgs='quote=$(quote-cfgs)' \
--cfgs='syn=$(syn-cfgs)' \
+ --cfgs='pin_init_internal=$(pin_init_internal-cfgs)' \
+ --cfgs='pin_init=$(pin_init-cfgs)' \
$(realpath $(srctree)) $(realpath $(objtree)) \
$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
> rust-project.json
@@ -711,4 +709,9 @@ $(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generate
endif
endif
+ifdef CONFIG_RUST_INLINE_HELPERS
+$(obj)/kernel.o: private link_helper = 1
+$(obj)/kernel.o: $(obj)/helpers/helpers.bc
+endif
+
endif # CONFIG_RUST
diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters
index fd2fd1c3cb9a..6f02d9720ad2 100644
--- a/rust/bindgen_parameters
+++ b/rust/bindgen_parameters
@@ -15,14 +15,14 @@
--opaque-type x86_msi_data
--opaque-type x86_msi_addr_lo
-# `try` is a reserved keyword since Rust 2018; solved in `bindgen` v0.59.2,
-# commit 2aed6b021680 ("context: Escape the try keyword properly").
---opaque-type kunit_try_catch
-
# If SMP is disabled, `arch_spinlock_t` is defined as a ZST which triggers a Rust
# warning. We don't need to peek into it anyway.
--opaque-type spinlock
+# enums that appear in indirect function calls should specify a cfi type
+--newtype-enum lru_status
+--with-attribute-custom-enum=lru_status='#[cfi_encoding="10lru_status"]'
+
# `seccomp`'s comment gets understood as a doctest
--no-doc-comments
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 083cc44aa952..faf3ee634ced 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -149,5 +149,4 @@ const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;
#if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST)
#include "../../drivers/android/binder/rust_binder.h"
#include "../../drivers/android/binder/rust_binder_events.h"
-#include "../../drivers/android/binder/page_range_helper.h"
#endif
diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs
index 19f57c5b2fa2..854e7c471434 100644
--- a/rust/bindings/lib.rs
+++ b/rust/bindings/lib.rs
@@ -9,10 +9,6 @@
//! using this crate.
#![no_std]
-// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
-#![cfg_attr(test, allow(deref_nullptr))]
-#![cfg_attr(test, allow(unaligned_references))]
-#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
missing_docs,
@@ -23,6 +19,7 @@
unreachable_pub,
unsafe_op_in_unsafe_fn
)]
+#![feature(cfi_encoding)]
#[allow(dead_code)]
#[allow(clippy::cast_lossless)]
diff --git a/rust/exports.c b/rust/exports.c
index 587f0e776aba..1b52460b0f4e 100644
--- a/rust/exports.c
+++ b/rust/exports.c
@@ -16,10 +16,13 @@
#define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym)
#include "exports_core_generated.h"
-#include "exports_helpers_generated.h"
#include "exports_bindings_generated.h"
#include "exports_kernel_generated.h"
+#ifndef CONFIG_RUST_INLINE_HELPERS
+#include "exports_helpers_generated.h"
+#endif
+
// For modules using `rust/build_error.rs`.
#ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
EXPORT_SYMBOL_RUST_GPL(rust_build_error);
diff --git a/rust/helpers/clk.c b/rust/helpers/clk.c
index 6d04372c9f3b..15fd7e469cdd 100644
--- a/rust/helpers/clk.c
+++ b/rust/helpers/clk.c
@@ -7,60 +7,62 @@
* CONFIG_HAVE_CLK or CONFIG_HAVE_CLK_PREPARE aren't set.
*/
#ifndef CONFIG_HAVE_CLK
-struct clk *rust_helper_clk_get(struct device *dev, const char *id)
+__rust_helper struct clk *rust_helper_clk_get(struct device *dev,
+ const char *id)
{
return clk_get(dev, id);
}
-void rust_helper_clk_put(struct clk *clk)
+__rust_helper void rust_helper_clk_put(struct clk *clk)
{
clk_put(clk);
}
-int rust_helper_clk_enable(struct clk *clk)
+__rust_helper int rust_helper_clk_enable(struct clk *clk)
{
return clk_enable(clk);
}
-void rust_helper_clk_disable(struct clk *clk)
+__rust_helper void rust_helper_clk_disable(struct clk *clk)
{
clk_disable(clk);
}
-unsigned long rust_helper_clk_get_rate(struct clk *clk)
+__rust_helper unsigned long rust_helper_clk_get_rate(struct clk *clk)
{
return clk_get_rate(clk);
}
-int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate)
+__rust_helper int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate)
{
return clk_set_rate(clk, rate);
}
#endif
#ifndef CONFIG_HAVE_CLK_PREPARE
-int rust_helper_clk_prepare(struct clk *clk)
+__rust_helper int rust_helper_clk_prepare(struct clk *clk)
{
return clk_prepare(clk);
}
-void rust_helper_clk_unprepare(struct clk *clk)
+__rust_helper void rust_helper_clk_unprepare(struct clk *clk)
{
clk_unprepare(clk);
}
#endif
-struct clk *rust_helper_clk_get_optional(struct device *dev, const char *id)
+__rust_helper struct clk *rust_helper_clk_get_optional(struct device *dev,
+ const char *id)
{
return clk_get_optional(dev, id);
}
-int rust_helper_clk_prepare_enable(struct clk *clk)
+__rust_helper int rust_helper_clk_prepare_enable(struct clk *clk)
{
return clk_prepare_enable(clk);
}
-void rust_helper_clk_disable_unprepare(struct clk *clk)
+__rust_helper void rust_helper_clk_disable_unprepare(struct clk *clk)
{
clk_disable_unprepare(clk);
}
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index a3c42e51f00a..e05c6e7e4abb 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -7,7 +7,36 @@
* Sorted alphabetically.
*/
+#include <linux/compiler_types.h>
+
+#ifdef __BINDGEN__
+// Omit `inline` for bindgen as it ignores inline functions.
#define __rust_helper
+#else
+// The helper functions are all inline functions.
+//
+// We use `__always_inline` here to bypass LLVM inlining checks, in case the
+// helpers are inlined directly into Rust CGUs.
+//
+// The LLVM inlining checks are false positives:
+// * LLVM doesn't want to inline functions compiled with
+// `-fno-delete-null-pointer-checks` with code compiled without.
+// The C CGUs all have this enabled and Rust CGUs don't. Inlining is okay
+// since this is one of the hardening features that does not change the ABI,
+// and we shouldn't have null pointer dereferences in these helpers.
+// * LLVM doesn't want to inline functions with different list of builtins. C
+// side has `-fno-builtin-wcslen`; `wcslen` is not a Rust builtin, so they
+// should be compatible, but LLVM does not perform inlining due to attributes
+// mismatch.
+// * clang and Rust doesn't have the exact target string. Clang generates
+// `+cmov,+cx8,+fxsr` but Rust doesn't enable them (in fact, Rust will
+// complain if `-Ctarget-feature=+cmov,+cx8,+fxsr` is used). x86-64 always
+// enable these features, so they are in fact the same target string, but
+// LLVM doesn't understand this and so inlining is inhibited. This can be
+// bypassed with `--ignore-tti-inline-compatible`, but this is a hidden
+// option.
+#define __rust_helper __always_inline
+#endif
#include "atomic.c"
#include "atomic_ext.c"
diff --git a/rust/helpers/jump_label.c b/rust/helpers/jump_label.c
index fc1f1e0df08e..7ca384e73121 100644
--- a/rust/helpers/jump_label.c
+++ b/rust/helpers/jump_label.c
@@ -7,7 +7,7 @@
#include <linux/jump_label.h>
#ifndef CONFIG_JUMP_LABEL
-int rust_helper_static_key_count(struct static_key *key)
+__rust_helper int rust_helper_static_key_count(struct static_key *key)
{
return static_key_count(key);
}
diff --git a/rust/kernel/alloc/allocator/iter.rs b/rust/kernel/alloc/allocator/iter.rs
index 5759f86029b7..e0a70b7a744a 100644
--- a/rust/kernel/alloc/allocator/iter.rs
+++ b/rust/kernel/alloc/allocator/iter.rs
@@ -42,15 +42,9 @@ impl<'a> Iterator for VmallocPageIter<'a> {
return None;
}
- // TODO: Use `NonNull::add()` instead, once the minimum supported compiler version is
- // bumped to 1.80 or later.
- //
// SAFETY: `offset` is in the interval `[0, (self.page_count() - 1) * page::PAGE_SIZE]`,
// hence the resulting pointer is guaranteed to be within the same allocation.
- let ptr = unsafe { self.buf.as_ptr().add(offset) };
-
- // SAFETY: `ptr` is guaranteed to be non-null given that it is derived from `self.buf`.
- let ptr = unsafe { NonNull::new_unchecked(ptr) };
+ let ptr = unsafe { self.buf.add(offset) };
// SAFETY:
// - `ptr` is a valid pointer to a `Vmalloc` allocation.
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index 622b3529edfc..bd6da02c7ab8 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -77,33 +77,8 @@ use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
/// `self.0` is always properly aligned and either points to memory allocated with `A` or, for
/// zero-sized types, is a dangling, well aligned pointer.
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
-pub struct Box<#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, pointee)] T: ?Sized, A: Allocator>(
- NonNull<T>,
- PhantomData<A>,
-);
-
-// This is to allow coercion from `Box<T, A>` to `Box<U, A>` if `T` can be converted to the
-// dynamically-sized type (DST) `U`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T, U, A> core::ops::CoerceUnsized<Box<U, A>> for Box<T, A>
-where
- T: ?Sized + core::marker::Unsize<U>,
- U: ?Sized,
- A: Allocator,
-{
-}
-
-// This is to allow `Box<U, A>` to be dispatched on when `Box<T, A>` can be coerced into `Box<U,
-// A>`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T, U, A> core::ops::DispatchFromDyn<Box<U, A>> for Box<T, A>
-where
- T: ?Sized + core::marker::Unsize<U>,
- U: ?Sized,
- A: Allocator,
-{
-}
+#[derive(core::marker::CoercePointee)]
+pub struct Box<#[pointee] T: ?Sized, A: Allocator>(NonNull<T>, PhantomData<A>);
/// Type alias for [`Box`] with a [`Kmalloc`] allocator.
///
diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs
index e7de5049ee47..985c5f2c3962 100644
--- a/rust/kernel/alloc/kvec/errors.rs
+++ b/rust/kernel/alloc/kvec/errors.rs
@@ -15,6 +15,7 @@ impl<T> fmt::Debug for PushError<T> {
}
impl<T> From<PushError<T>> for Error {
+ #[inline]
fn from(_: PushError<T>) -> Error {
// Returning ENOMEM isn't appropriate because the system is not out of memory. The vector
// is just full and we are refusing to resize it.
@@ -32,6 +33,7 @@ impl fmt::Debug for RemoveError {
}
impl From<RemoveError> for Error {
+ #[inline]
fn from(_: RemoveError) -> Error {
EINVAL
}
@@ -55,6 +57,7 @@ impl<T> fmt::Debug for InsertError<T> {
}
impl<T> From<InsertError<T>> for Error {
+ #[inline]
fn from(_: InsertError<T>) -> Error {
EINVAL
}
diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs
index c8b0ecb17082..912cb805caf5 100644
--- a/rust/kernel/block/mq/gen_disk.rs
+++ b/rust/kernel/block/mq/gen_disk.rs
@@ -140,9 +140,7 @@ impl GenDiskBuilder {
devnode: None,
alternative_gpt_sector: None,
get_unique_id: None,
- // TODO: Set to THIS_MODULE. Waiting for const_refs_to_static feature to
- // be merged (unstable in rustc 1.78 which is staged for linux 6.10)
- // <https://github.com/rust-lang/rust/issues/119618>
+ // TODO: Set to `THIS_MODULE`.
owner: core::ptr::null_mut(),
pr_ops: core::ptr::null_mut(),
free_disk: None,
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
index f8124dbc663f..2ea2154ec30c 100644
--- a/rust/kernel/build_assert.rs
+++ b/rust/kernel/build_assert.rs
@@ -1,10 +1,144 @@
// SPDX-License-Identifier: GPL-2.0
-//! Build-time assert.
+//! Various assertions that happen during build-time.
+//!
+//! There are three types of build-time assertions that you can use:
+//! - [`static_assert!`]
+//! - [`const_assert!`]
+//! - [`build_assert!`]
+//!
+//! The ones towards the bottom of the list are more expressive, while the ones towards the top of
+//! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should
+//! prefer the ones towards the top of the list wherever possible.
+//!
+//! # Choosing the correct assertion
+//!
+//! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use
+//! [`static_assert!`] as it is the only assertion that can be used in that context.
+//!
+//! Inside bodies, if your assertion condition does not depend on any variable or generics, you
+//! should use [`static_assert!`]. If the condition depends on generics, but not variables
+//! (including function arguments), you should use [`const_assert!`]. Otherwise, use
+//! [`build_assert!`]. The same is true regardless if the function is `const fn`.
+//!
+//! ```
+//! // Outside any bodies.
+//! static_assert!(core::mem::size_of::<u8>() == 1);
+//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile.
+//!
+//! #[inline(always)]
+//! fn foo<const N: usize>(v: usize) {
+//! static_assert!(core::mem::size_of::<u8>() == 1); // Preferred.
+//! const_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
+//! build_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
+//!
+//! // `static_assert!(N > 1);` is not allowed.
+//! const_assert!(N > 1); // Preferred.
+//! build_assert!(N > 1); // Discouraged.
+//!
+//! // `static_assert!(v > 1);` is not allowed.
+//! // `const_assert!(v > 1);` is not allowed.
+//! build_assert!(v > 1); // Works.
+//! }
+//! ```
+//!
+//! # Detailed behavior
+//!
+//! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant
+//! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program
+//! is always evaluated, regardless if the function it appears in is used or not. This is also the
+//! only usable assertion outside a body.
+//!
+//! `const_assert!()` has no direct C equivalence. It is a more powerful version of
+//! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability
+//! to refer to generics, the assertion is tied to a specific instance of a function. So if it is
+//! used in a generic function that is not instantiated, the assertion will not be checked. For this
+//! reason, `static_assert!()` is preferred wherever possible.
+//!
+//! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than
+//! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this
+//! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be
+//! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended
+//! to avoid it and prefer other two assertions where possible.
+
+pub use crate::{
+ build_assert,
+ build_error,
+ const_assert,
+ static_assert, //
+};
#[doc(hidden)]
pub use build_error::build_error;
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// An optional panic message can be supplied after the expression.
+/// Currently only a string literal without formatting is supported
+/// due to constness limitations of the [`assert!`] macro.
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to
+/// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See
+/// the [module documentation](self).
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+/// x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+ ($condition:expr $(,$arg:literal)?) => {
+ const _: () = ::core::assert!($condition $(,$arg)?);
+ };
+}
+
+/// Assertion during constant evaluation.
+///
+/// This is a more powerful version of [`static_assert!`] that can refer to generics inside
+/// functions or implementation blocks. However, it also has a limitation where it can only appear
+/// in places where statements can appear; for example, you cannot use it as an item in the module.
+///
+/// [`static_assert!`] should be preferred if no generics are referred to in the condition. You
+/// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the
+/// capability, use [`build_assert!`]. See the [module documentation](self).
+///
+/// # Examples
+///
+/// ```
+/// fn foo<const N: usize>() {
+/// const_assert!(N > 1);
+/// }
+///
+/// fn bar<T>() {
+/// const_assert!(size_of::<T>() > 0, "T cannot be ZST");
+/// }
+/// ```
+#[macro_export]
+macro_rules! const_assert {
+ ($condition:expr $(,$arg:literal)?) => {
+ const { ::core::assert!($condition $(,$arg)?) };
+ };
+}
+
/// 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.
@@ -38,44 +172,33 @@ macro_rules! build_error {
/// will panic. If the compiler or optimizer cannot guarantee the condition will
/// be evaluated to `true`, a build error will be triggered.
///
-/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+/// When a condition depends on a function argument, the function must be annotated with
+/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
+/// function, preventing it from optimizing out the error path.
+///
+/// If the assertion condition does not depend on any variables or generics, you should use
+/// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on
+/// generics, you should use [`const_assert!`]. See the [module documentation](self).
///
/// # Examples
///
-/// These examples show that different types of [`assert!`] will trigger errors
-/// at different stage of compilation. It is preferred to err as early as
-/// possible, so [`static_assert!`] should be used whenever possible.
-/// ```ignore
-/// fn foo() {
-/// static_assert!(1 > 1); // Compile-time error
-/// build_assert!(1 > 1); // Build-time error
-/// assert!(1 > 1); // Run-time error
-/// }
/// ```
+/// #[inline(always)] // Important.
+/// fn bar(n: usize) {
+/// build_assert!(n > 1);
+/// }
///
-/// When the condition refers to generic parameters or parameters of an inline function,
-/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
-/// ```
-/// fn foo<const N: usize>() {
-/// // `static_assert!(N > 1);` is not allowed
-/// build_assert!(N > 1); // Build-time check
-/// assert!(N > 1); // Run-time check
+/// fn foo() {
+/// bar(2);
/// }
-/// ```
///
-/// When a condition depends on a function argument, the function must be annotated with
-/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
-/// function, preventing it from optimizing out the error path.
-/// ```
-/// #[inline(always)]
-/// fn bar(n: usize) {
-/// // `static_assert!(n > 1);` is not allowed
-/// build_assert!(n > 1); // Build-time check
-/// assert!(n > 1); // Run-time check
+/// #[inline(always)] // Important.
+/// const fn const_bar(n: usize) {
+/// build_assert!(n > 1);
/// }
-/// ```
///
-/// [`static_assert!`]: crate::static_assert!
+/// const _: () = const_bar(2);
+/// ```
#[macro_export]
macro_rules! build_assert {
($cond:expr $(,)?) => {{
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 4059aff34d09..7abbd0767d8c 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -128,6 +128,13 @@ mod common_clk {
#[repr(transparent)]
pub struct Clk(*mut bindings::clk);
+ // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called.
+ unsafe impl Send for Clk {}
+
+ // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the
+ // methods are synchronized internally.
+ unsafe impl Sync for Clk {}
+
impl Clk {
/// Gets [`Clk`] corresponding to a [`Device`] and a connection id.
///
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 258b12afdcba..decceb6ae855 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -216,36 +216,42 @@ impl fmt::Debug for Error {
}
impl From<AllocError> for Error {
+ #[inline]
fn from(_: AllocError) -> Error {
code::ENOMEM
}
}
impl From<TryFromIntError> for Error {
+ #[inline]
fn from(_: TryFromIntError) -> Error {
code::EINVAL
}
}
impl From<Utf8Error> for Error {
+ #[inline]
fn from(_: Utf8Error) -> Error {
code::EINVAL
}
}
impl From<LayoutError> for Error {
+ #[inline]
fn from(_: LayoutError) -> Error {
code::ENOMEM
}
}
impl From<fmt::Error> for Error {
+ #[inline]
fn from(_: fmt::Error) -> Error {
code::EINVAL
}
}
impl From<core::convert::Infallible> for Error {
+ #[inline]
fn from(e: core::convert::Infallible) -> Error {
match e {}
}
@@ -446,6 +452,9 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
/// for errors. This function performs the check and converts the "error pointer"
/// to a normal pointer in an idiomatic fashion.
///
+/// Note that a `NULL` pointer is not considered an error pointer, and is returned
+/// as-is, wrapped in [`Ok`].
+///
/// # Examples
///
/// ```ignore
@@ -460,6 +469,34 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
/// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) })
/// }
/// ```
+///
+/// ```
+/// # use kernel::error::from_err_ptr;
+/// # mod bindings {
+/// # #![expect(clippy::missing_safety_doc)]
+/// # use kernel::prelude::*;
+/// # pub(super) unsafe fn einval_err_ptr() -> *mut kernel::ffi::c_void {
+/// # EINVAL.to_ptr()
+/// # }
+/// # pub(super) unsafe fn null_ptr() -> *mut kernel::ffi::c_void {
+/// # core::ptr::null_mut()
+/// # }
+/// # pub(super) unsafe fn non_null_ptr() -> *mut kernel::ffi::c_void {
+/// # 0x1234 as *mut kernel::ffi::c_void
+/// # }
+/// # }
+/// // SAFETY: ...
+/// let einval_err = from_err_ptr(unsafe { bindings::einval_err_ptr() });
+/// assert_eq!(einval_err, Err(EINVAL));
+///
+/// // SAFETY: ...
+/// let null_ok = from_err_ptr(unsafe { bindings::null_ptr() });
+/// assert_eq!(null_ok, Ok(core::ptr::null_mut()));
+///
+/// // SAFETY: ...
+/// let non_null = from_err_ptr(unsafe { bindings::non_null_ptr() }).unwrap();
+/// assert_ne!(non_null, core::ptr::null_mut());
+/// ```
pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
// CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid.
let const_ptr: *const crate::ffi::c_void = ptr.cast();
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index bb5b830f48c3..7b908f0c5a58 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -16,10 +16,11 @@ use crate::{
error::*,
of,
prelude::*,
- types::{
- AlwaysRefCounted,
- Opaque, //
- }, //
+ sync::aref::{
+ ARef,
+ AlwaysRefCounted, //
+ },
+ types::Opaque, //
};
use core::{
@@ -31,8 +32,6 @@ use core::{
}, //
};
-use kernel::types::ARef;
-
/// An I2C device id table.
#[repr(transparent)]
#[derive(Clone, Copy)]
@@ -416,7 +415,7 @@ kernel::impl_device_context_deref!(unsafe { I2cAdapter });
kernel::impl_device_context_into_aref!(I2cAdapter);
// SAFETY: Instances of `I2cAdapter` are always reference-counted.
-unsafe impl crate::types::AlwaysRefCounted for I2cAdapter {
+unsafe impl AlwaysRefCounted for I2cAdapter {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::i2c_get_adapter(self.index()) };
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index d93292d47420..0fa9d820fe7c 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -16,45 +16,14 @@
// Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
// the unstable features in use.
//
-// Stable since Rust 1.79.0.
-#![feature(generic_nonzero)]
-#![feature(inline_const)]
-#![feature(pointer_is_aligned)]
-#![feature(slice_ptr_len)]
-//
-// Stable since Rust 1.80.0.
-#![feature(slice_flatten)]
-//
-// Stable since Rust 1.81.0.
-#![feature(lint_reasons)]
-//
-// Stable since Rust 1.82.0.
-#![feature(raw_ref_op)]
-//
-// Stable since Rust 1.83.0.
-#![feature(const_maybe_uninit_as_mut_ptr)]
-#![feature(const_mut_refs)]
-#![feature(const_option)]
-#![feature(const_ptr_write)]
-#![feature(const_refs_to_cell)]
-//
-// Stable since Rust 1.84.0.
-#![feature(strict_provenance)]
-//
// Expected to become stable.
#![feature(arbitrary_self_types)]
+#![feature(derive_coerce_pointee)]
//
// To be determined.
#![feature(used_with_arg)]
//
-// `feature(derive_coerce_pointee)` is expected to become stable. Before Rust
-// 1.84.0, it did not exist, so enable the predecessor features.
-#![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(file_with_nul)` is expected to become stable. Before Rust 1.89.0, it did not exist, so
+// `feature(file_with_nul)` is stable since Rust 1.92.0. Before Rust 1.89.0, it did not exist, so
// enable it conditionally.
#![cfg_attr(CONFIG_RUSTC_HAS_FILE_WITH_NUL, feature(file_with_nul))]
@@ -77,7 +46,6 @@ pub mod bits;
#[cfg(CONFIG_BLOCK)]
pub mod block;
pub mod bug;
-#[doc(hidden)]
pub mod build_assert;
pub mod clk;
#[cfg(CONFIG_CONFIGFS_FS)]
@@ -145,10 +113,8 @@ pub mod scatterlist;
pub mod security;
pub mod seq_file;
pub mod sizes;
-pub mod slice;
#[cfg(CONFIG_SOC_BUS)]
pub mod soc;
-mod static_assert;
#[doc(hidden)]
pub mod std_vendor;
pub mod str;
diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs
index 8349ff32fc37..406e3a028c55 100644
--- a/rust/kernel/list.rs
+++ b/rust/kernel/list.rs
@@ -12,15 +12,31 @@ use core::ptr;
use pin_init::PinInit;
mod impl_list_item_mod;
+#[doc(inline)]
pub use self::impl_list_item_mod::{
- impl_has_list_links, impl_has_list_links_self_ptr, impl_list_item, HasListLinks, HasSelfPtr,
+ impl_has_list_links,
+ impl_has_list_links_self_ptr,
+ impl_list_item,
+ HasListLinks,
+ HasSelfPtr, //
};
mod arc;
-pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
+#[doc(inline)]
+pub use self::arc::{
+ impl_list_arc_safe,
+ AtomicTracker,
+ ListArc,
+ ListArcSafe,
+ TryNewListArc, //
+};
mod arc_field;
-pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
+#[doc(inline)]
+pub use self::arc_field::{
+ define_list_arc_field_getter,
+ ListArcField, //
+};
/// A linked list.
///
diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs
index 2282f33913ee..a9a2b0178f65 100644
--- a/rust/kernel/list/arc.rs
+++ b/rust/kernel/list/arc.rs
@@ -82,6 +82,7 @@ pub unsafe trait TryNewListArc<const ID: u64 = 0>: ListArcSafe<ID> {
/// [`AtomicTracker`]. However, it is also possible to defer the tracking to another struct
/// using also using this macro.
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_list_arc_safe {
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => {
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
@@ -159,7 +160,7 @@ pub use impl_list_arc_safe;
///
/// [`List`]: crate::list::List
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
+#[derive(core::marker::CoercePointee)]
pub struct ListArc<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
@@ -442,26 +443,6 @@ 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> + 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> + core::marker::Unsize<U> + ?Sized,
- U: ListArcSafe<ID> + ?Sized,
-{
-}
-
/// A utility for tracking whether a [`ListArc`] exists using an atomic.
///
/// # Invariants
diff --git a/rust/kernel/list/arc_field.rs b/rust/kernel/list/arc_field.rs
index c4b9dd503982..2ad8aea55993 100644
--- a/rust/kernel/list/arc_field.rs
+++ b/rust/kernel/list/arc_field.rs
@@ -66,6 +66,7 @@ impl<T, const ID: u64> ListArcField<T, ID> {
/// Defines getters for a [`ListArcField`].
#[macro_export]
+#[doc(hidden)]
macro_rules! define_list_arc_field_getter {
($pub:vis fn $name:ident(&self $(<$id:tt>)?) -> &$typ:ty { $field:ident }
$($rest:tt)*
diff --git a/rust/kernel/list/impl_list_item_mod.rs b/rust/kernel/list/impl_list_item_mod.rs
index ee53d0387e63..5a3eac9f3cf0 100644
--- a/rust/kernel/list/impl_list_item_mod.rs
+++ b/rust/kernel/list/impl_list_item_mod.rs
@@ -29,6 +29,7 @@ pub unsafe trait HasListLinks<const ID: u64 = 0> {
/// Implements the [`HasListLinks`] trait for the given type.
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_has_list_links {
($(impl$({$($generics:tt)*})?
HasListLinks$(<$id:tt>)?
@@ -74,6 +75,7 @@ where
/// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type.
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_has_list_links_self_ptr {
($(impl$({$($generics:tt)*})?
HasSelfPtr<$item_type:ty $(, $id:tt)?>
@@ -181,6 +183,7 @@ pub use impl_has_list_links_self_ptr;
/// }
/// ```
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_list_item {
(
$(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty {
diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
index fa81acbdc8c2..54d0ce3ba595 100644
--- a/rust/kernel/num/bounded.rs
+++ b/rust/kernel/num/bounded.rs
@@ -255,9 +255,7 @@ macro_rules! impl_const_new {
/// ```
pub const fn new<const VALUE: $type>() -> Self {
// Statically assert that `VALUE` fits within the set number of bits.
- const {
- assert!(fits_within!(VALUE, $type, N));
- }
+ const_assert!(fits_within!(VALUE, $type, N));
// SAFETY: `fits_within` confirmed that `VALUE` can be represented within
// `N` bits.
@@ -287,12 +285,10 @@ where
/// The caller must ensure that `value` can be represented within `N` bits.
const unsafe fn __new(value: T) -> Self {
// Enforce the type invariants.
- const {
- // `N` cannot be zero.
- assert!(N != 0);
- // The backing type is at least as large as `N` bits.
- assert!(N <= T::BITS);
- }
+ // `N` cannot be zero.
+ const_assert!(N != 0);
+ // The backing type is at least as large as `N` bits.
+ const_assert!(N <= T::BITS);
// INVARIANT: The caller ensures `value` fits within `N` bits.
Self(value)
@@ -406,12 +402,10 @@ where
/// assert_eq!(larger_v, v);
/// ```
pub const fn extend<const M: u32>(self) -> Bounded<T, M> {
- const {
- assert!(
- M >= N,
- "Requested number of bits is less than the current representation."
- );
- }
+ const_assert!(
+ M >= N,
+ "Requested number of bits is less than the current representation."
+ );
// SAFETY: The value did fit within `N` bits, so it will all the more fit within
// the larger `M` bits.
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 2877e3f7b6d3..44edf72a4a24 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -13,43 +13,97 @@
#[doc(no_inline)]
pub use core::{
- mem::{align_of, align_of_val, size_of, size_of_val},
- pin::Pin,
+ mem::{
+ align_of,
+ align_of_val,
+ size_of,
+ size_of_val, //
+ },
+ pin::Pin, //
};
pub use ::ffi::{
- c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong,
- c_ushort, c_void, CStr,
+ c_char,
+ c_int,
+ c_long,
+ c_longlong,
+ c_schar,
+ c_short,
+ c_uchar,
+ c_uint,
+ c_ulong,
+ c_ulonglong,
+ c_ushort,
+ c_void,
+ CStr, //
};
-pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
-
#[doc(no_inline)]
-pub use macros::{export, fmt, kunit_tests, module, vtable};
+pub use macros::{
+ export,
+ fmt,
+ kunit_tests,
+ module,
+ vtable, //
+};
-pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
+pub use pin_init::{
+ init,
+ pin_data,
+ pin_init,
+ pinned_drop,
+ InPlaceWrite,
+ Init,
+ PinInit,
+ Zeroable, //
+};
-pub use super::{build_assert, build_error};
+pub use super::{
+ alloc::{
+ flags::*,
+ Box,
+ KBox,
+ KVBox,
+ KVVec,
+ KVec,
+ VBox,
+ VVec,
+ Vec, //
+ },
+ build_assert,
+ build_error,
+ const_assert,
+ current,
+ dev_alert,
+ dev_crit,
+ dev_dbg,
+ dev_emerg,
+ dev_err,
+ dev_info,
+ dev_notice,
+ dev_warn,
+ error::{
+ code::*,
+ Error,
+ Result, //
+ },
+ init::InPlaceInit,
+ pr_alert,
+ pr_crit,
+ pr_debug,
+ pr_emerg,
+ pr_err,
+ pr_info,
+ pr_notice,
+ pr_warn,
+ static_assert,
+ str::CStrExt as _,
+ try_init,
+ try_pin_init,
+ uaccess::UserPtr,
+ ThisModule, //
+};
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
#[doc(no_inline)]
pub use super::dbg;
-pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
-pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
-
-pub use super::{try_init, try_pin_init};
-
-pub use super::static_assert;
-
-pub use super::error::{code::*, Error, Result};
-
-pub use super::{str::CStrExt as _, ThisModule};
-
-pub use super::init::InPlaceInit;
-
-pub use super::current;
-
-pub use super::uaccess::UserPtr;
-
-#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
-pub use super::slice::AsFlattened;
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
index bdc2d79ff669..3f3e529e9f58 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -11,6 +11,8 @@ use core::mem::{
};
use core::num::NonZero;
+use crate::const_assert;
+
/// Type representing an alignment, which is always a power of two.
///
/// It is used to validate that a given value is a valid alignment, and to perform masking and
@@ -44,12 +46,10 @@ impl Alignment {
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> Self {
- const {
- assert!(
- ALIGN.is_power_of_two(),
- "Provided alignment is not a power of two."
- );
- }
+ const_assert!(
+ ALIGN.is_power_of_two(),
+ "Provided alignment is not a power of two."
+ );
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
@@ -87,7 +87,6 @@ impl Alignment {
/// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
#[inline(always)]
pub const fn of<T>() -> Self {
- #![allow(clippy::incompatible_msrv)]
// This cannot panic since alignments are always powers of two.
//
// We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
@@ -253,3 +252,32 @@ impl<T> KnownSize for [T] {
p.len() * size_of::<T>()
}
}
+
+/// Aligns `value` up to `align`.
+///
+/// This is the const-compatible equivalent of [`Alignable::align_up`].
+///
+/// Returns [`None`] on overflow.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::{
+/// ptr::{
+/// const_align_up,
+/// Alignment, //
+/// },
+/// sizes::SZ_4K, //
+/// };
+///
+/// assert_eq!(const_align_up(0x4f, Alignment::new::<16>()), Some(0x50));
+/// assert_eq!(const_align_up(0x40, Alignment::new::<16>()), Some(0x40));
+/// assert_eq!(const_align_up(1, Alignment::new::<SZ_4K>()), Some(SZ_4K));
+/// ```
+#[inline(always)]
+pub const fn const_align_up(value: usize, align: Alignment) -> Option<usize> {
+ match value.checked_add(align.as_usize() - 1) {
+ Some(v) => Some(v & align.mask()),
+ None => None,
+ }
+}
diff --git a/rust/kernel/sizes.rs b/rust/kernel/sizes.rs
index 661e680d9330..521b2b38bfe7 100644
--- a/rust/kernel/sizes.rs
+++ b/rust/kernel/sizes.rs
@@ -3,48 +3,132 @@
//! Commonly used sizes.
//!
//! C headers: [`include/linux/sizes.h`](srctree/include/linux/sizes.h).
+//!
+//! The top-level `SZ_*` constants are [`usize`]-typed, for use in kernel page
+//! arithmetic and similar CPU-side work.
+//!
+//! The [`SizeConstants`] trait provides the same constants as associated constants
+//! on [`u32`], [`u64`], and [`usize`], for use in device address spaces where
+//! the address width depends on the hardware. Device drivers frequently need
+//! these constants as [`u64`] (or [`u32`]) rather than [`usize`], because
+//! device address spaces are sized independently of the CPU pointer width.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::{
+//! page::PAGE_SIZE,
+//! sizes::{
+//! SizeConstants,
+//! SZ_1M, //
+//! }, //
+//! };
+//!
+//! // Module-level constants continue to work without a type qualifier.
+//! let num_pages_in_1m = SZ_1M / PAGE_SIZE;
+//!
+//! // Trait associated constants require a type qualifier.
+//! let heap_size = 14 * u64::SZ_1M;
+//! let small = u32::SZ_4K;
+//! ```
+
+macro_rules! define_sizes {
+ ($($type:ty),* $(,)?) => {
+ define_sizes!(@internal [$($type),*]
+ /// `0x0000_0400`.
+ SZ_1K,
+ /// `0x0000_0800`.
+ SZ_2K,
+ /// `0x0000_1000`.
+ SZ_4K,
+ /// `0x0000_2000`.
+ SZ_8K,
+ /// `0x0000_4000`.
+ SZ_16K,
+ /// `0x0000_8000`.
+ SZ_32K,
+ /// `0x0001_0000`.
+ SZ_64K,
+ /// `0x0002_0000`.
+ SZ_128K,
+ /// `0x0004_0000`.
+ SZ_256K,
+ /// `0x0008_0000`.
+ SZ_512K,
+ /// `0x0010_0000`.
+ SZ_1M,
+ /// `0x0020_0000`.
+ SZ_2M,
+ /// `0x0040_0000`.
+ SZ_4M,
+ /// `0x0080_0000`.
+ SZ_8M,
+ /// `0x0100_0000`.
+ SZ_16M,
+ /// `0x0200_0000`.
+ SZ_32M,
+ /// `0x0400_0000`.
+ SZ_64M,
+ /// `0x0800_0000`.
+ SZ_128M,
+ /// `0x1000_0000`.
+ SZ_256M,
+ /// `0x2000_0000`.
+ SZ_512M,
+ /// `0x4000_0000`.
+ SZ_1G,
+ /// `0x8000_0000`.
+ SZ_2G,
+ );
+ };
+
+ (@internal [$($type:ty),*] $($names_and_metas:tt)*) => {
+ define_sizes!(@consts_and_trait $($names_and_metas)*);
+ define_sizes!(@impls [$($type),*] $($names_and_metas)*);
+ };
+
+ (@consts_and_trait $($(#[$meta:meta])* $name:ident,)*) => {
+ $(
+ $(#[$meta])*
+ pub const $name: usize = bindings::$name as usize;
+ )*
+
+ /// Size constants for device address spaces.
+ ///
+ /// Implemented for [`u32`], [`u64`], and [`usize`] so drivers can
+ /// choose the width that matches their hardware. All `SZ_*` values fit
+ /// in a [`u32`], so all implementations are lossless.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::sizes::SizeConstants;
+ ///
+ /// let gpu_heap = 14 * u64::SZ_1M;
+ /// let mmio_window = u32::SZ_16M;
+ /// ```
+ pub trait SizeConstants {
+ $(
+ $(#[$meta])*
+ const $name: Self;
+ )*
+ }
+ };
+
+ (@impls [] $($(#[$meta:meta])* $name:ident,)*) => {};
+
+ (@impls [$first:ty $(, $rest:ty)*] $($(#[$meta:meta])* $name:ident,)*) => {
+ impl SizeConstants for $first {
+ $(
+ const $name: Self = {
+ assert!((self::$name as u128) <= (<$first>::MAX as u128));
+ self::$name as $first
+ };
+ )*
+ }
+
+ define_sizes!(@impls [$($rest),*] $($(#[$meta])* $name,)*);
+ };
+}
-/// 0x00000400
-pub const SZ_1K: usize = bindings::SZ_1K as usize;
-/// 0x00000800
-pub const SZ_2K: usize = bindings::SZ_2K as usize;
-/// 0x00001000
-pub const SZ_4K: usize = bindings::SZ_4K as usize;
-/// 0x00002000
-pub const SZ_8K: usize = bindings::SZ_8K as usize;
-/// 0x00004000
-pub const SZ_16K: usize = bindings::SZ_16K as usize;
-/// 0x00008000
-pub const SZ_32K: usize = bindings::SZ_32K as usize;
-/// 0x00010000
-pub const SZ_64K: usize = bindings::SZ_64K as usize;
-/// 0x00020000
-pub const SZ_128K: usize = bindings::SZ_128K as usize;
-/// 0x00040000
-pub const SZ_256K: usize = bindings::SZ_256K as usize;
-/// 0x00080000
-pub const SZ_512K: usize = bindings::SZ_512K as usize;
-/// 0x00100000
-pub const SZ_1M: usize = bindings::SZ_1M as usize;
-/// 0x00200000
-pub const SZ_2M: usize = bindings::SZ_2M as usize;
-/// 0x00400000
-pub const SZ_4M: usize = bindings::SZ_4M as usize;
-/// 0x00800000
-pub const SZ_8M: usize = bindings::SZ_8M as usize;
-/// 0x01000000
-pub const SZ_16M: usize = bindings::SZ_16M as usize;
-/// 0x02000000
-pub const SZ_32M: usize = bindings::SZ_32M as usize;
-/// 0x04000000
-pub const SZ_64M: usize = bindings::SZ_64M as usize;
-/// 0x08000000
-pub const SZ_128M: usize = bindings::SZ_128M as usize;
-/// 0x10000000
-pub const SZ_256M: usize = bindings::SZ_256M as usize;
-/// 0x20000000
-pub const SZ_512M: usize = bindings::SZ_512M as usize;
-/// 0x40000000
-pub const SZ_1G: usize = bindings::SZ_1G as usize;
-/// 0x80000000
-pub const SZ_2G: usize = bindings::SZ_2G as usize;
+define_sizes!(u32, u64, usize);
diff --git a/rust/kernel/slice.rs b/rust/kernel/slice.rs
deleted file mode 100644
index ca2cde135061..000000000000
--- a/rust/kernel/slice.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Additional (and temporary) slice helpers.
-
-/// Extension trait providing a portable version of [`as_flattened`] and
-/// [`as_flattened_mut`].
-///
-/// In Rust 1.80, the previously unstable `slice::flatten` family of methods
-/// have been stabilized and renamed from `flatten` to `as_flattened`.
-///
-/// This creates an issue for as long as the MSRV is < 1.80, as the same functionality is provided
-/// by different methods depending on the compiler version.
-///
-/// This extension trait solves this by abstracting `as_flatten` and calling the correct method
-/// depending on the Rust version.
-///
-/// This trait can be removed once the MSRV passes 1.80.
-///
-/// [`as_flattened`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened
-/// [`as_flattened_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened_mut
-#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
-pub trait AsFlattened<T> {
- /// Takes a `&[[T; N]]` and flattens it to a `&[T]`.
- ///
- /// This is an portable layer on top of [`as_flattened`]; see its documentation for details.
- ///
- /// [`as_flattened`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened
- fn as_flattened(&self) -> &[T];
-
- /// Takes a `&mut [[T; N]]` and flattens it to a `&mut [T]`.
- ///
- /// This is an portable layer on top of [`as_flattened_mut`]; see its documentation for details.
- ///
- /// [`as_flattened_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened_mut
- fn as_flattened_mut(&mut self) -> &mut [T];
-}
-
-#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
-impl<T, const N: usize> AsFlattened<T> for [[T; N]] {
- #[allow(clippy::incompatible_msrv)]
- fn as_flattened(&self) -> &[T] {
- self.flatten()
- }
-
- #[allow(clippy::incompatible_msrv)]
- fn as_flattened_mut(&mut self) -> &mut [T] {
- self.flatten_mut()
- }
-}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
deleted file mode 100644
index a57ba14315a0..000000000000
--- a/rust/kernel/static_assert.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Static assert.
-
-/// Static assert (i.e. compile-time assert).
-///
-/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
-///
-/// An optional panic message can be supplied after the expression.
-/// Currently only a string literal without formatting is supported
-/// due to constness limitations of the [`assert!`] macro.
-///
-/// The feature may be added to Rust in the future: see [RFC 2790].
-///
-/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
-/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
-/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
-///
-/// # Examples
-///
-/// ```
-/// static_assert!(42 > 24);
-/// static_assert!(core::mem::size_of::<u8>() == 1);
-///
-/// const X: &[u8] = b"bar";
-/// static_assert!(X[1] == b'a');
-///
-/// const fn f(x: i32) -> i32 {
-/// x + 2
-/// }
-/// static_assert!(f(40) == 42);
-/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
-/// ```
-#[macro_export]
-macro_rules! static_assert {
- ($condition:expr $(,$arg:literal)?) => {
- const _: () = ::core::assert!($condition $(,$arg)?);
- };
-}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 3f8918764640..8311d91549e1 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -189,6 +189,7 @@ macro_rules! b_str {
//
// - error[E0379]: functions in trait impls cannot be declared const
#[inline]
+#[expect(clippy::disallowed_methods, reason = "internal implementation")]
pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char {
c_str.as_ptr().cast()
}
@@ -319,6 +320,7 @@ unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] {
impl CStrExt for CStr {
#[inline]
+ #[expect(clippy::disallowed_methods, reason = "internal implementation")]
unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self {
// SAFETY: The safety preconditions are the same as for `CStr::from_ptr`.
unsafe { CStr::from_ptr(ptr.cast()) }
@@ -334,6 +336,7 @@ impl CStrExt for CStr {
}
#[inline]
+ #[expect(clippy::disallowed_methods, reason = "internal implementation")]
fn as_char_ptr(&self) -> *const c_char {
self.as_ptr().cast()
}
@@ -376,19 +379,32 @@ impl AsRef<BStr> for CStr {
}
}
-/// Creates a new [`CStr`] from a string literal.
+/// Creates a new [`CStr`] at compile time.
///
-/// The string literal should not contain any `NUL` bytes.
+/// Rust supports C string literals since Rust 1.77, and they should be used instead of this macro
+/// where possible. This macro exists to allow static *non-literal* C strings to be created at
+/// compile time. This is most often used in other macros.
+///
+/// # Panics
+///
+/// This macro panics if the operand contains an interior `NUL` byte.
///
/// # Examples
///
/// ```
/// # use kernel::c_str;
/// # use kernel::str::CStr;
-/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// // This is allowed, but `c"literal"` should be preferred for literals.
+/// const BAD: &CStr = c_str!("literal");
+///
+/// // `c_str!` is still needed for static non-literal C strings.
+/// const GOOD: &CStr = c_str!(concat!(file!(), ":", line!(), ": My CStr!"));
/// ```
#[macro_export]
macro_rules! c_str {
+ // NB: We could write `($str:lit) => compile_error!("use a C string literal instead");` here but
+ // that would trigger when the literal is at the top of several macro expansions. That would be
+ // too limiting to macro authors.
($str:expr) => {{
const S: &str = concat!($str, "\0");
const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
@@ -828,7 +844,10 @@ impl CString {
f.write_str("\0")?;
// SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
- // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+ // `buf`'s capacity. The `Formatter` is created with `size` as its limit, and the `?`
+ // operators on `write_fmt` and `write_str` above ensure that if writing exceeds this
+ // limit, an error is returned early. The contents of the buffer have been initialised
+ // by writes to `f`.
unsafe { buf.inc_len(f.bytes_written()) };
// Check that there are no `NUL` bytes before the end.
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 921e19333b89..18d6c0d62ce0 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -128,7 +128,7 @@ mod std_vendor;
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
+#[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
@@ -182,15 +182,6 @@ 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`.
-#[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>`.
-#[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
// `T` to be `Send` because any thread that has an `Arc<T>` may ultimately access `T` using a
@@ -547,20 +538,12 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
+#[derive(core::marker::CoercePointee)]
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
inner: NonNull<ArcInner<T>>,
_p: PhantomData<&'a ()>,
}
-// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
-// `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>
-{
-}
-
impl<T: ?Sized> Clone for ArcBorrow<'_, T> {
fn clone(&self) -> Self {
*self
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index cc907fb531bc..049c8a4d45d8 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -6,16 +6,15 @@
use crate::{
bindings,
- ffi::{c_int, c_long, c_uint},
mm::MmWithUser,
pid_namespace::PidNamespace,
+ prelude::*,
sync::aref::ARef,
types::{NotThreadSafe, Opaque},
};
use core::{
- cmp::{Eq, PartialEq},
ops::Deref,
- ptr,
+ ptr, //
};
/// A sentinel value used for infinite timeouts.
@@ -419,7 +418,7 @@ pub fn might_sleep() {
let file = kernel::file_from_location(loc);
// SAFETY: `file.as_ptr()` is valid for reading and guaranteed to be nul-terminated.
- unsafe { crate::bindings::__might_sleep(file.as_ptr().cast(), loc.line() as i32) }
+ unsafe { crate::bindings::__might_sleep(file.as_char_ptr(), loc.line() as i32) }
}
// SAFETY: Always safe to call.
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 6ea98dfcd027..363e93cbb139 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -60,7 +60,13 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
/// cases the user of the clock has to decide which clock is best suited for the
/// purpose. In most scenarios clock [`Monotonic`] is the best choice as it
/// provides a accurate monotonic notion of time (leap second smearing ignored).
-pub trait ClockSource {
+///
+/// # Safety
+///
+/// Implementers must ensure that `ktime_get()` returns a value in the inclusive range
+/// `0..=KTIME_MAX` (i.e., greater than or equal to 0 and less than or equal to
+/// `KTIME_MAX`, where `KTIME_MAX` equals `i64::MAX`).
+pub unsafe trait ClockSource {
/// The kernel clock ID associated with this clock source.
///
/// This constant corresponds to the C side `clockid_t` value.
@@ -68,7 +74,7 @@ pub trait ClockSource {
/// Get the current time from the clock source.
///
- /// The function must return a value in the range from 0 to `KTIME_MAX`.
+ /// The function must return a value in the range `0..=KTIME_MAX`.
fn ktime_get() -> bindings::ktime_t;
}
@@ -85,7 +91,9 @@ pub trait ClockSource {
/// count time that the system is suspended.
pub struct Monotonic;
-impl ClockSource for Monotonic {
+// SAFETY: The kernel's `ktime_get()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for Monotonic {
const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -110,7 +118,9 @@ impl ClockSource for Monotonic {
/// the clock will experience discontinuity around leap second adjustment.
pub struct RealTime;
-impl ClockSource for RealTime {
+// SAFETY: The kernel's `ktime_get_real()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for RealTime {
const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -128,7 +138,9 @@ impl ClockSource for RealTime {
/// discontinuities if the time is changed using settimeofday(2) or similar.
pub struct BootTime;
-impl ClockSource for BootTime {
+// SAFETY: The kernel's `ktime_get_boottime()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for BootTime {
const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -150,7 +162,9 @@ impl ClockSource for BootTime {
/// The acronym TAI refers to International Atomic Time.
pub struct Tai;
-impl ClockSource for Tai {
+// SAFETY: The kernel's `ktime_get_clocktai()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for Tai {
const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -363,6 +377,12 @@ impl Delta {
/// A span of time equal to zero.
pub const ZERO: Self = Self { nanos: 0 };
+ /// Create a new [`Delta`] from a number of nanoseconds.
+ #[inline]
+ pub const fn from_nanos(nanos: i64) -> Self {
+ Self { nanos }
+ }
+
/// Create a new [`Delta`] from a number of microseconds.
///
/// The `micros` can range from -9_223_372_036_854_775 to 9_223_372_036_854_775.
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 856d2d929a00..2d7f1131a813 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -66,6 +66,342 @@
//!
//! A `restart` operation on a timer in the **stopped** state is equivalent to a
//! `start` operation.
+//!
+//! When a type implements both `HrTimerPointer` and `Clone`, it is possible to
+//! issue the `start` operation while the timer is in the **started** state. In
+//! this case the `start` operation is equivalent to the `restart` operation.
+//!
+//! # Examples
+//!
+//! ## Using an intrusive timer living in a [`Box`]
+//!
+//! ```
+//! # use kernel::{
+//! # alloc::flags,
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # Arc,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
+//! # HrTimerRestart, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//!
+//! #[pin_data]
+//! struct Shared {
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl Shared {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! #[pin_data]
+//! struct BoxIntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! shared: Arc<Shared>,
+//! }
+//!
+//! impl BoxIntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self, kernel::error::Error> {
+//! try_pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for BoxIntrusiveHrTimer {
+//! type Pointer<'a> = Pin<KBox<Self>>;
+//!
+//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! let flag = this.shared.flag.fetch_add(1, ordering::Full);
+//! this.shared.cond.complete_all();
+//!
+//! if flag == 4 {
+//! HrTimerRestart::NoRestart
+//! } else {
+//! HrTimerRestart::Restart
+//! }
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for BoxIntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! let has_timer = Box::pin_init(BoxIntrusiveHrTimer::new(), GFP_KERNEL)?;
+//! let shared = has_timer.shared.clone();
+//! let _handle = has_timer.start(Delta::from_micros(200));
+//!
+//! while shared.flag.load(ordering::Relaxed) != 5 {
+//! shared.cond.wait_for_completion();
+//! }
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using an intrusive timer in an [`Arc`]
+//!
+//! ```
+//! # use kernel::{
+//! # alloc::flags,
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # Arc, ArcBorrow,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//! # HasHrTimer, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//!
+//! #[pin_data]
+//! struct ArcIntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl ArcIntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for ArcIntrusiveHrTimer {
+//! type Pointer<'a> = Arc<Self>;
+//!
+//! fn run(
+//! this: ArcBorrow<'_, Self>,
+//! _ctx: HrTimerCallbackContext<'_, Self>,
+//! ) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! let flag = this.flag.fetch_add(1, ordering::Full);
+//! this.cond.complete_all();
+//!
+//! if flag == 4 {
+//! HrTimerRestart::NoRestart
+//! } else {
+//! HrTimerRestart::Restart
+//! }
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for ArcIntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! let has_timer = Arc::pin_init(ArcIntrusiveHrTimer::new(), GFP_KERNEL)?;
+//! let _handle = has_timer.clone().start(Delta::from_micros(200));
+//!
+//! while has_timer.flag.load(ordering::Relaxed) != 5 {
+//! has_timer.cond.wait_for_completion();
+//! }
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using a stack-based timer
+//!
+//! ```
+//! # use kernel::{
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//! # HasHrTimer, RelativeMode, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//! # use pin_init::stack_pin_init;
+//!
+//! #[pin_data]
+//! struct IntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl IntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for IntrusiveHrTimer {
+//! type Pointer<'a> = Pin<&'a Self>;
+//!
+//! fn run(this: Pin<&Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! this.flag.store(1, ordering::Release);
+//! this.cond.complete_all();
+//!
+//! HrTimerRestart::NoRestart
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for IntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! stack_pin_init!( let has_timer = IntrusiveHrTimer::new() );
+//! has_timer.as_ref().start_scoped(Delta::from_micros(200), || {
+//! while has_timer.flag.load(ordering::Relaxed) != 1 {
+//! has_timer.cond.wait_for_completion();
+//! }
+//! });
+//!
+//! pr_info!("Flag raised\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using a mutable stack-based timer
+//!
+//! ```
+//! # use kernel::{
+//! # alloc::flags,
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # Arc,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//! # HasHrTimer, RelativeMode, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//! # use pin_init::stack_try_pin_init;
+//!
+//! #[pin_data]
+//! struct Shared {
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl Shared {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! #[pin_data]
+//! struct IntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! shared: Arc<Shared>,
+//! }
+//!
+//! impl IntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self, kernel::error::Error> {
+//! try_pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for IntrusiveHrTimer {
+//! type Pointer<'a> = Pin<&'a mut Self>;
+//!
+//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! let flag = this.shared.flag.fetch_add(1, ordering::Full);
+//! this.shared.cond.complete_all();
+//!
+//! if flag == 4 {
+//! HrTimerRestart::NoRestart
+//! } else {
+//! HrTimerRestart::Restart
+//! }
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for IntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! stack_try_pin_init!( let has_timer =? IntrusiveHrTimer::new() );
+//! let shared = has_timer.shared.clone();
+//!
+//! has_timer.as_mut().start_scoped(Delta::from_micros(200), || {
+//! while shared.flag.load(ordering::Relaxed) != 5 {
+//! shared.cond.wait_for_completion();
+//! }
+//! });
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! [`Arc`]: kernel::sync::Arc
use super::{ClockSource, Delta, Instant};
use crate::{prelude::*, types::Opaque};
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 5711580c9f9b..654b5ede2fe2 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -49,7 +49,6 @@ pub unsafe trait FromBytes {
let slice_ptr = bytes.as_ptr().cast::<Self>();
let size = size_of::<Self>();
- #[allow(clippy::incompatible_msrv)]
if bytes.len() == size && slice_ptr.is_aligned() {
// SAFETY: Size and alignment were just checked.
unsafe { Some(&*slice_ptr) }
@@ -67,16 +66,9 @@ pub unsafe trait FromBytes {
where
Self: Sized,
{
- if bytes.len() < size_of::<Self>() {
- None
- } else {
- // PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at` cannot
- // panic.
- // TODO: replace with `split_at_checked` once the MSRV is >= 1.80.
- let (prefix, remainder) = bytes.split_at(size_of::<Self>());
+ let (prefix, remainder) = bytes.split_at_checked(size_of::<Self>())?;
- Self::from_bytes(prefix).map(|s| (s, remainder))
- }
+ Self::from_bytes(prefix).map(|s| (s, remainder))
}
/// Converts a mutable slice of bytes to a reference to `Self`.
@@ -92,7 +84,6 @@ pub unsafe trait FromBytes {
let slice_ptr = bytes.as_mut_ptr().cast::<Self>();
let size = size_of::<Self>();
- #[allow(clippy::incompatible_msrv)]
if bytes.len() == size && slice_ptr.is_aligned() {
// SAFETY: Size and alignment were just checked.
unsafe { Some(&mut *slice_ptr) }
@@ -110,16 +101,9 @@ pub unsafe trait FromBytes {
where
Self: AsBytes + Sized,
{
- if bytes.len() < size_of::<Self>() {
- None
- } else {
- // PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at_mut` cannot
- // panic.
- // TODO: replace with `split_at_mut_checked` once the MSRV is >= 1.80.
- let (prefix, remainder) = bytes.split_at_mut(size_of::<Self>());
+ let (prefix, remainder) = bytes.split_at_mut_checked(size_of::<Self>())?;
- Self::from_bytes_mut(prefix).map(|s| (s, remainder))
- }
+ Self::from_bytes_mut(prefix).map(|s| (s, remainder))
}
/// Creates an owned instance of `Self` by copying `bytes`.
@@ -149,16 +133,9 @@ pub unsafe trait FromBytes {
where
Self: Sized,
{
- if bytes.len() < size_of::<Self>() {
- None
- } else {
- // PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at` cannot
- // panic.
- // TODO: replace with `split_at_checked` once the MSRV is >= 1.80.
- let (prefix, remainder) = bytes.split_at(size_of::<Self>());
+ let (prefix, remainder) = bytes.split_at_checked(size_of::<Self>())?;
- Self::from_bytes_copy(prefix).map(|s| (s, remainder))
- }
+ Self::from_bytes_copy(prefix).map(|s| (s, remainder))
}
}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 9c5e7dbf1632..4329d3c2c2e5 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -11,8 +11,6 @@ use core::{
};
use pin_init::{PinInit, Wrapper, Zeroable};
-pub use crate::sync::aref::{ARef, AlwaysRefCounted};
-
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 0e1b9a88f4f1..9c17a672cd27 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -18,10 +18,8 @@ use crate::{
to_result, //
},
prelude::*,
- types::{
- AlwaysRefCounted,
- Opaque, //
- },
+ sync::aref::AlwaysRefCounted,
+ types::Opaque,
ThisModule, //
};
use core::{
diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs
index a49d6db28845..46e5f43223fe 100644
--- a/rust/kernel/xarray.rs
+++ b/rust/kernel/xarray.rs
@@ -172,6 +172,7 @@ pub struct StoreError<T> {
}
impl<T> From<StoreError<T>> for Error {
+ #[inline]
fn from(value: StoreError<T>) -> Self {
value.error
}
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index 37ef6a6f2c85..d18fbf4daa0a 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -49,7 +49,6 @@ pub(crate) fn file() -> String {
}
#[cfg(CONFIG_RUSTC_HAS_SPAN_FILE)]
- #[allow(clippy::incompatible_msrv)]
{
proc_macro::Span::call_site().file()
}
diff --git a/rust/macros/kunit.rs b/rust/macros/kunit.rs
index 6be880d634e2..ae20ed6768f1 100644
--- a/rust/macros/kunit.rs
+++ b/rust/macros/kunit.rs
@@ -87,10 +87,11 @@ pub(crate) fn kunit_tests(test_suite: Ident, mut module: ItemMod) -> Result<Toke
continue;
};
- // TODO: Replace below with `extract_if` when MSRV is bumped above 1.85.
- let before_len = f.attrs.len();
- f.attrs.retain(|attr| !attr.path().is_ident("test"));
- if f.attrs.len() == before_len {
+ if f.attrs
+ .extract_if(.., |attr| attr.path().is_ident("test"))
+ .count()
+ == 0
+ {
processed_items.push(Item::Fn(f));
continue;
}
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 0c36194d9971..2cfd59e0f9e7 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -6,6 +6,9 @@
// and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is
// touched by Kconfig when the version string from the compiler changes.
+// Stable since Rust 1.87.0.
+#![feature(extract_if)]
+//
// Stable since Rust 1.88.0 under a different name, `proc_macro_span_file`,
// which was added in Rust 1.88.0. This is why `cfg_attr` is used here, i.e.
// to avoid depending on the full `proc_macro_span` on Rust >= 1.88.0.
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index e16298e520c7..06c18e207508 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -52,12 +52,7 @@ impl<'a> ModInfoBuilder<'a> {
fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) {
let string = if builtin {
// Built-in modules prefix their modinfo strings by `module.`.
- format!(
- "{module}.{field}={content}\0",
- module = self.module,
- field = field,
- content = content
- )
+ format!("{module}.{field}={content}\0", module = self.module)
} else {
// Loadable modules' modinfo strings go as-is.
format!("{field}={content}\0")
@@ -109,7 +104,7 @@ impl<'a> ModInfoBuilder<'a> {
}
fn emit_param(&mut self, field: &str, param: &str, content: &str) {
- let content = format!("{param}:{content}", param = param, content = content);
+ let content = format!("{param}:{content}");
self.emit_internal(field, &content, true);
}
diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md
index 6cee6ab1eb57..9095d6661ff6 100644
--- a/rust/pin-init/README.md
+++ b/rust/pin-init/README.md
@@ -160,7 +160,6 @@ actually does the initialization in the correct way. Here are the things to look
```rust
use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
use core::{
- ptr::addr_of_mut,
marker::PhantomPinned,
cell::UnsafeCell,
pin::Pin,
@@ -199,7 +198,7 @@ impl RawFoo {
unsafe {
pin_init_from_closure(move |slot: *mut Self| {
// `slot` contains uninit memory, avoid creating a reference.
- let foo = addr_of_mut!((*slot).foo);
+ let foo = &raw mut (*slot).foo;
let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
// Initialize the `foo`
diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs
index c05139927486..80f89b5f8fd6 100644
--- a/rust/pin-init/examples/big_struct_in_place.rs
+++ b/rust/pin-init/examples/big_struct_in_place.rs
@@ -1,5 +1,8 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
+
use pin_init::*;
// Struct with size over 1GiB
diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs
index 8445a5890cb7..119169e4dc41 100644
--- a/rust/pin-init/examples/linked_list.rs
+++ b/rust/pin-init/examples/linked_list.rs
@@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
use core::{
cell::Cell,
diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs
index 9f295226cd64..d53671f0edb8 100644
--- a/rust/pin-init/examples/mutex.rs
+++ b/rust/pin-init/examples/mutex.rs
@@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![allow(clippy::missing_safety_doc)]
use core::{
diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs
index 4e082ec7d5de..f3b5cc9b7134 100644
--- a/rust/pin-init/examples/pthread_mutex.rs
+++ b/rust/pin-init/examples/pthread_mutex.rs
@@ -3,7 +3,8 @@
// inspired by <https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs>
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#[cfg(not(windows))]
mod pthread_mtx {
diff --git a/rust/pin-init/examples/static_init.rs b/rust/pin-init/examples/static_init.rs
index 0e165daa9798..f7e53d1a5ae6 100644
--- a/rust/pin-init/examples/static_init.rs
+++ b/rust/pin-init/examples/static_init.rs
@@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![allow(unused_imports)]
use core::{
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 2fe918f4d82a..daa3f1c6466e 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -173,6 +173,12 @@ pub(crate) fn expand(
};
// SAFETY: TODO
let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) };
+ // FIXME: this let binding is required to avoid a compiler error (cycle when computing the
+ // opaque type returned by this function) before Rust 1.81. Remove after MSRV bump.
+ #[allow(
+ clippy::let_and_return,
+ reason = "some clippy versions warn about the let binding"
+ )]
init
}})
}
@@ -264,7 +270,7 @@ fn init_fields(
{
#value_prep
// SAFETY: TODO
- unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
+ unsafe { #write(&raw mut (*#slot).#ident, #value_ident) };
}
#(#cfgs)*
#[allow(unused_variables)]
@@ -287,7 +293,7 @@ fn init_fields(
// return when an error/panic occurs.
// - We also use `#data` to require the correct trait (`Init` or `PinInit`)
// for `#ident`.
- unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? };
+ unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? };
},
quote! {
// SAFETY: TODO
@@ -302,7 +308,7 @@ fn init_fields(
unsafe {
::pin_init::Init::__init(
#init,
- ::core::ptr::addr_of_mut!((*#slot).#ident),
+ &raw mut (*#slot).#ident,
)?
};
},
@@ -342,7 +348,7 @@ fn init_fields(
// SAFETY: We forget the guard later when initialization has succeeded.
let #guard = unsafe {
::pin_init::__internal::DropGuard::new(
- ::core::ptr::addr_of_mut!((*slot).#ident)
+ &raw mut (*slot).#ident
)
};
});
diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src/lib.rs
index 08372c8f65f0..b08dfe003031 100644
--- a/rust/pin-init/internal/src/lib.rs
+++ b/rust/pin-init/internal/src/lib.rs
@@ -6,7 +6,7 @@
//! `pin-init` proc macros.
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
// Documentation is done in the pin-init crate instead.
#![allow(missing_docs)]
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index fe4c85ae3f02..64eec095c859 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -172,7 +172,6 @@
//! # #![feature(extern_types)]
//! use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
//! use core::{
-//! ptr::addr_of_mut,
//! marker::PhantomPinned,
//! cell::UnsafeCell,
//! pin::Pin,
@@ -211,7 +210,7 @@
//! unsafe {
//! pin_init_from_closure(move |slot: *mut Self| {
//! // `slot` contains uninit memory, avoid creating a reference.
-//! let foo = addr_of_mut!((*slot).foo);
+//! let foo = &raw mut (*slot).foo;
//! let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
//!
//! // Initialize the `foo`
@@ -264,12 +263,10 @@
//! [`impl Init<T, E>`]: crate::Init
//! [Rust-for-Linux]: https://rust-for-linux.com/
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![cfg_attr(
- all(
- any(feature = "alloc", feature = "std"),
- not(RUSTC_NEW_UNINIT_IS_STABLE)
- ),
+ all(any(feature = "alloc", feature = "std"), USE_RUSTC_FEATURES),
feature(new_uninit)
)]
#![forbid(missing_docs, unsafe_op_in_unsafe_fn)]
@@ -279,6 +276,8 @@
all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED),
feature(unsafe_pinned)
)]
+#![cfg_attr(all(USE_RUSTC_FEATURES, doc), allow(internal_features))]
+#![cfg_attr(all(USE_RUSTC_FEATURES, doc), feature(rustdoc_internals))]
use core::{
cell::UnsafeCell,
@@ -755,7 +754,7 @@ macro_rules! stack_try_pin_init {
///
/// ```rust
/// # use pin_init::*;
-/// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
+/// # use core::marker::PhantomPinned;
/// #[pin_data]
/// #[derive(Zeroable)]
/// struct Buf {
@@ -769,7 +768,7 @@ macro_rules! stack_try_pin_init {
/// let init = pin_init!(&this in Buf {
/// buf: [0; 64],
/// // SAFETY: TODO.
-/// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
+/// ptr: unsafe { (&raw mut (*this.as_ptr()).buf).cast() },
/// pin: PhantomPinned,
/// });
/// let init = pin_init!(Buf {
@@ -1147,9 +1146,12 @@ pub const unsafe fn cast_pin_init<T, U, E>(init: impl PinInit<T, E>) -> impl Pin
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
// requirements.
let res = unsafe { pin_init_from_closure(|ptr: *mut U| init.__pinned_init(ptr.cast::<T>())) };
- // FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
- // cycle when computing the type returned by this function)
- #[allow(clippy::let_and_return)]
+ // FIXME: this let binding is required to avoid a compiler error (cycle when computing the opaque
+ // type returned by this function) before Rust 1.81. Remove after MSRV bump.
+ #[allow(
+ clippy::let_and_return,
+ reason = "some clippy versions warn about the let binding"
+ )]
res
}
@@ -1163,9 +1165,12 @@ pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E>
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
// requirements.
let res = unsafe { init_from_closure(|ptr: *mut U| init.__init(ptr.cast::<T>())) };
- // FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
- // cycle when computing the type returned by this function)
- #[allow(clippy::let_and_return)]
+ // FIXME: this let binding is required to avoid a compiler error (cycle when computing the opaque
+ // type returned by this function) before Rust 1.81. Remove after MSRV bump.
+ #[allow(
+ clippy::let_and_return,
+ reason = "some clippy versions warn about the let binding"
+ )]
res
}
@@ -1610,13 +1615,6 @@ impl_zeroable! {
// SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`.
{<T: ?Sized + Zeroable>} UnsafeCell<T>,
- // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
- // <https://doc.rust-lang.org/stable/std/option/index.html#representation>).
- Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>,
- Option<NonZeroU128>, Option<NonZeroUsize>,
- Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
- Option<NonZeroI128>, Option<NonZeroIsize>,
-
// SAFETY: `null` pointer is valid.
//
// We cannot use `T: ?Sized`, since the VTABLE pointer part of fat pointers is not allowed to be
@@ -1635,8 +1633,14 @@ impl_zeroable! {
}
macro_rules! impl_tuple_zeroable {
- ($(,)?) => {};
+ ($first:ident, $(,)?) => {
+ #[cfg_attr(all(USE_RUSTC_FEATURES, doc), doc(fake_variadic))]
+ /// Implemented for tuples up to 10 items long.
+ // SAFETY: All elements are zeroable and padding can be zero.
+ unsafe impl<$first: Zeroable> Zeroable for ($first,) {}
+ };
($first:ident, $($t:ident),* $(,)?) => {
+ #[cfg_attr(doc, doc(hidden))]
// SAFETY: All elements are zeroable and padding can be zero.
unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {}
impl_tuple_zeroable!($($t),* ,);
@@ -1651,7 +1655,16 @@ macro_rules! impl_fn_zeroable_option {
$(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
};
({$($prefix:tt)*} {$(,)?}) => {};
+ ({$($prefix:tt)*} {$ret:ident, $arg:ident $(,)?}) => {
+ #[cfg_attr(all(USE_RUSTC_FEATURES, doc), doc(fake_variadic))]
+ /// Implemented for function pointers with up to 20 arity.
+ // SAFETY: function pointers are part of the option layout optimization:
+ // <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+ unsafe impl<$ret, $arg> ZeroableOption for $($prefix)* fn($arg) -> $ret {}
+ impl_fn_zeroable_option!({$($prefix)*} {$arg,});
+ };
({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
+ #[cfg_attr(doc, doc(hidden))]
// SAFETY: function pointers are part of the option layout optimization:
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
@@ -1661,6 +1674,20 @@ macro_rules! impl_fn_zeroable_option {
impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U });
+macro_rules! impl_non_zero_int_zeroable_option {
+ ($($int:ty),* $(,)?) => {
+ // SAFETY: Safety comment written in the macro invocation.
+ $(unsafe impl ZeroableOption for $int {})*
+ };
+}
+
+impl_non_zero_int_zeroable_option! {
+ // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
+ // <https://doc.rust-lang.org/stable/std/option/index.html#representation>).
+ NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
+ NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
+}
+
/// This trait allows creating an instance of `Self` which contains exactly one
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
///
diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs
index 1d5fd9efb93e..b8a515de31ca 100644
--- a/rust/uapi/lib.rs
+++ b/rust/uapi/lib.rs
@@ -8,10 +8,6 @@
//! userspace APIs.
#![no_std]
-// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
-#![cfg_attr(test, allow(deref_nullptr))]
-#![cfg_attr(test, allow(unaligned_references))]
-#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
clippy::cast_lossless,
@@ -28,6 +24,7 @@
unsafe_op_in_unsafe_fn
)]
#![cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))]
+#![feature(cfi_encoding)]
// Manual definition of blocklisted types.
type __kernel_size_t = usize;