summaryrefslogtreecommitdiffstats
path: root/rust/zerocopy-derive/derive/mod.rs
diff options
context:
space:
mode:
authorYazen Ghannam <yazen.ghannam@amd.com>2026-09-03 10:43:25 -0500
committerBorislav Petkov (AMD) <bp@alien8.de>2026-09-10 18:05:43 -0700
commit27600805e62f800bacf990354632eae4e487d34c (patch)
treee8aec0ddfaa0bc264d79af632e3de3f1b75ae4c8 /rust/zerocopy-derive/derive/mod.rs
downloadlinux-stable-27600805e62f800bacf990354632eae4e487d34c.tar.gz
linux-stable-27600805e62f800bacf990354632eae4e487d34c.zip
x86/amd_node: Fix PCI device reference counting in amd_smn_init()grafted
The local "root" pointer is a temporary variable used during the device search. Therefore, refcount related to the search iterators should be cleaned up after the search is complete. Use the __free() cleanup macro to ensure the refcount is decremented when the temporary pointer goes out of scope. Additionally, increment the refcount when caching a root pointer. This ensures the in-use refcount is separate from the temporary search refcounting. Finally, drop the redundant "root = NULL" before the second search loop. The pci_get_class() iterator always decrements the refcount of its "from" argument, so the first loop can only fall through with "root" already NULL. Fixes: 0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching") Closes: https://sashiko.dev/#/patchset/20260806160159.230453-1-jason.andryuk%40amd.com Reported-by: Sashiko <sashiko-bot@kernel.org> Assisted-by: LLM Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Cc: <stable@kernel.org> Link: https://patch.msgid.link/20260903154325.74343-1-yazen.ghannam@amd.com
Diffstat (limited to 'rust/zerocopy-derive/derive/mod.rs')
-rw-r--r--rust/zerocopy-derive/derive/mod.rs136
1 files changed, 136 insertions, 0 deletions
diff --git a/rust/zerocopy-derive/derive/mod.rs b/rust/zerocopy-derive/derive/mod.rs
new file mode 100644
index 000000000..b3839fcf7
--- /dev/null
+++ b/rust/zerocopy-derive/derive/mod.rs
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
+//
+pub mod from_bytes;
+pub mod into_bytes;
+pub mod known_layout;
+pub mod try_from_bytes;
+pub mod unaligned;
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{Data, Error};
+
+use crate::{
+ repr::StructUnionRepr,
+ util::{Ctx, DataExt, FieldBounds, ImplBlockBuilder, Trait},
+};
+
+pub(crate) fn derive_immutable(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
+ Ok(match &ctx.ast.data {
+ Data::Struct(strct) => {
+ ImplBlockBuilder::new(ctx, strct, Trait::Immutable, FieldBounds::ALL_SELF).build()
+ }
+ Data::Enum(enm) => {
+ ImplBlockBuilder::new(ctx, enm, Trait::Immutable, FieldBounds::ALL_SELF).build()
+ }
+ Data::Union(unn) => {
+ ImplBlockBuilder::new(ctx, unn, Trait::Immutable, FieldBounds::ALL_SELF).build()
+ }
+ })
+}
+
+pub(crate) fn derive_hash(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
+ // This doesn't delegate to `impl_block` because `impl_block` assumes it is
+ // deriving a `zerocopy`-defined trait, and these trait impls share a common
+ // shape that `Hash` does not. In particular, `zerocopy` traits contain a
+ // method that only `zerocopy_derive` macros are supposed to implement, and
+ // `impl_block` generating this trait method is incompatible with `Hash`.
+ let type_ident = &ctx.ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
+ let where_predicates = where_clause.map(|clause| &clause.predicates);
+ let zerocopy_crate = &ctx.zerocopy_crate;
+ let core = ctx.core_path();
+ Ok(quote! {
+ impl #impl_generics #core::hash::Hash for #type_ident #ty_generics
+ where
+ Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
+ #where_predicates
+ {
+ fn hash<H: #core::hash::Hasher>(&self, state: &mut H) {
+ #core::hash::Hasher::write(state, #zerocopy_crate::IntoBytes::as_bytes(self))
+ }
+
+ fn hash_slice<H: #core::hash::Hasher>(data: &[Self], state: &mut H) {
+ #core::hash::Hasher::write(state, #zerocopy_crate::IntoBytes::as_bytes(data))
+ }
+ }
+ })
+}
+
+pub(crate) fn derive_eq(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
+ // This doesn't delegate to `impl_block` because `impl_block` assumes it is
+ // deriving a `zerocopy`-defined trait, and these trait impls share a common
+ // shape that `Eq` does not. In particular, `zerocopy` traits contain a
+ // method that only `zerocopy_derive` macros are supposed to implement, and
+ // `impl_block` generating this trait method is incompatible with `Eq`.
+ let type_ident = &ctx.ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
+ let where_predicates = where_clause.map(|clause| &clause.predicates);
+ let zerocopy_crate = &ctx.zerocopy_crate;
+ let core = ctx.core_path();
+ Ok(quote! {
+ impl #impl_generics #core::cmp::PartialEq for #type_ident #ty_generics
+ where
+ Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
+ #where_predicates
+ {
+ fn eq(&self, other: &Self) -> bool {
+ #core::cmp::PartialEq::eq(
+ #zerocopy_crate::IntoBytes::as_bytes(self),
+ #zerocopy_crate::IntoBytes::as_bytes(other),
+ )
+ }
+ }
+
+ impl #impl_generics #core::cmp::Eq for #type_ident #ty_generics
+ where
+ Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
+ #where_predicates
+ {
+ }
+ })
+}
+
+pub(crate) fn derive_split_at(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
+ let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
+
+ match &ctx.ast.data {
+ Data::Struct(_) => {}
+ Data::Enum(_) | Data::Union(_) => {
+ return ctx
+ .error_or_skip(Error::new(Span::call_site(), "can only be applied to structs"));
+ }
+ };
+
+ if repr.get_packed().is_some() {
+ return ctx.error_or_skip(Error::new(
+ Span::call_site(),
+ "must not have #[repr(packed)] attribute",
+ ));
+ }
+
+ if !(repr.is_c() || repr.is_transparent()) {
+ return ctx.error_or_skip(Error::new(
+ Span::call_site(),
+ "must have #[repr(C)] or #[repr(transparent)] in order to guarantee this type's layout is splitable",
+ ));
+ }
+
+ let fields = ctx.ast.data.fields();
+ let trailing_field = if let Some(((_, _, trailing_field), _)) = fields.split_last() {
+ trailing_field
+ } else {
+ return ctx.error_or_skip(Error::new(Span::call_site(), "must at least one field"));
+ };
+
+ let zerocopy_crate = &ctx.zerocopy_crate;
+ // SAFETY: `#ty`, per the above checks, is `repr(C)` or `repr(transparent)`
+ // and is not packed; its trailing field is guaranteed to be well-aligned
+ // for its type. By invariant on `FieldBounds::TRAILING_SELF`, the trailing
+ // slice of the trailing field is also well-aligned for its type.
+ Ok(ImplBlockBuilder::new(ctx, &ctx.ast.data, Trait::SplitAt, FieldBounds::TRAILING_SELF)
+ .inner_extras(quote! {
+ type Elem = <#trailing_field as #zerocopy_crate::SplitAt>::Elem;
+ })
+ .build())
+}