diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2026-09-30 09:59:20 +0000 |
|---|---|---|
| committer | Kumar Kartikeya Dwivedi <memxor@gmail.com> | 2026-10-01 18:40:05 +0200 |
| commit | aeb709c767aeca996e6011133e4f7bdb2a4af652 (patch) | |
| tree | c1c2bdbb4b6b7174a5bbe9e4c2c1f1c0204adcb5 /rust/zerocopy-derive/lib.rs | |
| download | linux-stable-aeb709c767aeca996e6011133e4f7bdb2a4af652.tar.gz linux-stable-aeb709c767aeca996e6011133e4f7bdb2a4af652.zip | |
selftests/bpf: Add a test for objects stuck in free_by_rcu_ttracegrafted
Delete all elements of BPF_F_NO_PREALLOC hash map in one batch. The first
free_bulk() starts RCU tasks trace GP and the rest of the elements are
freed while it's in flight. Wait for call_rcu_ttrace_in_progress to clear
in bpf_mem_cache of every cpu and check that free_by_rcu_ttrace and
waiting_for_gp_ttrace lists are empty.
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20260930095920.601738-4-alexei.starovoitov@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Diffstat (limited to 'rust/zerocopy-derive/lib.rs')
| -rw-r--r-- | rust/zerocopy-derive/lib.rs | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/rust/zerocopy-derive/lib.rs b/rust/zerocopy-derive/lib.rs new file mode 100644 index 000000000..d387de368 --- /dev/null +++ b/rust/zerocopy-derive/lib.rs @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT +// +// Copyright 2019 The Fuchsia Authors +// +// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 +// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Derive macros for [zerocopy]'s traits. +//! +//! [zerocopy]: https://docs.rs/zerocopy + +// Sometimes we want to use lints which were added after our MSRV. +// `unknown_lints` is `warn` by default and we deny warnings in CI, so without +// this attribute, any unknown lint would cause a CI failure when testing with +// our MSRV. +#![allow(unknown_lints)] +#![deny(renamed_and_removed_lints)] +#![deny( + clippy::all, + clippy::missing_safety_doc, + clippy::multiple_unsafe_ops_per_block, + clippy::undocumented_unsafe_blocks +)] +// We defer to own discretion on type complexity. +#![allow(clippy::type_complexity)] +// Inlining format args isn't supported on our MSRV. +#![allow(clippy::uninlined_format_args)] +#![deny( + rustdoc::bare_urls, + rustdoc::broken_intra_doc_links, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_html_tags, + rustdoc::invalid_rust_codeblocks, + rustdoc::missing_crate_level_docs, + rustdoc::private_intra_doc_links +)] +#![recursion_limit = "128"] + +macro_rules! ident { + (($fmt:literal $(, $arg:expr)*), $span:expr) => { + syn::Ident::new(&format!($fmt $(, crate::util::to_ident_str($arg))*), $span) + }; +} + +mod derive; +#[cfg(test)] +mod output_tests; +mod repr; +mod util; + +use syn::{DeriveInput, Error}; + +use crate::util::*; + +// FIXME(https://github.com/rust-lang/rust/issues/54140): Some errors could be +// made better if we could add multiple lines of error output like this: +// +// error: unsupported representation +// --> enum.rs:28:8 +// | +// 28 | #[repr(transparent)] +// | +// help: required by the derive of FromBytes +// +// Instead, we have more verbose error messages like "unsupported representation +// for deriving FromZeros, FromBytes, IntoBytes, or Unaligned on an enum" +// +// This will probably require Span::error +// (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error), +// which is currently unstable. Revisit this once it's stable. + +/// Defines a derive function named `$outer` which parses its input +/// `TokenStream` as a `DeriveInput` and then invokes the `$inner` function. +/// +/// Note that the separate `$outer` parameter is required - proc macro functions +/// are currently required to live at the crate root, and so the caller must +/// specify the name in order to avoid name collisions. +macro_rules! derive { + ($trait:ident => $outer:ident => $inner:path) => { + #[proc_macro_derive($trait, attributes(zerocopy))] + pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + let ctx = match Ctx::try_from_derive_input(ast) { + Ok(ctx) => ctx, + Err(e) => return e.into_compile_error().into(), + }; + let ts = $inner(&ctx, Trait::$trait).into_ts(); + // We wrap in `const_block` as a backstop in case any derive fails + // to wrap its output in `const_block` (and thus fails to annotate) + // with the full set of `#[allow(...)]` attributes). + let ts = const_block([Some(ts)]); + #[cfg(test)] + crate::util::testutil::check_hygiene(ts.clone()); + ts.into() + } + }; +} + +trait IntoTokenStream { + fn into_ts(self) -> proc_macro2::TokenStream; +} + +impl IntoTokenStream for proc_macro2::TokenStream { + fn into_ts(self) -> proc_macro2::TokenStream { + self + } +} + +impl IntoTokenStream for Result<proc_macro2::TokenStream, Error> { + fn into_ts(self) -> proc_macro2::TokenStream { + match self { + Ok(ts) => ts, + Err(err) => err.to_compile_error(), + } + } +} + +derive!(KnownLayout => derive_known_layout => crate::derive::known_layout::derive); +derive!(Immutable => derive_immutable => crate::derive::derive_immutable); +derive!(TryFromBytes => derive_try_from_bytes => crate::derive::try_from_bytes::derive_try_from_bytes); +derive!(FromZeros => derive_from_zeros => crate::derive::from_bytes::derive_from_zeros); +derive!(FromBytes => derive_from_bytes => crate::derive::from_bytes::derive_from_bytes); +derive!(IntoBytes => derive_into_bytes => crate::derive::into_bytes::derive_into_bytes); +derive!(Unaligned => derive_unaligned => crate::derive::unaligned::derive_unaligned); +derive!(ByteHash => derive_hash => crate::derive::derive_hash); +derive!(ByteEq => derive_eq => crate::derive::derive_eq); +derive!(SplitAt => derive_split_at => crate::derive::derive_split_at); + +#[cfg_attr(not(zerocopy_unstable_linux), doc(hidden))] +#[proc_macro_derive(most_traits, attributes(zerocopy))] +pub fn most_traits(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(ts as DeriveInput); + let ctx = match Ctx::try_from_derive_input(ast) { + Ok(ctx) => ctx, + Err(e) => return e.into_compile_error().into(), + } + .skip_on_error(); + + // top-level traits for which to attempt a derive + let derives: [(fn(&Ctx, Trait) -> _, _); 6] = [ + (crate::derive::known_layout::derive, Trait::KnownLayout), + (crate::derive::derive_immutable, Trait::Immutable), + (crate::derive::from_bytes::derive_from_bytes, Trait::FromBytes), + (crate::derive::into_bytes::derive_into_bytes, Trait::IntoBytes), + (crate::derive::derive_split_at, Trait::SplitAt), + (crate::derive::unaligned::derive_unaligned, Trait::Unaligned), + ]; + + let mut tokens = proc_macro2::TokenStream::new(); + for (derive, t) in derives { + tokens.extend(derive(&ctx, t)) + } + + // We wrap in `const_block` as a backstop in case any derive fails + // to wrap its output in `const_block` (and thus fails to annotate) + // with the full set of `#[allow(...)]` attributes). + let ts = const_block([Some(tokens)]); + #[cfg(test)] + crate::util::testutil::check_hygiene(ts.clone()); + ts.into() +} + +/// Deprecated: prefer [`FromZeros`] instead. +#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")] +#[doc(hidden)] +#[proc_macro_derive(FromZeroes)] +pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + derive_from_zeros(ts) +} + +/// Deprecated: prefer [`IntoBytes`] instead. +#[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")] +#[doc(hidden)] +#[proc_macro_derive(AsBytes)] +pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + derive_into_bytes(ts) +} |
