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

Pull Rust updates from Miguel Ojeda:
 "This one is big due to the vendoring of the `zerocopy` library, which
  allows us to replace a bunch of `unsafe` code dealing with conversions
  between byte sequences and other types with safe alternatives. More
  details on that below (and in its merge commit).

  Toolchain and infrastructure:

   - Introduce support for the 'zerocopy' library [1][2]:

         Fast, safe, compile error. Pick two.

         Zerocopy makes zero-cost memory manipulation effortless. We write
         `unsafe` so you don't have to.

     It essentially provides derivable traits (e.g. 'FromBytes') and
     macros (e.g. 'transmute!') for safely converting between byte
     sequences and other types. Having such support allows us to remove
     some 'unsafe' code.

     It is among the most downloaded Rust crates and it is also used by
     the Rust compiler itself.

     It is licensed under "BSD-2-Clause OR Apache-2.0 OR MIT".

     The crates are imported essentially as-is (only +2/-3 lines needed
     to be adapted), plus SPDX identifiers. Upstream has since added the
     SPDX identifiers as well as one of the tweaks at my request, thus
     reducing our future diffs on updates -- I keep the details in one
     of our usual live lists [3].

     In total, it is about ~39k lines added, ~32k without counting
     'benches/' which are just for documentation purposes.

     The series includes a few Kbuild and rust-analyzer improvements and
     an example patch using it in Nova, removing one 'unsafe impl'.

     I checked that the codegen of an isolated example function (similar
     to the Nova patch on top) is essentially identical. It also turns
     out that (for that particular case) the 'zerocopy' version, even
     with 'debug-assertions' enabled, has no remaining panics, unlike a
     few in the current code (since the compiler can prove the remaining
     'ub_checks' statically).

     So their "fast, safe" does indeed check out -- at least in that
     case.

   - Support AutoFDO. This allows Rust code to be profiled and optimized
     based on the profile. Tested with Rust Binder: ~13% slower without
     AutoFDO in the binderAddInts benchmark (using an app-launch
     benchmark for the profile).

   - Support Software Tag-Based KASAN.

     In addition, fix KASAN Kconfig by requiring Clang.

   - Add Kconfig options for each existing Rust KUnit test suite, such
     as 'CONFIG_RUST_BITMAP_KUNIT_TEST'.

     They are placed within a new menu, 'CONFIG_RUST_KUNIT_TESTS', in
     the new 'rust/kernel/Kconfig.test' file.

   - Support the upcoming Rust 1.98.0 release (expected 2026-08-20):
     lint cleanups and an unstable flag rename.

   - Disable 'rustdoc' documentation inlining for all prelude items,
     which bloats the generated documentation.

   - Ignore (in Git) and clean (in Kbuild) the (rarely) 'rustc'-generated
     '*.long-type-*.txt' files.

  'kernel' crate:

   - Add new 'bitfield' module with the 'bitfield!' macro (extracted
     from the existing 'register!' one), which declares integer types
     that are split into distinct bit fields of arbitrary length.

     Each field is a 'Bounded' of the appropriate bit width (ensuring
     values are properly validated and avoiding implicit data loss) and
     gets several generated getters and setters (infallible, 'const' and
     fallible) as well as associated constants ('_MASK', '_SHIFT' and
     '_RANGE'). It also supports fields that can be converted from/to
     custom types, either fallibly ('?=>') or infallibly ('=>').

     For instance:

         bitfield! {
             struct Rgb(u16) {
                 15:11 blue;
                 10:5 green;
                 4:0 red;
             }
         }

         // Compile-time checks.
         let color = Rgb::zeroed().with_const_green::<0x1f>();

         assert_eq!(color.green(), 0x1f);
         assert_eq!(color.into_raw(), 0x1f << Rgb::GREEN_SHIFT);

     Add as well documentation and a test suite for it, as usual; and
     update the 'register!' macro to use it.

     It will be maintained by Alexandre Courbot (with Yury Norov as
     reviewer) under a new 'MAINTAINERS' entry: 'RUST [BITFIELD]'.

   - 'ptr' module: rework index projection syntax into keyworded syntax
     and introduce panicking variant.

     The keyword syntax ('build:', 'try:', 'panic:') is more explicit
     and paves the way of perhaps adding more flavors in the future,
     e.g. an 'unsafe' index projection.

     For instance, projections now look like this:

         fn f(p: *const [u8; 32]) -> Result {
             // Ok, within bounds, checked at build time.
             project!(p, [build: 1]);

             // Build error.
             project!(p, [build: 128]);

             // `OutOfBound` runtime error (convertible to `ERANGE`).
             project!(p, [try: 128]);

             // Runtime panic.
             project!(p, [panic: 128]);

             Ok(())
         }

     Update as well the users, which now look like e.g.

         // Pointer to the first entry of the GSP message queue.
         let data = project!(self.0.as_ptr(), .gspq.msgq.data[build: 0]);

   - 'build_assert' module: make the module the home of its macros
     instead of rendering them twice.

   - 'sync' module: add 'UniqueArc::as_ptr()' associated function.

   - 'alloc' module:

       - Fix the 'Vec::reserve()' doctest to properly account for the
         existing vector length in the capacity assertion.

       - Fix an incorrect operator in the 'Vec::extend_with()' 'SAFETY'
         comment; add a doc test demonstrating basic usage and the
         zero-length case.

   - Clean imports across several modules to follow the "kernel
     vertical" import style in order to minimize conflicts.

  'pin-init' crate:

   - User visible changes:

       - Do not generate 'non_snake_case' warnings for identifiers that
         are syntactically just users of a field name. This would allow
         all '#[allow(non_snake_case)]' in nova-core to be removed,
         which Gary will send to the nova tree next cycle.

       - Filter non-cfg attributes out properly in derived structs. This
         improves pin-init compatibility with other derive macros.

       - Insert projection types' where clause properly.

   - Other changes:

       - Bump MSRV to 1.82, plus associated cleanups.

       - Overhaul how init slots are projected. The new approach is
         easier to justify with safety comments.

       - Mark more functions as inline, which should help mitigate the
         super-long symbol name issue due to lack of inlining.

  rust-analyzer:

   - Support '--envs' for passing env vars for crates like 'zerocopy'.

  'MAINTAINERS':

   - Add the following reviewers to the 'RUST' entry:
       - Daniel Almeida
       - Tamir Duberstein
       - Alexandre Courbot
       - Onur Özkan

     They have been involved in the Rust for Linux project for about 7
     collective years and bring expertise across several domains, which
     will be very useful to have around in the future.

     Thanks everyone for stepping up!

  And some other fixes, cleanups and improvements"

