MAINTAINERS | 1 + drivers/block/rnull/configfs.rs | 2 +- rust/kernel/configfs.rs | 251 ---------------------------------------- rust/macros/configfs_attrs.rs | 182 +++++++++++++++++++++++++++++ rust/macros/lib.rs | 85 ++++++++++++++ samples/rust/rust_configfs.rs | 2 +- 6 files changed, 270 insertions(+), 253 deletions(-)
Implement `configfs_attrs!` as a procedural macro using `syn`, this
improves readability and maintainability. Remove the old macro and
replace all uses with the new macro. Add the new macro implementation
file to MAINTAINERS.
Signed-off-by: Malte Wechter <maltewechter@gmail.com>
---
MAINTAINERS | 1 +
drivers/block/rnull/configfs.rs | 2 +-
rust/kernel/configfs.rs | 251 ----------------------------------------
rust/macros/configfs_attrs.rs | 182 +++++++++++++++++++++++++++++
rust/macros/lib.rs | 85 ++++++++++++++
samples/rust/rust_configfs.rs | 2 +-
6 files changed, 270 insertions(+), 253 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd163..45f7a1ec93b45 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6464,6 +6464,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/a.hindborg/linux.git config
F: fs/configfs/
F: include/linux/configfs.h
F: rust/kernel/configfs.rs
+F: rust/macros/configfs_attrs.rs
F: samples/configfs/
F: samples/rust/rust_configfs.rs
diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 7c2eb5c0b7228..f28ec69d79846 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -4,8 +4,8 @@
use kernel::{
block::mq::gen_disk::{GenDisk, GenDiskBuilder},
configfs::{self, AttributeOperations},
- configfs_attrs,
fmt::{self, Write as _},
+ macros::configfs_attrs,
new_mutex,
page::PAGE_SIZE,
prelude::*,
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 2339c6467325d..7a91e36677f52 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -791,254 +791,3 @@ fn as_ptr(&self) -> *const bindings::config_item_type {
self.item_type.get()
}
}
-
-/// Define a list of configfs attributes statically.
-///
-/// Invoking the macro in the following manner:
-///
-/// ```ignore
-/// let item_type = configfs_attrs! {
-/// container: configfs::Subsystem<Configuration>,
-/// data: Configuration,
-/// child: Child,
-/// attributes: [
-/// message: 0,
-/// bar: 1,
-/// ],
-/// };
-/// ```
-///
-/// Expands the following output:
-///
-/// ```ignore
-/// let item_type = {
-/// static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<
-/// 0,
-/// Configuration,
-/// Configuration,
-/// > = unsafe {
-/// kernel::configfs::Attribute::new({
-/// const S: &str = "message\u{0}";
-/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
-/// S.as_bytes()
-/// ) {
-/// Ok(v) => v,
-/// Err(_) => {
-/// core::panicking::panic_fmt(core::const_format_args!(
-/// "string contains interior NUL"
-/// ));
-/// }
-/// };
-/// C
-/// })
-/// };
-///
-/// static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
-/// 1,
-/// Configuration,
-/// Configuration
-/// > = unsafe {
-/// kernel::configfs::Attribute::new({
-/// const S: &str = "bar\u{0}";
-/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
-/// S.as_bytes()
-/// ) {
-/// Ok(v) => v,
-/// Err(_) => {
-/// core::panicking::panic_fmt(core::const_format_args!(
-/// "string contains interior NUL"
-/// ));
-/// }
-/// };
-/// C
-/// })
-/// };
-///
-/// const N: usize = (1usize + (1usize + 0usize)) + 1usize;
-///
-/// static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =
-/// unsafe { kernel::configfs::AttributeList::new() };
-///
-/// {
-/// const N: usize = 0usize;
-/// unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };
-/// }
-///
-/// {
-/// const N: usize = (1usize + 0usize);
-/// unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };
-/// }
-///
-/// static CONFIGURATION_TPE:
-/// kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>
-/// = kernel::configfs::ItemType::<
-/// configfs::Subsystem<Configuration>,
-/// Configuration
-/// >::new_with_child_ctor::<N,Child>(
-/// &THIS_MODULE,
-/// &CONFIGURATION_ATTRS
-/// );
-///
-/// &CONFIGURATION_TPE
-/// }
-/// ```
-#[macro_export]
-macro_rules! configfs_attrs {
- (
- container: $container:ty,
- data: $data:ty,
- attributes: [
- $($name:ident: $attr:literal),* $(,)?
- ] $(,)?
- ) => {
- $crate::configfs_attrs!(
- count:
- @container($container),
- @data($data),
- @child(),
- @no_child(x),
- @attrs($($name $attr)*),
- @eat($($name $attr,)*),
- @assign(),
- @cnt(0usize),
- )
- };
- (
- container: $container:ty,
- data: $data:ty,
- child: $child:ty,
- attributes: [
- $($name:ident: $attr:literal),* $(,)?
- ] $(,)?
- ) => {
- $crate::configfs_attrs!(
- count:
- @container($container),
- @data($data),
- @child($child),
- @no_child(),
- @attrs($($name $attr)*),
- @eat($($name $attr,)*),
- @assign(),
- @cnt(0usize),
- )
- };
- (count:
- @container($container:ty),
- @data($data:ty),
- @child($($child:ty)?),
- @no_child($($no_child:ident)?),
- @attrs($($aname:ident $aattr:literal)*),
- @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),
- @assign($($assign:block)*),
- @cnt($cnt:expr),
- ) => {
- $crate::configfs_attrs!(
- count:
- @container($container),
- @data($data),
- @child($($child)?),
- @no_child($($no_child)?),
- @attrs($($aname $aattr)*),
- @eat($($rname $rattr,)*),
- @assign($($assign)* {
- const N: usize = $cnt;
- // The following macro text expands to a call to `Attribute::add`.
-
- // SAFETY: By design of this macro, the name of the variable we
- // invoke the `add` method on below, is not visible outside of
- // the macro expansion. The macro does not operate concurrently
- // on this variable, and thus we have exclusive access to the
- // variable.
- unsafe {
- $crate::macros::paste!(
- [< $data:upper _ATTRS >]
- .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])
- )
- };
- }),
- @cnt(1usize + $cnt),
- )
- };
- (count:
- @container($container:ty),
- @data($data:ty),
- @child($($child:ty)?),
- @no_child($($no_child:ident)?),
- @attrs($($aname:ident $aattr:literal)*),
- @eat(),
- @assign($($assign:block)*),
- @cnt($cnt:expr),
- ) =>
- {
- $crate::configfs_attrs!(
- final:
- @container($container),
- @data($data),
- @child($($child)?),
- @no_child($($no_child)?),
- @attrs($($aname $aattr)*),
- @assign($($assign)*),
- @cnt($cnt),
- )
- };
- (final:
- @container($container:ty),
- @data($data:ty),
- @child($($child:ty)?),
- @no_child($($no_child:ident)?),
- @attrs($($name:ident $attr:literal)*),
- @assign($($assign:block)*),
- @cnt($cnt:expr),
- ) =>
- {
- $crate::macros::paste!{
- {
- $(
- // SAFETY: We are expanding `configfs_attrs`.
- static [< $data:upper _ $name:upper _ATTR >]:
- $crate::configfs::Attribute<$attr, $data, $data> =
- unsafe {
- $crate::configfs::Attribute::new(
- $crate::c_str!(::core::stringify!($name)),
- )
- };
- )*
-
-
- // We need space for a null terminator.
- const N: usize = $cnt + 1usize;
-
- // SAFETY: We are expanding `configfs_attrs`.
- static [< $data:upper _ATTRS >]:
- $crate::configfs::AttributeList<N, $data> =
- unsafe { $crate::configfs::AttributeList::new() };
-
- $($assign)*
-
- $(
- const [<$no_child:upper>]: bool = true;
-
- static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> =
- $crate::configfs::ItemType::<$container, $data>::new::<N>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
- );
- )?
-
- $(
- static [< $data:upper _TPE >]:
- $crate::configfs::ItemType<$container, $data> =
- $crate::configfs::ItemType::<$container, $data>::
- new_with_child_ctor::<N, $child>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
- );
- )?
-
- & [< $data:upper _TPE >]
- }
- }
- };
-
-}
-
-pub use crate::configfs_attrs;
diff --git a/rust/macros/configfs_attrs.rs b/rust/macros/configfs_attrs.rs
new file mode 100644
index 0000000000000..f5c3a8d9bffbd
--- /dev/null
+++ b/rust/macros/configfs_attrs.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use quote::{
+ quote, //
+ ToTokens,
+};
+
+use proc_macro2::{
+ Span, //
+};
+
+use syn::{
+ bracketed,
+ parse::{
+ Parse,
+ ParseStream, //
+ },
+ punctuated::Punctuated,
+ spanned::Spanned,
+ Ident,
+ LitInt,
+ Token,
+ Type, //
+};
+
+pub(crate) struct ConfigfsAttrs {
+ container: Type,
+ data: Type,
+ child: Option<Type>,
+ attributes: Vec<(Ident, LitInt)>,
+}
+
+fn parse_attribute_field(stream: ParseStream<'_>) -> syn::Result<(Ident, LitInt)> {
+ let id = stream.parse::<syn::Ident>()?;
+ let _colon = stream.parse::<Token![:]>()?;
+ let v = stream.parse::<LitInt>()?;
+ Ok((id, v))
+}
+
+fn parse_named_field(stream: ParseStream<'_>, name: &str) -> syn::Result<Type> {
+ let try_stream = stream.fork();
+ let name_id = try_stream.parse::<Ident>()?;
+ if name_id != name {
+ return Err(parse_field_error(name_id.span(), &name_id, name));
+ }
+ let _name_id = stream.parse::<Ident>()?;
+ let _colon = stream.parse::<Token![:]>()?;
+ let v = stream.parse::<Type>()?;
+ stream.parse::<Token![,]>()?;
+ Ok(v)
+}
+
+fn parse_attributes(stream: ParseStream<'_>) -> syn::Result<Vec<(Ident, LitInt)>> {
+ let attribute_id = stream.parse::<Ident>()?;
+ if attribute_id != "attributes" {
+ return Err(syn::Error::new(
+ attribute_id.span(),
+ format!(
+ "unexpected identifier: {}, expected: 'attributes'",
+ attribute_id
+ ),
+ ));
+ }
+ stream.parse::<Token![:]>()?;
+ let attr_stream;
+ let _bracket = bracketed!(attr_stream in stream);
+ let attributes = Punctuated::<(Ident, LitInt), Token![,]>::parse_terminated_with(
+ &attr_stream,
+ parse_attribute_field,
+ )?;
+ let attributes = attributes.into_iter().collect::<Vec<_>>();
+
+ stream.parse::<Option<Token![,]>>()?;
+ Ok(attributes)
+}
+
+fn parse_field_error(span: Span, name: &Ident, expected_name: &str) -> syn::Error {
+ syn::Error::new(
+ span,
+ format!("Unexpected field name, got: {name} expected: {expected_name}"),
+ )
+}
+
+impl Parse for ConfigfsAttrs {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let container = parse_named_field(input, "container")?;
+ let data = parse_named_field(input, "data")?;
+ let child = parse_named_field(input, "child").ok();
+ let attributes = parse_attributes(input)?;
+
+ Ok(ConfigfsAttrs {
+ container,
+ data,
+ child,
+ attributes,
+ })
+ }
+}
+
+fn make_static_ident<T: ToTokens>(ty: &T, suffix: &str) -> syn::Ident {
+ let raw_id = quote! { #ty }.to_string();
+
+ // Sanitizing syn::Type::Path, this is safe since it is
+ // only used as the identifier.
+ let normalized = raw_id
+ .split("::")
+ .map(|s| String::from(s.trim()))
+ .reduce(|a, b| format!("{a}_{b}"))
+ .expect("Cannot be empty")
+ .to_uppercase()
+ .replace(|c: char| !c.is_alphanumeric(), "_");
+
+ Ident::new(&format!("{}_{}", normalized, suffix), ty.span())
+}
+
+pub(crate) fn configfs_attrs(cfs_attrs: ConfigfsAttrs) -> proc_macro2::TokenStream {
+ let (container_ty, data_ty) = (&cfs_attrs.container, &cfs_attrs.data);
+
+ let data_tp_ident = make_static_ident(data_ty, "TPE");
+ let data_attr_ident = make_static_ident(data_ty, "ATTR_LIST");
+
+ let n = cfs_attrs.attributes.len() + 1;
+
+ let attr_list = quote! {
+ static #data_attr_ident: kernel::configfs::AttributeList<#n, #data_ty> =
+ // SAFETY: We are expanding `configfs_attrs`.
+ unsafe { kernel::configfs::AttributeList::new() };
+ };
+
+ let mut attrs = Vec::new();
+ for (attr_idx, (name, id)) in cfs_attrs.attributes.iter().enumerate() {
+ let name_with_attr = make_static_ident(name, "ATTR");
+
+ let id: u64 = match id.base10_parse::<u64>() {
+ Ok(v) => v,
+ Err(_) => {
+ return syn::Error::new(id.span(), "Could not parse attribute ID as a u64")
+ .to_compile_error();
+ }
+ };
+
+ attrs.push(quote! {
+ static #name_with_attr: kernel::configfs::Attribute<#id, #data_ty, #data_ty> =
+ // SAFETY: We are expanding `configfs_attrs`.
+ unsafe {
+ kernel::configfs::Attribute::new(kernel::c_str!(::core::stringify!(#name)))
+ };
+
+ // SAFETY: By design of this macro, the name of the variable we
+ // invoke the `add` method on below, is not visible outside of
+ // the macro expansion. The macro does not operate concurrently
+ // on this variable, and thus we have exclusive access to the
+ // variable.
+ unsafe { #data_attr_ident.add::<#attr_idx, #id, _>(&#name_with_attr) }
+ });
+ }
+
+ let has_child_code = if let Some(child) = cfs_attrs.child {
+ quote! { new_with_child_ctor::<#n, #child>}
+ } else {
+ quote! { new::<#n> }
+ };
+
+ let data_type = quote! {
+ {
+ static #data_tp_ident:
+ kernel::configfs::ItemType<#container_ty, #data_ty> =
+ kernel::configfs::ItemType::<#container_ty, #data_ty>::#has_child_code(
+ &THIS_MODULE, &#data_attr_ident
+ );
+ &#data_tp_ident
+ }
+ };
+
+ quote! {
+ {
+ #attr_list
+ #(#attrs)*
+ #data_type
+ }
+ }
+}
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 2cfd59e0f9e7c..745ba83c828b9 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -15,6 +15,8 @@
#![cfg_attr(not(CONFIG_RUSTC_HAS_SPAN_FILE), feature(proc_macro_span))]
mod concat_idents;
+#[cfg(CONFIG_CONFIGFS_FS)]
+mod configfs_attrs;
mod export;
mod fmt;
mod helpers;
@@ -489,3 +491,86 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {
.unwrap_or_else(|e| e.into_compile_error())
.into()
}
+
+/// Define a list of configfs attributes statically.
+///
+/// # Examples
+///
+/// ```ignore
+/// let item_type = configfs_attrs! {
+/// container: configfs::Subsystem<Configuration>,
+/// data: Configuration,
+/// child: Child,
+/// attributes: [
+/// message: 0,
+/// bar: 1,
+/// ],
+/// };
+///```
+///
+/// Expands the following output:
+/// let item_type = {
+/// static CONFIGURATION_ATTR_LIST: kernel::configfs::AttributeList<
+/// 3usize,
+/// Configuration,
+/// > = unsafe { kernel::configfs::AttributeList::new() };
+/// static MESSAGE_ATTR: kernel::configfs::Attribute<
+/// 0u64,
+/// Configuration,
+/// Configuration,
+/// > = unsafe {
+/// kernel::configfs::Attribute::new({
+/// const S: &str = "message\u{0}";
+/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
+/// S.as_bytes(),
+/// ) {
+/// Ok(v) => v,
+/// Err(_) => {
+/// ::core::panicking::panic_fmt(
+/// format_args!("string contains interior NUL"),
+/// );
+/// }
+/// };
+/// C
+/// })
+/// };
+/// unsafe { CONFIGURATION_ATTR_LIST.add::<0usize, 0u64, _>(&MESSAGE_ATTR) }
+/// static BAR_ATTR: kernel::configfs::Attribute<
+/// 1u64,
+/// Configuration,
+/// Configuration,
+/// > = unsafe {
+/// kernel::configfs::Attribute::new({
+/// const S: &str = "bar\u{0}";
+/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
+/// S.as_bytes(),
+/// ) {
+/// Ok(v) => v,
+/// Err(_) => {
+/// ::core::panicking::panic_fmt(
+/// format_args!("string contains interior NUL"),
+/// );
+/// }
+/// };
+/// C
+/// })
+/// };
+/// unsafe { CONFIGURATION_ATTR_LIST.add::<1usize, 1u64, _>(&BAR_ATTR) }
+/// {
+/// static CONFIGURATION_TPE: kernel::configfs::ItemType<
+/// Subsystem<Configuration>,
+/// Configuration,
+/// > = kernel::configfs::ItemType::<
+/// Subsystem<Configuration>,
+/// Configuration,
+/// >::new_with_child_ctor::<3usize, Child>(&THIS_MODULE, &CONFIGURATION_ATTR_LIST);
+/// &CONFIGURATION_TPE
+/// }
+/// };
+///
+#[cfg(CONFIG_CONFIGFS_FS)]
+#[proc_macro]
+pub fn configfs_attrs(input: TokenStream) -> TokenStream {
+ configfs_attrs::configfs_attrs(parse_macro_input!(input as configfs_attrs::ConfigfsAttrs))
+ .into()
+}
diff --git a/samples/rust/rust_configfs.rs b/samples/rust/rust_configfs.rs
index a1bd9db6010da..876462f7789d1 100644
--- a/samples/rust/rust_configfs.rs
+++ b/samples/rust/rust_configfs.rs
@@ -4,7 +4,7 @@
use kernel::alloc::flags;
use kernel::configfs;
-use kernel::configfs::configfs_attrs;
+use kernel::macros::configfs_attrs;
use kernel::new_mutex;
use kernel::page::PAGE_SIZE;
use kernel::prelude::*;
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260417-configfs-syn-191e07130027
Best regards,
--
Malte Wechter <maltewechter@gmail.com>
On Wed May 20, 2026 at 9:40 AM CEST, Malte Wechter wrote:
> Implement `configfs_attrs!` as a procedural macro using `syn`, this
> improves readability and maintainability. Remove the old macro and
> replace all uses with the new macro. Add the new macro implementation
> file to MAINTAINERS.
The current declarative macro implementation is quite readable and IMO more so
than this syn rewrite.
Unless there's a compelling use case where it needs to be implememented using
token munchers with declarative macro but can be easily parsed with proc macro,
I think it should just stay as decl macro.
>
> Signed-off-by: Malte Wechter <maltewechter@gmail.com>
> ---
> MAINTAINERS | 1 +
> drivers/block/rnull/configfs.rs | 2 +-
> rust/kernel/configfs.rs | 251 ----------------------------------------
> rust/macros/configfs_attrs.rs | 182 +++++++++++++++++++++++++++++
> rust/macros/lib.rs | 85 ++++++++++++++
> samples/rust/rust_configfs.rs | 2 +-
> 6 files changed, 270 insertions(+), 253 deletions(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2fb1c75afd163..45f7a1ec93b45 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6464,6 +6464,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/a.hindborg/linux.git config
> F: fs/configfs/
> F: include/linux/configfs.h
> F: rust/kernel/configfs.rs
> +F: rust/macros/configfs_attrs.rs
> F: samples/configfs/
> F: samples/rust/rust_configfs.rs
>
> diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
> index 7c2eb5c0b7228..f28ec69d79846 100644
> --- a/drivers/block/rnull/configfs.rs
> +++ b/drivers/block/rnull/configfs.rs
> @@ -4,8 +4,8 @@
> use kernel::{
> block::mq::gen_disk::{GenDisk, GenDiskBuilder},
> configfs::{self, AttributeOperations},
> - configfs_attrs,
> fmt::{self, Write as _},
> + macros::configfs_attrs,
Except for very generics things like `paste` or `concat_idents`, other things
should not live in kernel::macros (or from top-level) but be re-exported from
subsystems.
Best,
Gary
> new_mutex,
> page::PAGE_SIZE,
> prelude::*,
> diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
"Gary Guo" <gary@garyguo.net> writes: > On Wed May 20, 2026 at 9:40 AM CEST, Malte Wechter wrote: >> Implement `configfs_attrs!` as a procedural macro using `syn`, this >> improves readability and maintainability. Remove the old macro and >> replace all uses with the new macro. Add the new macro implementation >> file to MAINTAINERS. > > The current declarative macro implementation is quite readable and IMO more so > than this syn rewrite. > > Unless there's a compelling use case where it needs to be implememented using > token munchers with declarative macro but can be easily parsed with proc macro, > I think it should just stay as decl macro. I disagree. I think the proc macro is difficult to read and maintain, and I prefer a procedural parser. Best regards, Andreas Hindborg
Hi Malte, kernel test robot noticed the following build warnings: [auto build test WARNING on 254f49634ee16a731174d2ae34bc50bd5f45e731] url: https://github.com/intel-lab-lkp/linux/commits/Malte-Wechter/rust-add-procedural-macro-for-declaring-configfs-attributes/20260520-154816 base: 254f49634ee16a731174d2ae34bc50bd5f45e731 patch link: https://lore.kernel.org/r/20260520-configfs-syn-v1-1-6c5b80a9cef2%40gmail.com patch subject: [PATCH] rust: add procedural macro for declaring configfs attributes config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260520/202605201854.YArCKAtw-lkp@intel.com/config) compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261) rustc: rustc 1.88.0 (6b00bc388 2025-06-23) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260520/202605201854.YArCKAtw-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202605201854.YArCKAtw-lkp@intel.com/ All warnings (new ones prefixed by >>): >> warning: unclosed HTML tag `Configuration` --> rust/macros/lib.rs:561:30 | 561 | /// Subsystem<Configuration>, | ^^^^^^^^^^^^^^^ | = note: `#[warn(rustdoc::invalid_html_tags)]` on by default help: try marking as source code | 561 | /// `Subsystem<Configuration>`, | + + -- >> warning: unclosed HTML tag `Configuration` --> rust/macros/lib.rs:564:30 | 564 | /// Subsystem<Configuration>, | ^^^^^^^^^^^^^^^ | help: try marking as source code | 564 | /// `Subsystem<Configuration>`, | + + -- >> warning: unresolved link to `crate::configfs_attrs` --> rust/kernel/configfs.rs:240:1 | 240 | / /// A configfs group. 241 | | /// 242 | | /// To add a subgroup to configfs, pass this type as `ctype` to 243 | | /// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`]. | |_______________________________________________________________________________________^ | = note: the link appears in this line: -- >> warning: unresolved link to `kernel::configfs_attrs` --> rust/kernel/configfs.rs:630:1 | 630 | / /// Operations supported by an attribute. 631 | | /// 632 | | /// Implement this trait on type and pass that type as generic parameter when 633 | | /// creating an [`Attribute`]. The type carrying the implementation serve no ... | 640 | | /// attributes via the [`kernel::configfs_attrs`] macro, to tie 641 | | /// `AttributeOperations` implementations to concrete named attributes. | |_______________________________________________________________________^ | = note: the link appears in this line: -- >> warning: unresolved link to `kernel::configfs_attrs` --> rust/kernel/configfs.rs:672:7 | 672 | /// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a | ^^^^^^^^^^^^^^^^^^^^^^ no item named `configfs_attrs` in module `kernel` -- >> warning: unresolved link to `kernel::configfs_attrs` --> rust/kernel/configfs.rs:678:7 | 678 | /// [`kernel::configfs_attrs`] macro. | ^^^^^^^^^^^^^^^^^^^^^^ no item named `configfs_attrs` in module `kernel` -- >> warning: unresolved link to `kernel::configfs_attrs` --> rust/kernel/configfs.rs:723:1 | 723 | / /// A representation of the attributes that will appear in a [`Group`] or 724 | | /// [`Subsystem`]. 725 | | /// 726 | | /// Users should not directly instantiate objects of this type. Rather, they 727 | | /// should use the [`kernel::configfs_attrs`] macro to statically declare the 728 | | /// shape of a [`Group`] or [`Subsystem`]. | |__________________________________________^ | = note: the link appears in this line: -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.