Link: https://github.com/google/zerocopy [1]
Link: https://docs.rs/zerocopy [2]
Link: https://github.com/Rust-for-Linux/linux/issues/1239 [3]

* tag 'rust-7.2' of gitolite.kernel.org:pub/scm/linux/kernel/git/ojeda/linux: (86 commits)
  MAINTAINERS: add Onur Özkan as Rust reviewer
  MAINTAINERS: add Alexandre Courbot as Rust reviewer
  MAINTAINERS: add Tamir Duberstein as Rust reviewer
  MAINTAINERS: add Daniel Almeida as Rust reviewer
  kbuild: rust: clean `zerocopy-derive` in `mrproper`
  rust: make `build_assert` module the home of related macros
  rust: str: clean unused import for Rust >= 1.98
  rust: str: use the "kernel vertical" imports style
  rust: aref: use the "kernel vertical" imports style
  rust: page: use the "kernel vertical" imports style
  gpu: nova-core: firmware: parse `FalconUCodeDescV2` via `zerocopy`
  rust: prelude: add `zerocopy{,_derive}::FromBytes`
  rust: zerocopy-derive: enable support in kbuild
  rust: zerocopy-derive: add `README.md`
  rust: zerocopy-derive: avoid generating non-ASCII identifiers
  rust: zerocopy-derive: add SPDX License Identifiers
  rust: zerocopy-derive: import crate
  rust: zerocopy: enable support in kbuild
  rust: zerocopy: add `README.md`
  rust: zerocopy: remove float `Display` support
  ...
This commit is contained in:
Linus Torvalds
2026-06-15 09:25:48 +05:30
310 changed files with 40556 additions and 844 deletions
+3
View File
@@ -188,5 +188,8 @@ sphinx_*/
# Rust analyzer configuration
/rust-project.json
# rustc error message long types
*.long-type-*.txt
# bc language scripts (not LLVM bitcode)
!kernel/time/timeconst.bc
+5
View File
@@ -140,11 +140,15 @@ are also mapped to KUnit.
These tests are introduced by the ``kunit_tests`` procedural macro, which takes
the name of the test suite as an argument.
Each test suite should be guarded by a Kconfig option in
``rust/kernel/Kconfig.test``.
For instance, assume we want to test the function ``f`` from the documentation
tests section. We could write, in the same file where we have our function:
.. code-block:: rust
#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
#[kunit_tests(rust_kernel_mymod)]
mod tests {
use super::*;
@@ -173,6 +177,7 @@ the unit type ``()``) or ``Result`` (i.e. any ``Result<T, E>``). For instance:
.. code-block:: rust
#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
#[kunit_tests(rust_kernel_mymod)]
mod tests {
use super::*;
+11
View File
@@ -23400,6 +23400,10 @@ R: Andreas Hindborg <a.hindborg@kernel.org>
R: Alice Ryhl <aliceryhl@google.com>
R: Trevor Gross <tmgross@umich.edu>
R: Danilo Krummrich <dakr@kernel.org>
R: Daniel Almeida <daniel.almeida@collabora.com>
R: Tamir Duberstein <tamird@kernel.org>
R: Alexandre Courbot <acourbot@nvidia.com>
R: Onur Özkan <work@onurozkan.dev>
L: rust-for-linux@vger.kernel.org
S: Supported
W: https://rust-for-linux.com
@@ -23429,6 +23433,13 @@ T: git https://github.com/Rust-for-Linux/linux.git alloc-next
F: rust/kernel/alloc.rs
F: rust/kernel/alloc/
RUST [BITFIELD]
M: Alexandre Courbot <acourbot@nvidia.com>
R: Yury Norov <yury.norov@gmail.com>
L: rust-for-linux@vger.kernel.org
S: Maintained
F: rust/kernel/bitfield.rs
RUST [INTEROP]
M: Joel Fernandes <joelagnelf@nvidia.com>
M: Alexandre Courbot <acourbot@nvidia.com>
+5 -1
View File
@@ -1709,7 +1709,8 @@ MRPROPER_FILES += include/config include/generated \
vmlinux-gdb.py \
rpmbuild \
rust/libmacros.so rust/libmacros.dylib \
rust/libpin_init_internal.so rust/libpin_init_internal.dylib
rust/libpin_init_internal.so rust/libpin_init_internal.dylib \
rust/libzerocopy_derive.so rust/libzerocopy_derive.dylib
# clean - Delete most, but leave enough to build external modules
#
@@ -1961,6 +1962,8 @@ rustfmt:
-path $(srctree)/rust/proc-macro2 \
-o -path $(srctree)/rust/quote \
-o -path $(srctree)/rust/syn \
-o -path $(srctree)/rust/zerocopy \
-o -path $(srctree)/rust/zerocopy-derive \
\) -prune -o \
-type f -a -name '*.rs' -a ! -name '*generated*' -print \
| xargs $(RUSTFMT) $(rustfmt_flags)
@@ -2169,6 +2172,7 @@ clean: $(clean-dirs)
-o -name '*.c.[012]*.*' \
-o -name '*.ll' \
-o -name '*.gcno' \
-o -name '*.long-type-*.txt' \
\) -type f -print \
-o -name '.tmp_*' -print \
| xargs rm -rf
+2 -2
View File
@@ -170,7 +170,7 @@ macro_rules! bitfield {
(@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => {
#[allow(clippy::eq_op)]
const _: () = {
::kernel::build_assert!(
::kernel::build_assert::build_assert!(
$hi == $lo,
concat!("boolean field `", stringify!($field), "` covers more than one bit")
);
@@ -181,7 +181,7 @@ macro_rules! bitfield {
(@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => {
#[allow(clippy::eq_op)]
const _: () = {
::kernel::build_assert!(
::kernel::build_assert::build_assert!(
$hi >= $lo,
concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB")
);
+1 -4
View File
@@ -48,7 +48,7 @@ fn request_firmware(
/// Structure used to describe some firmwares, notably FWSEC-FRTS.
#[repr(C)]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, FromBytes)]
pub(crate) struct FalconUCodeDescV2 {
/// Header defined by 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*' in OpenRM.
hdr: u32,
@@ -84,9 +84,6 @@ pub(crate) struct FalconUCodeDescV2 {
pub(crate) alt_dmem_load_size: u32,
}
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
unsafe impl FromBytes for FalconUCodeDescV2 {}
/// Structure used to describe some firmwares, notably FWSEC-FRTS.
#[repr(C)]
#[derive(Debug, Clone)]
+3 -3
View File
@@ -237,7 +237,7 @@ impl DmaGspMem {
let start = gsp_mem.dma_handle();
// Write values one by one to avoid an on-stack instance of `PteArray`.
for i in 0..GspMem::PTE_ARRAY_SIZE {
dma_write!(gsp_mem, .ptes.0[i], PteArray::<0>::entry(start, i)?);
dma_write!(gsp_mem, .ptes.0[build: i], PteArray::<0>::entry(start, i)?);
}
dma_write!(
@@ -260,7 +260,7 @@ impl DmaGspMem {
let rx = self.gsp_read_ptr();
// Pointer to the first entry of the CPU message queue.
let data = ptr::project!(mut self.0.as_mut_ptr(), .cpuq.msgq.data[0]);
let data = ptr::project!(mut self.0.as_mut_ptr(), .cpuq.msgq.data[build: 0]);
let (tail_end, wrap_end) = if rx == 0 {
// The write area is non-wrapping, and stops at the second-to-last entry of the command
@@ -322,7 +322,7 @@ impl DmaGspMem {
let rx = self.cpu_read_ptr();
// Pointer to the first entry of the GSP message queue.
let data = ptr::project!(self.0.as_ptr(), .gspq.msgq.data[0]);
let data = ptr::project!(self.0.as_ptr(), .gspq.msgq.data[build: 0]);
let (tail_end, wrap_end) = if rx <= tx {
// Read area is non-wrapping and stops right before `tx`.
+1 -1
View File
@@ -49,7 +49,7 @@ macro_rules! impl_safe_as {
#[allow(unused)]
#[inline(always)]
pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
kernel::static_assert!(size_of::<$into>() >= size_of::<$from>());
::kernel::build_assert::static_assert!(size_of::<$into>() >= size_of::<$from>());
value as $into
}
+4 -2
View File
@@ -16,6 +16,8 @@ use kernel::{
transmute::FromBytes,
};
use zerocopy::FromBytes as _;
use crate::{
driver::Bar0,
firmware::{
@@ -1011,8 +1013,8 @@ impl FwSecBiosImage {
let data = self.base.data.get(falcon_ucode_offset..).ok_or(EINVAL)?;
match ver {
2 => {
let v2 = FalconUCodeDescV2::from_bytes_copy_prefix(data)
.ok_or(EINVAL)?
let v2 = FalconUCodeDescV2::read_from_prefix(data)
.map_err(|_| EINVAL)?
.0;
Ok(FalconUCodeDesc::V2(v2))
}
+4 -1
View File
@@ -2195,7 +2195,8 @@ config RUST
depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && !LTO)
depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
select CFI_ICALL_NORMALIZE_INTEGERS if CFI
depends on !KASAN_SW_TAGS
depends on !KASAN || CC_IS_CLANG
depends on !KASAN_SW_TAGS || RUSTC_VERSION >= 109600
help
Enables Rust support in the kernel.
@@ -2209,6 +2210,8 @@ config RUST
If unsure, say N.
source "rust/kernel/Kconfig.test"
config RUSTC_VERSION_TEXT
string
depends on RUST
+81 -15
View File
@@ -6,6 +6,8 @@ rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h
obj-$(CONFIG_RUST) += zerocopy.o
ifdef CONFIG_RUST_INLINE_HELPERS
always-$(CONFIG_RUST) += helpers/helpers.bc helpers/helpers_module.bc
else
@@ -47,13 +49,14 @@ endif
# Avoids running `$(RUSTC)` when it may not be available.
ifdef CONFIG_RUST
libmacros_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - </dev/null)
libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
procmacro-name = $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name $(1) --crate-type proc-macro - </dev/null)
procmacro-extension := $(patsubst libname.%,%,$(call procmacro-name,name))
libpin_init_internal_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name pin_init_internal --crate-type proc-macro - </dev/null)
libpin_init_internal_extension := $(patsubst libpin_init_internal.%,%,$(libpin_init_internal_name))
libzerocopy_derive_name := $(call procmacro-name,zerocopy_derive)
libmacros_name := $(call procmacro-name,macros)
libpin_init_internal_name := $(call procmacro-name,pin_init_internal)
always-$(CONFIG_RUST) += $(libmacros_name) $(libpin_init_internal_name)
always-$(CONFIG_RUST) += $(libzerocopy_derive_name) $(libmacros_name) $(libpin_init_internal_name)
# `$(rust_flags)` is passed in case the user added `--sysroot`.
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
@@ -81,6 +84,12 @@ core-flags := \
--edition=$(core-edition) \
$(call cfgs-to-flags,$(core-cfgs))
zerocopy-flags := \
--cap-lints=allow
zerocopy-envs := \
CARGO_PKG_VERSION=0.8.50
proc_macro2-cfgs := \
feature="proc-macro" \
wrap_proc_macro \
@@ -118,6 +127,12 @@ syn-flags := \
--extern quote \
$(call cfgs-to-flags,$(syn-cfgs))
zerocopy_derive-flags := \
--cap-lints=allow \
--extern proc_macro2 \
--extern quote \
--extern syn
pin_init_internal-cfgs := \
kernel USE_RUSTC_FEATURES
@@ -144,6 +159,7 @@ doctests_modifiers_workaround := $(rustdoc_modifiers_workaround)$(if $(call rust
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj) \
@@ -166,7 +182,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
# command-like flags to solve the issue. Meanwhile, we use the non-custom case
# and then retouch the generated files.
rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
rustdoc-kernel rustdoc-pin_init
rustdoc-kernel rustdoc-pin_init rustdoc-zerocopy rustdoc-zerocopy_derive
$(Q)grep -Ehro '<a href="srctree/([^"]+)"' $(rustdoc_output) | \
cut -d'"' -f2 | cut -d/ -f2- | while read f; do \
if [ ! -e "$(srctree)/$$f" ]; then \
@@ -199,6 +215,12 @@ rustdoc-syn: private rustc_target_flags = $(syn-flags)
rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE
+$(call if_changed,rustdoc)
rustdoc-zerocopy_derive: private rustdoc_host = yes
rustdoc-zerocopy_derive: private rustc_target_flags = $(zerocopy_derive-flags) \
--extern proc_macro --crate-type proc-macro
rustdoc-zerocopy_derive: $(src)/zerocopy-derive/lib.rs rustdoc-clean rustdoc-syn FORCE
+$(call if_changed,rustdoc)
rustdoc-macros: private rustdoc_host = yes
rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
--extern proc_macro --extern proc_macro2 --extern quote --extern syn
@@ -218,6 +240,13 @@ rustdoc-compiler_builtins: private is-kernel-object := y
rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
+$(call if_changed,rustdoc)
rustdoc-zerocopy: private rustc_target_envs := $(zerocopy-envs)
rustdoc-zerocopy: private is-kernel-object := y
rustdoc-zerocopy: private rustc_target_flags = $(zerocopy-flags) \
--extend-css $(src)/zerocopy/rustdoc/style.css
rustdoc-zerocopy: $(src)/zerocopy/src/lib.rs rustdoc-clean rustdoc-core FORCE
+$(call if_changed,rustdoc)
rustdoc-ffi: private is-kernel-object := y
rustdoc-ffi: $(src)/ffi.rs rustdoc-core FORCE
+$(call if_changed,rustdoc)
@@ -239,7 +268,8 @@ rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \
rustdoc-kernel: private is-kernel-object := y
rustdoc-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
--extern build_error --extern macros \
--extern bindings --extern uapi
--extern bindings --extern uapi \
--extern zerocopy --extern zerocopy_derive
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \
rustdoc-pin_init rustdoc-compiler_builtins $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
@@ -250,6 +280,7 @@ rustdoc-clean: FORCE
quiet_cmd_rustc_test_library = $(RUSTC_OR_CLIPPY_QUIET) TL $<
cmd_rustc_test_library = \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
$(RUSTC_OR_CLIPPY) $(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
@$(objtree)/include/generated/rustc_cfg \
@@ -258,6 +289,11 @@ quiet_cmd_rustc_test_library = $(RUSTC_OR_CLIPPY_QUIET) TL $<
-L$(objtree)/$(obj)/test \
--crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $<
rusttestlib-zerocopy: private rustc_target_envs := $(zerocopy-envs)
rusttestlib-zerocopy: private rustc_target_flags = $(zerocopy-flags)
rusttestlib-zerocopy: $(src)/zerocopy/src/lib.rs FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-build_error: $(src)/build_error.rs FORCE
+$(call if_changed,rustc_test_library)
@@ -277,6 +313,12 @@ rusttestlib-syn: private rustc_target_flags = $(syn-flags)
rusttestlib-syn: $(src)/syn/lib.rs rusttestlib-quote FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-zerocopy_derive: private rustc_target_flags = $(zerocopy_derive-flags) \
--extern proc_macro
rusttestlib-zerocopy_derive: private rustc_test_library_proc = yes
rusttestlib-zerocopy_derive: $(src)/zerocopy-derive/lib.rs rusttestlib-syn FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-macros: private rustc_target_flags = --extern proc_macro \
--extern proc_macro2 --extern quote --extern syn
rusttestlib-macros: private rustc_test_library_proc = yes
@@ -298,10 +340,11 @@ rusttestlib-pin_init: $(src)/pin-init/src/lib.rs rusttestlib-macros \
rusttestlib-kernel: private rustc_target_flags = --extern ffi \
--extern build_error --extern macros --extern pin_init \
--extern bindings --extern uapi
--extern bindings --extern uapi \
--extern zerocopy --extern zerocopy_derive
rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \
rusttestlib-build_error rusttestlib-pin_init $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
$(obj)/bindings.o rusttestlib-zerocopy rusttestlib-zerocopy_derive FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-bindings: private rustc_target_flags = --extern ffi --extern pin_init
@@ -314,6 +357,7 @@ rusttestlib-uapi: $(src)/uapi/lib.rs rusttestlib-ffi rusttestlib-pin_init FORCE
quiet_cmd_rustdoc_test = RUSTDOC T $<
cmd_rustdoc_test = \
$(rustc_target_envs) \
RUST_MODFILE=test.rs \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(rust_common_flags) \
@@ -328,11 +372,13 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
cmd_rustdoc_test_kernel = \
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
$(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 \
--extern zerocopy --extern zerocopy_derive \
--no-run --crate-name kernel -Zunstable-options \
--sysroot=/dev/null \
$(doctests_modifiers_workaround) \
@@ -350,6 +396,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
# so for the moment we skip `-Cpanic=abort`.
quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $<
cmd_rustc_test = \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
$(RUSTC_OR_CLIPPY) --test $(rust_common_flags) \
@$(objtree)/include/generated/rustc_cfg \
@@ -517,8 +564,9 @@ $(obj)/exports_bindings_generated.h: $(obj)/bindings.o FORCE
$(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE
$(call if_changed,exports)
quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@
quiet_cmd_rustc_procmacrolibrary = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) PL $@
cmd_rustc_procmacrolibrary = \
$(rustc_target_envs) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
--emit=dep-info=$(depfile) --emit=link=$@ --crate-type rlib -O \
@@ -541,17 +589,24 @@ $(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags)
$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
quiet_cmd_rustc_procmacro = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) P $@
cmd_rustc_procmacro = \
$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
$(rustc_target_envs) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) $(rust_common_flags) $(rustc_target_flags) \
-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro -L$(objtree)/$(obj) \
--crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) \
--crate-name $(patsubst lib%.$(procmacro-extension),%,$(notdir $@)) \
@$(objtree)/include/generated/rustc_cfg $<
# Procedural macros can only be used with the `rustc` that compiled it.
$(obj)/$(libzerocopy_derive_name): private skip_clippy = 1
$(obj)/$(libzerocopy_derive_name): private rustc_target_flags = $(zerocopy_derive-flags)
$(obj)/$(libzerocopy_derive_name): $(src)/zerocopy-derive/lib.rs $(obj)/libproc_macro2.rlib \
$(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
+$(call if_changed_dep,rustc_procmacro)
$(obj)/$(libmacros_name): private rustc_target_flags = \
--extern proc_macro2 --extern quote --extern syn
$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
@@ -567,6 +622,7 @@ $(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs \
# since Rust 1.95.0 (https://github.com/rust-lang/rust/pull/151534).
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
cmd_rustc_library = \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_flags)) $(rustc_target_flags) \
@@ -591,6 +647,7 @@ rust-analyzer:
--cfgs='syn=$(syn-cfgs)' \
--cfgs='pin_init_internal=$(pin_init_internal-cfgs)' \
--cfgs='pin_init=$(pin_init-cfgs)' \
--envs='zerocopy=$(zerocopy-envs)' \
$(realpath $(srctree)) $(realpath $(objtree)) \
$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
> rust-project.json
@@ -662,6 +719,13 @@ $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
$(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE
+$(call if_changed_rule,rustc_library)
$(obj)/zerocopy.o: private skip_clippy = 1
$(obj)/zerocopy.o: private skip_gendwarfksyms = 1
$(obj)/zerocopy.o: private rustc_target_envs := $(zerocopy-envs)
$(obj)/zerocopy.o: private rustc_target_flags = $(zerocopy-flags)
$(obj)/zerocopy.o: $(src)/zerocopy/src/lib.rs $(obj)/compiler_builtins.o FORCE
+$(call if_changed_rule,rustc_library)
$(obj)/pin_init.o: private skip_gendwarfksyms = 1
$(obj)/pin_init.o: private rustc_target_flags = $(pin_init-flags)
$(obj)/pin_init.o: $(src)/pin-init/src/lib.rs $(obj)/compiler_builtins.o \
@@ -697,9 +761,11 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
+$(call if_changed_rule,rustc_library)
$(obj)/kernel.o: private rustc_target_flags = --extern ffi --extern pin_init \
--extern build_error --extern macros --extern bindings --extern uapi
--extern build_error --extern macros --extern bindings --extern uapi \
--extern zerocopy --extern zerocopy_derive
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
$(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
$(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o \
$(obj)/zerocopy.o $(obj)/$(libzerocopy_derive_name) FORCE
+$(call if_changed_rule,rustc_library)
ifdef CONFIG_JUMP_LABEL
+86
View File
@@ -0,0 +1,86 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig RUST_KUNIT_TESTS
bool "Rust KUnit tests"
depends on KUNIT && RUST
default KUNIT_ALL_TESTS
help
This menu collects all options for Rust KUnit tests.
See Documentation/rust/testing.rst for how to protect
unit tests with these options.
Say Y here to enable Rust KUnit tests.
If unsure, say N.
if RUST_KUNIT_TESTS
config RUST_ALLOCATOR_KUNIT_TEST
bool "KUnit tests for Rust allocator API" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the Rust allocator API.
These are only for development and testing, not for regular
kernel use cases.
If unsure, say N.
config RUST_KVEC_KUNIT_TEST
bool "KUnit tests for Rust KVec API" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the Rust KVec API.
These are only for development and testing, not for
regular kernel use cases.
If unsure, say N.
config RUST_BITMAP_KUNIT_TEST
bool "KUnit tests for Rust bitmap API" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the Rust bitmap API.
These are only for development and testing, not for regular
kernel use cases.
If unsure, say N.
config RUST_KUNIT_SELFTEST
bool "KUnit selftests for Rust" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit selftests. These are only
for development and testing, not for regular kernel
use cases.
If unsure, say N.
config RUST_STR_KUNIT_TEST
bool "KUnit tests for Rust strings API" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the Rust strings API.
These are only for development and testing, not for regular
kernel use cases.
If unsure, say N.
config RUST_ATOMICS_KUNIT_TEST
bool "KUnit tests for Rust atomics API" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the Rust atomics API.
These are only for development and testing, not for regular
kernel use cases.
If unsure, say N.
config RUST_BITFIELD_KUNIT_TEST
bool "KUnit tests for the Rust `bitfield!` macro" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the Rust `bitfield!` macro.
These are only for development and testing, not for regular
kernel use cases.
If unsure, say N.
endif
+6 -2
View File
@@ -22,8 +22,12 @@ pub use self::kvec::Vec;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError;
use crate::error::{code::EINVAL, Result};
use core::{alloc::Layout, ptr::NonNull};
use crate::prelude::*;
use core::{
alloc::Layout,
ptr::NonNull, //
};
/// Flags to be used when allocating memory.
///
+24 -9
View File
@@ -8,14 +8,25 @@
//!
//! Reference: <https://docs.kernel.org/core-api/memory-allocation.html>
use super::Flags;
use core::alloc::Layout;
use core::ptr;
use core::ptr::NonNull;
use super::{
AllocError,
Allocator,
Flags,
NumaNode, //
};
use crate::alloc::{AllocError, Allocator, NumaNode};
use crate::bindings;
use crate::page;
use crate::{
bindings,
page, //
};
use core::{
alloc::Layout,
ptr::{
self,
NonNull, //
}, //
};
const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN;
@@ -163,8 +174,11 @@ impl Vmalloc {
/// # Examples
///
/// ```
/// # use core::ptr::{NonNull, from_mut};
/// # use kernel::{page, prelude::*};
/// # use core::ptr::{
/// # from_mut,
/// # NonNull, //
/// # };
/// # use kernel::page;
/// use kernel::alloc::allocator::Vmalloc;
///
/// let mut vbox = VBox::<[u8; page::PAGE_SIZE]>::new_uninit(GFP_KERNEL)?;
@@ -251,6 +265,7 @@ unsafe impl Allocator for KVmalloc {
}
}
#[cfg(CONFIG_RUST_ALLOCATOR_KUNIT_TEST)]
#[macros::kunit_tests(rust_allocator)]
mod tests {
use super::*;
+6 -2
View File
@@ -1,9 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
use super::Vmalloc;
use crate::page;
use core::marker::PhantomData;
use core::ptr::NonNull;
use core::{
marker::PhantomData,
ptr::NonNull, //
};
/// An [`Iterator`] of [`page::BorrowedPage`] items owned by a [`Vmalloc`] allocation.
///
+53 -23
View File
@@ -3,24 +3,47 @@
//! Implementation of [`Box`].
#[allow(unused_imports)] // Used in doc comments.
use super::allocator::{KVmalloc, Kmalloc, Vmalloc, VmallocPageIter};
use super::{AllocError, Allocator, Flags, NumaNode};
use core::alloc::Layout;
use core::borrow::{Borrow, BorrowMut};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::ptr::NonNull;
use core::result::Result;
use super::allocator::{
KVmalloc,
Kmalloc,
Vmalloc,
VmallocPageIter, //
};
use crate::ffi::c_void;
use crate::fmt;
use crate::init::InPlaceInit;
use crate::page::AsPageIter;
use crate::types::ForeignOwnable;
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
use super::{
AllocError,
Allocator,
Flags,
NumaNode, //
};
use crate::{
fmt,
page::AsPageIter,
prelude::*,
types::ForeignOwnable, //
};
use core::{
alloc::Layout,
borrow::{
Borrow,
BorrowMut, //
},
marker::PhantomData,
mem::{
ManuallyDrop,
MaybeUninit, //
},
ops::{
Deref,
DerefMut, //
},
ptr::NonNull,
result::Result, //
};
use pin_init::ZeroableOption;
/// The kernel's [`Box`] type -- a heap allocation for a single value of type `T`.
///
@@ -274,7 +297,10 @@ where
/// # Examples
///
/// ```
/// use kernel::sync::{new_spinlock, SpinLock};
/// use kernel::sync::{
/// new_spinlock,
/// SpinLock, //
/// };
///
/// struct Inner {
/// a: u32,
@@ -411,6 +437,7 @@ where
{
type Initialized = Box<T, A>;
#[inline]
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
let slot = self.as_mut_ptr();
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
@@ -420,6 +447,7 @@ where
Ok(unsafe { Box::assume_init(self) })
}
#[inline]
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
let slot = self.as_mut_ptr();
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
@@ -567,7 +595,6 @@ where
///
/// ```
/// # use core::borrow::Borrow;
/// # use kernel::alloc::KBox;
/// struct Foo<B: Borrow<u32>>(B);
///
/// // Owned instance.
@@ -595,7 +622,6 @@ where
///
/// ```
/// # use core::borrow::BorrowMut;
/// # use kernel::alloc::KBox;
/// struct Foo<B: BorrowMut<u32>>(B);
///
/// // Owned instance.
@@ -660,9 +686,13 @@ where
/// # Examples
///
/// ```
/// # use kernel::prelude::*;
/// use kernel::alloc::allocator::VmallocPageIter;
/// use kernel::page::{AsPageIter, PAGE_SIZE};
/// use kernel::{
/// alloc::allocator::VmallocPageIter,
/// page::{
/// AsPageIter,
/// PAGE_SIZE, //
/// }, //
/// };
///
/// let mut vbox = VBox::new((), GFP_KERNEL)?;
///
+64 -18
View File
@@ -3,29 +3,52 @@
//! Implementation of [`Vec`].
use super::{
allocator::{KVmalloc, Kmalloc, Vmalloc, VmallocPageIter},
allocator::{
KVmalloc,
Kmalloc,
Vmalloc,
VmallocPageIter, //
},
layout::ArrayLayout,
AllocError, Allocator, Box, Flags, NumaNode,
AllocError,
Allocator,
Box,
Flags,
NumaNode, //
};
use crate::{
fmt,
page::{
AsPageIter,
PAGE_SIZE, //
},
}, //
};
use core::{
borrow::{Borrow, BorrowMut},
borrow::{
Borrow,
BorrowMut, //
},
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
ops::Deref,
ops::DerefMut,
ops::Index,
ops::IndexMut,
ptr,
ptr::NonNull,
slice,
slice::SliceIndex,
mem::{
ManuallyDrop,
MaybeUninit, //
},
ops::{
Deref,
DerefMut,
Index,
IndexMut, //
},
ptr::{
self,
NonNull, //
},
slice::{
self,
SliceIndex, //
}, //
};
mod errors;
@@ -614,7 +637,7 @@ where
///
/// v.reserve(10, GFP_KERNEL)?;
/// let cap = v.capacity();
/// assert!(cap >= 10);
/// assert!(cap >= v.len() + 10);
///
/// v.reserve(10, GFP_KERNEL)?;
/// let new_cap = v.capacity();
@@ -849,6 +872,24 @@ impl<T> Vec<T, KVmalloc> {
impl<T: Clone, A: Allocator> Vec<T, A> {
/// Extend the vector by `n` clones of `value`.
///
/// # Examples
///
/// ```
/// let mut v = KVec::new();
/// v.push(1, GFP_KERNEL)?;
///
/// v.extend_with(3, 5, GFP_KERNEL)?;
/// assert_eq!(&v, &[1, 5, 5, 5]);
///
/// v.extend_with(2, 8, GFP_KERNEL)?;
/// assert_eq!(&v, &[1, 5, 5, 5, 8, 8]);
///
/// v.extend_with(0, 3, GFP_KERNEL)?;
/// assert_eq!(&v, &[1, 5, 5, 5, 8, 8]);
///
/// # Ok::<(), Error>(())
/// ```
pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
if n == 0 {
return Ok(());
@@ -866,7 +907,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
spare[n - 1].write(value);
// SAFETY:
// - `self.len() + n < self.capacity()` due to the call to reserve above,
// - `self.len() + n <= self.capacity()` due to the call to reserve above,
// - the loop and the line above initialized the next `n` elements.
unsafe { self.inc_len(n) };
@@ -1146,9 +1187,13 @@ where
/// # Examples
///
/// ```
/// # use kernel::prelude::*;
/// use kernel::alloc::allocator::VmallocPageIter;
/// use kernel::page::{AsPageIter, PAGE_SIZE};
/// use kernel::{
/// alloc::allocator::VmallocPageIter,
/// page::{
/// AsPageIter,
/// PAGE_SIZE, //
/// }, //
/// };
///
/// let mut vec = VVec::<u8>::new();
///
@@ -1463,6 +1508,7 @@ impl<'vec, T> Drop for DrainAll<'vec, T> {
}
}
#[cfg(CONFIG_RUST_KVEC_KUNIT_TEST)]
#[macros::kunit_tests(rust_kvec)]
mod tests {
use super::*;
+4 -2
View File
@@ -2,8 +2,10 @@
//! Errors for the [`Vec`] type.
use kernel::fmt;
use kernel::prelude::*;
use crate::{
fmt,
prelude::*, //
};
/// Error type for [`Vec::push_within_capacity`].
pub struct PushError<T>(pub T);
+8 -2
View File
@@ -4,7 +4,10 @@
//!
//! Custom layout types extending or improving [`Layout`].
use core::{alloc::Layout, marker::PhantomData};
use core::{
alloc::Layout,
marker::PhantomData, //
};
/// Error when constructing an [`ArrayLayout`].
pub struct LayoutError;
@@ -47,7 +50,10 @@ impl<T> ArrayLayout<T> {
/// # Examples
///
/// ```
/// # use kernel::alloc::layout::{ArrayLayout, LayoutError};
/// # use kernel::alloc::layout::{
/// # ArrayLayout,
/// # LayoutError, //
/// # };
/// let layout = ArrayLayout::<i32>::new(15)?;
/// assert_eq!(layout.len(), 15);
///
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More