From 8b3d955f72f999ccce26aabdeb09939964d05a61 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Thu, 29 May 2025 10:10:23 +0200 Subject: [PATCH 01/84] rust: pin-init: improve safety documentation for `impl [Pin]Init for T` The inner SAFETY comments were missing since commit 5cfe7bef6751 ("rust: enable `clippy::undocumented_unsafe_blocks` lint"). Also rework the implementation of `__pinned_init` to better justify the SAFETY comment. Link: https://github.com/Rust-for-Linux/pin-init/pull/62/commits/df925b2e27d499b7144df7e62b01acb00d4b94b8 Reviewed-by: Boqun Feng Link: https://lore.kernel.org/all/20250529081027.297648-1-lossin@kernel.org Signed-off-by: Benno Lossin --- rust/pin-init/src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 9ab34036e6bc..d1c3ca5cfff4 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1390,20 +1390,22 @@ pub fn pin_init_array_from_fn( unsafe { pin_init_from_closure(init) } } -// SAFETY: Every type can be initialized by-value. +// SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. unsafe impl Init for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: TODO. + // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) } } -// SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. +// SAFETY: the `__pinned_init` function always returns `Ok(())` and initializes every field of +// `slot`. Additionally, all pinning invariants of `T` are upheld. unsafe impl PinInit for T { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: TODO. - unsafe { self.__init(slot) } + // SAFETY: `slot` is valid for writes by the safety requirements of this function. + unsafe { slot.write(self) }; + Ok(()) } } From e832374ccadf4d1ce7bd40a85b9320bd7fbb3628 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Thu, 29 May 2025 10:10:24 +0200 Subject: [PATCH 02/84] rust: pin-init: change blanket impls for `[Pin]Init` and add one for `Result` Remove the error from the blanket implementations `impl Init for T` (and also for `PinInit`). Add implementations for `Result`. This allows one to easily construct (un)conditional failing initializers. It also improves the compatibility with APIs that do not use pin-init, because users can supply a `Result` to a function taking an `impl PinInit`. Suggested-by: Alice Ryhl Link: https://github.com/Rust-for-Linux/pin-init/pull/62/commits/58612514b256c6f4a4a0718be25298410e67387a [ Also fix a compile error in block. - Benno ] Reviewed-by: Boqun Feng Link: https://lore.kernel.org/all/20250529081027.297648-2-lossin@kernel.org [ Add title prefix `rust: pin-init`. - Benno ] Signed-off-by: Benno Lossin --- rust/kernel/block/mq/tag_set.rs | 12 +++++++----- rust/pin-init/src/lib.rs | 30 ++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index bcf4214ad149..c3cf56d52bee 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -9,7 +9,7 @@ use crate::{ bindings, block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations}, - error, + error::{self, Result}, prelude::try_pin_init, types::Opaque, }; @@ -41,7 +41,7 @@ pub fn new( // SAFETY: `blk_mq_tag_set` only contains integers and pointers, which // all are allowed to be 0. let tag_set: bindings::blk_mq_tag_set = unsafe { core::mem::zeroed() }; - let tag_set = core::mem::size_of::() + let tag_set: Result<_> = core::mem::size_of::() .try_into() .map(|cmd_size| { bindings::blk_mq_tag_set { @@ -56,12 +56,14 @@ pub fn new( nr_maps: num_maps, ..tag_set } - }); + }) + .map(Opaque::new) + .map_err(|e| e.into()); try_pin_init!(TagSet { - inner <- PinInit::<_, error::Error>::pin_chain(Opaque::new(tag_set?), |tag_set| { + inner <- tag_set.pin_chain(|tag_set| { // SAFETY: we do not move out of `tag_set`. - let tag_set = unsafe { Pin::get_unchecked_mut(tag_set) }; + let tag_set: &mut Opaque<_> = unsafe { Pin::get_unchecked_mut(tag_set) }; // SAFETY: `tag_set` is a reference to an initialized `blk_mq_tag_set`. error::to_result( unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())}) }), diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index d1c3ca5cfff4..f4e034497cdd 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1391,8 +1391,8 @@ pub fn pin_init_array_from_fn( } // SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. -unsafe impl Init for T { - unsafe fn __init(self, slot: *mut T) -> Result<(), E> { +unsafe impl Init for T { + unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) @@ -1401,14 +1401,36 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: the `__pinned_init` function always returns `Ok(())` and initializes every field of // `slot`. Additionally, all pinning invariants of `T` are upheld. -unsafe impl PinInit for T { - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { +unsafe impl PinInit for T { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) } } +// SAFETY: when the `__init` function returns with +// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. +// - `Err(err)`, slot was not written to. +unsafe impl Init for Result { + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `slot` is valid for writes by the safety requirements of this function. + unsafe { slot.write(self?) }; + Ok(()) + } +} + +// SAFETY: when the `__pinned_init` function returns with +// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. +// - `Err(err)`, slot was not written to. +unsafe impl PinInit for Result { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `slot` is valid for writes by the safety requirements of this function. + unsafe { slot.write(self?) }; + Ok(()) + } +} + /// Smart pointer containing uninitialized memory and that can write a value. pub trait InPlaceWrite { /// The type `Self` turns into when the contents are initialized. From a2801affa7103862d549050401a9f53b3365fca4 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:00 +0200 Subject: [PATCH 03/84] rust: device: Create FwNode abstraction for accessing device properties Accessing device properties is currently done via methods on `Device` itself, using bindings to device_property_* functions. This is sufficient for the existing method property_present. However, it's not sufficient for other device properties we want to access. For example, iterating over child nodes of a device will yield a fwnode_handle. That's not a device, so it wouldn't be possible to read the properties of that child node. Thus, we need an abstraction over fwnode_handle and methods for reading its properties. Add a struct FwNode which abstracts over the C struct fwnode_handle. Implement its reference counting analogous to other Rust abstractions over reference-counted C structs. Subsequent patches will add functionality to access FwNode and read properties with it. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-2-remo@buenzli.dev [ Add temporary #[expect(dead_code)] to avoid a warning. - Danilo ] Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + rust/helpers/helpers.c | 1 + rust/helpers/property.c | 8 ++++ rust/kernel/device.rs | 2 + rust/kernel/device/property.rs | 74 ++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 rust/helpers/property.c create mode 100644 rust/kernel/device/property.rs diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa16..9f724cd556f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7366,6 +7366,7 @@ F: include/linux/property.h F: include/linux/sysfs.h F: lib/kobj* F: rust/kernel/device.rs +F: rust/kernel/device/ F: rust/kernel/device_id.rs F: rust/kernel/devres.rs F: rust/kernel/driver.rs diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0f1b5d115985..ed00695af971 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -30,6 +30,7 @@ #include "platform.c" #include "pci.c" #include "pid_namespace.c" +#include "property.c" #include "rbtree.c" #include "rcu.c" #include "refcount.c" diff --git a/rust/helpers/property.c b/rust/helpers/property.c new file mode 100644 index 000000000000..08f68e2dac4a --- /dev/null +++ b/rust/helpers/property.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_fwnode_handle_put(struct fwnode_handle *fwnode) +{ + fwnode_handle_put(fwnode); +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index dea06b79ecb5..d6237827a936 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -14,6 +14,8 @@ #[cfg(CONFIG_PRINTK)] use crate::c_str; +pub mod property; + /// A reference-counted device. /// /// This structure represents the Rust abstraction for a C `struct device`. This implementation diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs new file mode 100644 index 000000000000..82ef54b54f18 --- /dev/null +++ b/rust/kernel/device/property.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Unified device property interface. +//! +//! C header: [`include/linux/property.h`](srctree/include/linux/property.h) + +use core::ptr; + +use crate::{ + bindings, + types::{ARef, Opaque}, +}; + +/// A reference-counted fwnode_handle. +/// +/// This structure represents the Rust abstraction for a +/// C `struct fwnode_handle`. This implementation abstracts the usage of an +/// already existing C `struct fwnode_handle` within Rust code that we get +/// passed from the C side. +/// +/// # Invariants +/// +/// A `FwNode` instance represents a valid `struct fwnode_handle` created by the +/// C portion of the kernel. +/// +/// Instances of this type are always reference-counted, that is, a call to +/// `fwnode_handle_get` ensures that the allocation remains valid at least until +/// the matching call to `fwnode_handle_put`. +#[repr(transparent)] +pub struct FwNode(Opaque); + +impl FwNode { + /// # Safety + /// + /// Callers must ensure that: + /// - The reference count was incremented at least once. + /// - They relinquish that increment. That is, if there is only one + /// increment, callers must not use the underlying object anymore -- it is + /// only safe to do so via the newly created `ARef`. + #[expect(dead_code)] + unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef { + // SAFETY: As per the safety requirements of this function: + // - `NonNull::new_unchecked`: + // - `raw` is not null. + // - `ARef::from_raw`: + // - `raw` has an incremented refcount. + // - that increment is relinquished, i.e. it won't be decremented + // elsewhere. + // CAST: It is safe to cast from a `*mut fwnode_handle` to + // `*mut FwNode`, because `FwNode` is defined as a + // `#[repr(transparent)]` wrapper around `fwnode_handle`. + unsafe { ARef::from_raw(ptr::NonNull::new_unchecked(raw.cast())) } + } + + /// Obtain the raw `struct fwnode_handle *`. + pub(crate) fn as_raw(&self) -> *mut bindings::fwnode_handle { + self.0.get() + } +} + +// SAFETY: Instances of `FwNode` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for FwNode { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the + // refcount is non-zero. + unsafe { bindings::fwnode_handle_get(self.as_raw()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is + // non-zero. + unsafe { bindings::fwnode_handle_put(obj.cast().as_ptr()) } + } +} From 658f23b59251e15cc9263cfe5157d5757a293017 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:01 +0200 Subject: [PATCH 04/84] rust: device: Enable accessing the FwNode of a Device Subsequent patches will add methods for reading properties to FwNode. The first step to accessing these methods will be to access the "root" FwNode of a Device. Add the method `fwnode` to `Device`. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-3-remo@buenzli.dev Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index d6237827a936..48d45af1cfb2 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -205,6 +205,21 @@ unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) { }; } + /// Obtain the [`FwNode`](property::FwNode) corresponding to this [`Device`]. + pub fn fwnode(&self) -> Option<&property::FwNode> { + // SAFETY: `self` is valid. + let fwnode_handle = unsafe { bindings::__dev_fwnode(self.as_raw()) }; + if fwnode_handle.is_null() { + return None; + } + // SAFETY: `fwnode_handle` is valid. Its lifetime is tied to `&self`. We + // return a reference instead of an `ARef` because `dev_fwnode()` + // doesn't increment the refcount. It is safe to cast from a + // `struct fwnode_handle*` to a `*const FwNode` because `FwNode` is + // defined as a `#[repr(transparent)]` wrapper around `fwnode_handle`. + Some(unsafe { &*fwnode_handle.cast() }) + } + /// Checks if property is present or not. pub fn property_present(&self, name: &CStr) -> bool { // SAFETY: By the invariant of `CStr`, `name` is null-terminated. From d3393e845038f5fd32c24b841bb4b6026aa1cf4b Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:02 +0200 Subject: [PATCH 05/84] rust: device: Move property_present() to FwNode The new FwNode abstraction will be used for accessing all device properties. It would be possible to duplicate the methods on the device itself, but since some of the methods on Device would have different type sigatures as the ones on FwNode, this would only lead to inconsistency and confusion. For this reason, property_present is removed from Device and existing users are updated. Acked-by: Viresh Kumar Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-4-remo@buenzli.dev Signed-off-by: Danilo Krummrich --- drivers/cpufreq/rcpufreq_dt.rs | 3 ++- rust/kernel/device.rs | 7 ------- rust/kernel/device/property.rs | 7 +++++++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index 94ed81644fe1..4eb240dc9fdc 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -20,7 +20,8 @@ /// Finds exact supply name from the OF node. fn find_supply_name_exact(dev: &Device, name: &str) -> Option { let prop_name = CString::try_from_fmt(fmt!("{}-supply", name)).ok()?; - dev.property_present(&prop_name) + dev.fwnode()? + .property_present(&prop_name) .then(|| CString::try_from_fmt(fmt!("{name}")).ok()) .flatten() } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 48d45af1cfb2..665f5ceadecc 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -6,7 +6,6 @@ use crate::{ bindings, - str::CStr, types::{ARef, Opaque}, }; use core::{fmt, marker::PhantomData, ptr}; @@ -219,12 +218,6 @@ pub fn fwnode(&self) -> Option<&property::FwNode> { // defined as a `#[repr(transparent)]` wrapper around `fwnode_handle`. Some(unsafe { &*fwnode_handle.cast() }) } - - /// Checks if property is present or not. - pub fn property_present(&self, name: &CStr) -> bool { - // SAFETY: By the invariant of `CStr`, `name` is null-terminated. - unsafe { bindings::device_property_present(self.as_raw().cast_const(), name.as_char_ptr()) } - } } // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 82ef54b54f18..ed17b20f7ae1 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -8,6 +8,7 @@ use crate::{ bindings, + str::CStr, types::{ARef, Opaque}, }; @@ -56,6 +57,12 @@ unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef { pub(crate) fn as_raw(&self) -> *mut bindings::fwnode_handle { self.0.get() } + + /// Checks if property is present or not. + pub fn property_present(&self, name: &CStr) -> bool { + // SAFETY: By the invariant of `CStr`, `name` is null-terminated. + unsafe { bindings::fwnode_property_present(self.as_raw().cast_const(), name.as_char_ptr()) } + } } // SAFETY: Instances of `FwNode` are always reference-counted. From ecea2459818383c2886ec1cff81cce7e70d99893 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:03 +0200 Subject: [PATCH 06/84] rust: device: Enable printing fwnode name and path Add two new public methods `display_name` and `display_path` to `FwNode`. They can be used by driver authors for logging purposes. In addition, they will be used by core property abstractions for automatic logging, for example when a driver attempts to read a required but missing property. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-5-remo@buenzli.dev [ Remove #[expect(dead_code)] from FwNode::from_raw(). - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device/property.rs | 77 +++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index ed17b20f7ae1..4cac335bad78 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -38,7 +38,6 @@ impl FwNode { /// - They relinquish that increment. That is, if there is only one /// increment, callers must not use the underlying object anymore -- it is /// only safe to do so via the newly created `ARef`. - #[expect(dead_code)] unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef { // SAFETY: As per the safety requirements of this function: // - `NonNull::new_unchecked`: @@ -58,6 +57,32 @@ pub(crate) fn as_raw(&self) -> *mut bindings::fwnode_handle { self.0.get() } + /// Returns an object that implements [`Display`](core::fmt::Display) for + /// printing the name of a node. + /// + /// This is an alternative to the default `Display` implementation, which + /// prints the full path. + pub fn display_name(&self) -> impl core::fmt::Display + '_ { + struct FwNodeDisplayName<'a>(&'a FwNode); + + impl core::fmt::Display for FwNodeDisplayName<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // SAFETY: `self` is valid by its type invariant. + let name = unsafe { bindings::fwnode_get_name(self.0.as_raw()) }; + if name.is_null() { + return Ok(()); + } + // SAFETY: + // - `fwnode_get_name` returns null or a valid C string. + // - `name` was checked to be non-null. + let name = unsafe { CStr::from_char_ptr(name) }; + write!(f, "{name}") + } + } + + FwNodeDisplayName(self) + } + /// Checks if property is present or not. pub fn property_present(&self, name: &CStr) -> bool { // SAFETY: By the invariant of `CStr`, `name` is null-terminated. @@ -79,3 +104,53 @@ unsafe fn dec_ref(obj: ptr::NonNull) { unsafe { bindings::fwnode_handle_put(obj.cast().as_ptr()) } } } + +enum Node<'a> { + Borrowed(&'a FwNode), + Owned(ARef), +} + +impl core::fmt::Display for FwNode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // The logic here is the same as the one in lib/vsprintf.c + // (fwnode_full_name_string). + + // SAFETY: `self.as_raw()` is valid by its type invariant. + let num_parents = unsafe { bindings::fwnode_count_parents(self.as_raw()) }; + + for depth in (0..=num_parents).rev() { + let fwnode = if depth == 0 { + Node::Borrowed(self) + } else { + // SAFETY: `self.as_raw()` is valid. + let ptr = unsafe { bindings::fwnode_get_nth_parent(self.as_raw(), depth) }; + // SAFETY: + // - The depth passed to `fwnode_get_nth_parent` is + // within the valid range, so the returned pointer is + // not null. + // - The reference count was incremented by + // `fwnode_get_nth_parent`. + // - That increment is relinquished to + // `FwNode::from_raw`. + Node::Owned(unsafe { FwNode::from_raw(ptr) }) + }; + // Take a reference to the owned or borrowed `FwNode`. + let fwnode: &FwNode = match &fwnode { + Node::Borrowed(f) => f, + Node::Owned(f) => f, + }; + + // SAFETY: `fwnode` is valid by its type invariant. + let prefix = unsafe { bindings::fwnode_get_name_prefix(fwnode.as_raw()) }; + if !prefix.is_null() { + // SAFETY: `fwnode_get_name_prefix` returns null or a + // valid C string. + let prefix = unsafe { CStr::from_char_ptr(prefix) }; + write!(f, "{prefix}")?; + } + write!(f, "{}", fwnode.display_name())?; + } + + Ok(()) + } +} From 9bd791d9413b4b65e203c4ff84c8b8b2c8c3b770 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:04 +0200 Subject: [PATCH 07/84] rust: device: Introduce PropertyGuard This abstraction is a way to force users to specify whether a property is supposed to be required or not. This allows us to move error logging of missing required properties into core, preventing a lot of boilerplate in drivers. It will be used by upcoming methods for reading device properties. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-6-remo@buenzli.dev [ Use prelude::* to avoid build failure; move PropertyGuard below Display impl of FwNode. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device/property.rs | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 4cac335bad78..2c9482578987 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -8,6 +8,7 @@ use crate::{ bindings, + prelude::*, str::CStr, types::{ARef, Opaque}, }; @@ -154,3 +155,62 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { Ok(()) } } + +/// A helper for reading device properties. +/// +/// Use [`Self::required_by`] if a missing property is considered a bug and +/// [`Self::optional`] otherwise. +/// +/// For convenience, [`Self::or`] and [`Self::or_default`] are provided. +pub struct PropertyGuard<'fwnode, 'name, T> { + /// The result of reading the property. + inner: Result, + /// The fwnode of the property, used for logging in the "required" case. + fwnode: &'fwnode FwNode, + /// The name of the property, used for logging in the "required" case. + name: &'name CStr, +} + +impl PropertyGuard<'_, '_, T> { + /// Access the property, indicating it is required. + /// + /// If the property is not present, the error is automatically logged. If a + /// missing property is not an error, use [`Self::optional`] instead. The + /// device is required to associate the log with it. + pub fn required_by(self, dev: &super::Device) -> Result { + if self.inner.is_err() { + dev_err!( + dev, + "{}: property '{}' is missing\n", + self.fwnode, + self.name + ); + } + self.inner + } + + /// Access the property, indicating it is optional. + /// + /// In contrast to [`Self::required_by`], no error message is logged if + /// the property is not present. + pub fn optional(self) -> Option { + self.inner.ok() + } + + /// Access the property or the specified default value. + /// + /// Do not pass a sentinel value as default to detect a missing property. + /// Use [`Self::required_by`] or [`Self::optional`] instead. + pub fn or(self, default: T) -> T { + self.inner.unwrap_or(default) + } +} + +impl PropertyGuard<'_, '_, T> { + /// Access the property or a default value. + /// + /// Use [`Self::or`] to specify a custom default value. + pub fn or_default(self) -> T { + self.inner.unwrap_or_default() + } +} From 2db611374cef12bd793b72d5728f0ecd1affeb17 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:05 +0200 Subject: [PATCH 08/84] rust: device: Implement accessors for firmware properties Add methods to FwNode for reading several firmware property types like strings, integers and arrays. Most types are read with the generic `property_read` method. There are two exceptions: * `property_read_bool` cannot fail, so the fallible function signature of `property_read` would not make sense for reading booleans. * `property_read_array_vec` can fail because of a dynamic memory allocation. This error must be handled separately, leading to a different function signature than `property_read`. The traits `Property` and `PropertyInt` drive the generic behavior of `property_read`. `PropertyInt` is necessary to associate specific integer types with the C functions to read them. While there is a C function to read integers of generic sizes called `fwnode_property_read_int_array`, it was preferred not to make this public. Tested-by: Dirk Behme Co-developed-by: Rob Herring (Arm) Signed-off-by: Rob Herring (Arm) Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-7-remo@buenzli.dev [ Properly include kernel::device::private::Sealed; add explicit type annotations for core::mem::transmute(). - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device/property.rs | 254 ++++++++++++++++++++++++++++++++- 1 file changed, 252 insertions(+), 2 deletions(-) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 2c9482578987..838509111e57 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -4,12 +4,15 @@ //! //! C header: [`include/linux/property.h`](srctree/include/linux/property.h) -use core::ptr; +use core::{mem::MaybeUninit, ptr}; +use super::private::Sealed; use crate::{ + alloc::KVec, bindings, + error::{to_result, Result}, prelude::*, - str::CStr, + str::{CStr, CString}, types::{ARef, Opaque}, }; @@ -89,6 +92,104 @@ pub fn property_present(&self, name: &CStr) -> bool { // SAFETY: By the invariant of `CStr`, `name` is null-terminated. unsafe { bindings::fwnode_property_present(self.as_raw().cast_const(), name.as_char_ptr()) } } + + /// Returns firmware property `name` boolean value. + pub fn property_read_bool(&self, name: &CStr) -> bool { + // SAFETY: + // - `name` is non-null and null-terminated. + // - `self.as_raw()` is valid because `self` is valid. + unsafe { bindings::fwnode_property_read_bool(self.as_raw(), name.as_char_ptr()) } + } + + /// Returns the index of matching string `match_str` for firmware string + /// property `name`. + pub fn property_match_string(&self, name: &CStr, match_str: &CStr) -> Result { + // SAFETY: + // - `name` and `match_str` are non-null and null-terminated. + // - `self.as_raw` is valid because `self` is valid. + let ret = unsafe { + bindings::fwnode_property_match_string( + self.as_raw(), + name.as_char_ptr(), + match_str.as_char_ptr(), + ) + }; + to_result(ret)?; + Ok(ret as usize) + } + + /// Returns firmware property `name` integer array values in a [`KVec`]. + pub fn property_read_array_vec<'fwnode, 'name, T: PropertyInt>( + &'fwnode self, + name: &'name CStr, + len: usize, + ) -> Result>> { + let mut val: KVec = KVec::with_capacity(len, GFP_KERNEL)?; + + let res = T::read_array_from_fwnode_property(self, name, val.spare_capacity_mut()); + let res = match res { + Ok(_) => { + // SAFETY: + // - `len` is equal to `val.capacity - val.len`, because + // `val.capacity` is `len` and `val.len` is zero. + // - All elements within the interval [`0`, `len`) were initialized + // by `read_array_from_fwnode_property`. + unsafe { val.inc_len(len) } + Ok(val) + } + Err(e) => Err(e), + }; + Ok(PropertyGuard { + inner: res, + fwnode: self, + name, + }) + } + + /// Returns integer array length for firmware property `name`. + pub fn property_count_elem(&self, name: &CStr) -> Result { + T::read_array_len_from_fwnode_property(self, name) + } + + /// Returns the value of firmware property `name`. + /// + /// This method is generic over the type of value to read. The types that + /// can be read are strings, integers and arrays of integers. + /// + /// Reading a [`KVec`] of integers is done with the separate + /// method [`Self::property_read_array_vec`], because it takes an + /// additional `len` argument. + /// + /// Reading a boolean is done with the separate method + /// [`Self::property_read_bool`], because this operation is infallible. + /// + /// For more precise documentation about what types can be read, see + /// the [implementors of Property][Property#implementors] and [its + /// implementations on foreign types][Property#foreign-impls]. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{c_str, device::{Device, property::FwNode}, str::CString}; + /// fn examples(dev: &Device) -> Result { + /// let fwnode = dev.fwnode().ok_or(ENOENT)?; + /// let b: u32 = fwnode.property_read(c_str!("some-number")).required_by(dev)?; + /// if let Some(s) = fwnode.property_read::(c_str!("some-str")).optional() { + /// // ... + /// } + /// Ok(()) + /// } + /// ``` + pub fn property_read<'fwnode, 'name, T: Property>( + &'fwnode self, + name: &'name CStr, + ) -> PropertyGuard<'fwnode, 'name, T> { + PropertyGuard { + inner: T::read_from_fwnode_property(self, name), + fwnode: self, + name, + } + } } // SAFETY: Instances of `FwNode` are always reference-counted. @@ -156,6 +257,155 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { } } +/// Implemented for types that can be read as properties. +/// +/// This is implemented for strings, integers and arrays of integers. It's used +/// to make [`FwNode::property_read`] generic over the type of property being +/// read. There are also two dedicated methods to read other types, because they +/// require more specialized function signatures: +/// - [`property_read_bool`](FwNode::property_read_bool) +/// - [`property_read_array_vec`](FwNode::property_read_array_vec) +/// +/// It must be public, because it appears in the signatures of other public +/// functions, but its methods shouldn't be used outside the kernel crate. +pub trait Property: Sized + Sealed { + /// Used to make [`FwNode::property_read`] generic. + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result; +} + +impl Sealed for CString {} + +impl Property for CString { + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result { + let mut str: *mut u8 = ptr::null_mut(); + let pstr: *mut _ = &mut str; + + // SAFETY: + // - `name` is non-null and null-terminated. + // - `fwnode.as_raw` is valid because `fwnode` is valid. + let ret = unsafe { + bindings::fwnode_property_read_string(fwnode.as_raw(), name.as_char_ptr(), pstr.cast()) + }; + to_result(ret)?; + + // SAFETY: + // - `pstr` is a valid pointer to a NUL-terminated C string. + // - It is valid for at least as long as `fwnode`, but it's only used + // within the current function. + // - The memory it points to is not mutated during that time. + let str = unsafe { CStr::from_char_ptr(*pstr) }; + Ok(str.try_into()?) + } +} + +/// Implemented for all integers that can be read as properties. +/// +/// This helper trait is needed on top of the existing [`Property`] +/// trait to associate the integer types of various sizes with their +/// corresponding `fwnode_property_read_*_array` functions. +/// +/// It must be public, because it appears in the signatures of other public +/// functions, but its methods shouldn't be used outside the kernel crate. +pub trait PropertyInt: Copy + Sealed { + /// Reads a property array. + fn read_array_from_fwnode_property<'a>( + fwnode: &FwNode, + name: &CStr, + out: &'a mut [MaybeUninit], + ) -> Result<&'a mut [Self]>; + + /// Reads the length of a property array. + fn read_array_len_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result; +} +// This macro generates implementations of the traits `Property` and +// `PropertyInt` for integers of various sizes. Its input is a list +// of pairs separated by commas. The first element of the pair is the +// type of the integer, the second one is the name of its corresponding +// `fwnode_property_read_*_array` function. +macro_rules! impl_property_for_int { + ($($int:ty: $f:ident),* $(,)?) => { $( + impl Sealed for $int {} + impl Sealed for [$int; N] {} + + impl PropertyInt for $int { + fn read_array_from_fwnode_property<'a>( + fwnode: &FwNode, + name: &CStr, + out: &'a mut [MaybeUninit], + ) -> Result<&'a mut [Self]> { + // SAFETY: + // - `fwnode`, `name` and `out` are all valid by their type + // invariants. + // - `out.len()` is a valid bound for the memory pointed to by + // `out.as_mut_ptr()`. + // CAST: It's ok to cast from `*mut MaybeUninit<$int>` to a + // `*mut $int` because they have the same memory layout. + let ret = unsafe { + bindings::$f( + fwnode.as_raw(), + name.as_char_ptr(), + out.as_mut_ptr().cast(), + out.len(), + ) + }; + to_result(ret)?; + // SAFETY: Transmuting from `&'a mut [MaybeUninit]` to + // `&'a mut [Self]` is sound, because the previous call to a + // `fwnode_property_read_*_array` function (which didn't fail) + // fully initialized the slice. + Ok(unsafe { core::mem::transmute::<&mut [MaybeUninit], &mut [Self]>(out) }) + } + + fn read_array_len_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result { + // SAFETY: + // - `fwnode` and `name` are valid by their type invariants. + // - It's ok to pass a null pointer to the + // `fwnode_property_read_*_array` functions if `nval` is zero. + // This will return the length of the array. + let ret = unsafe { + bindings::$f( + fwnode.as_raw(), + name.as_char_ptr(), + ptr::null_mut(), + 0, + ) + }; + to_result(ret)?; + Ok(ret as usize) + } + } + + impl Property for $int { + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result { + let val: [_; 1] = <[$int; 1]>::read_from_fwnode_property(fwnode, name)?; + Ok(val[0]) + } + } + + impl Property for [$int; N] { + fn read_from_fwnode_property(fwnode: &FwNode, name: &CStr) -> Result { + let mut val: [MaybeUninit<$int>; N] = [const { MaybeUninit::uninit() }; N]; + + <$int>::read_array_from_fwnode_property(fwnode, name, &mut val)?; + + // SAFETY: `val` is always initialized when + // `fwnode_property_read_*_array` is successful. + Ok(val.map(|v| unsafe { v.assume_init() })) + } + } + )* }; +} +impl_property_for_int! { + u8: fwnode_property_read_u8_array, + u16: fwnode_property_read_u16_array, + u32: fwnode_property_read_u32_array, + u64: fwnode_property_read_u64_array, + i8: fwnode_property_read_u8_array, + i16: fwnode_property_read_u16_array, + i32: fwnode_property_read_u32_array, + i64: fwnode_property_read_u64_array, +} + /// A helper for reading device properties. /// /// Use [`Self::required_by`] if a missing property is considered a bug and From 2a1ea59de83bf367215e2a4dd9bf8bbd061349b3 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:08 +0200 Subject: [PATCH 09/84] samples: rust: platform: Add property read examples Add some example usage of the device property read methods for DT/ACPI/swnode properties. Tested-by: Dirk Behme Co-developed-by: Rob Herring (Arm) Signed-off-by: Rob Herring (Arm) Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-10-remo@buenzli.dev Signed-off-by: Danilo Krummrich --- drivers/of/unittest-data/tests-platform.dtsi | 3 + samples/rust/rust_driver_platform.rs | 60 +++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/of/unittest-data/tests-platform.dtsi b/drivers/of/unittest-data/tests-platform.dtsi index 4171f43cf01c..50a51f38afb6 100644 --- a/drivers/of/unittest-data/tests-platform.dtsi +++ b/drivers/of/unittest-data/tests-platform.dtsi @@ -37,6 +37,9 @@ dev@100 { test-device@2 { compatible = "test,rust-device"; reg = <0x2>; + + test,u32-prop = <0xdeadbeef>; + test,i16-array = /bits/ 16 <1 2 (-3) (-4)>; }; }; diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 8b42b3cfb363..c0abf78d0683 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -2,7 +2,14 @@ //! Rust Platform driver sample. -use kernel::{c_str, device::Core, of, platform, prelude::*, types::ARef}; +use kernel::{ + c_str, + device::{self, Core}, + of, platform, + prelude::*, + str::CString, + types::ARef, +}; struct SampleDriver { pdev: ARef, @@ -31,12 +38,63 @@ fn probe( dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0); } + Self::properties_parse(pdev.as_ref())?; + let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?; Ok(drvdata.into()) } } +impl SampleDriver { + fn properties_parse(dev: &device::Device) -> Result { + let fwnode = dev.fwnode().ok_or(ENOENT)?; + + if let Ok(idx) = + fwnode.property_match_string(c_str!("compatible"), c_str!("test,rust-device")) + { + dev_info!(dev, "matched compatible string idx = {}\n", idx); + } + + let name = c_str!("compatible"); + let prop = fwnode.property_read::(name).required_by(dev)?; + dev_info!(dev, "'{name}'='{prop:?}'\n"); + + let name = c_str!("test,bool-prop"); + let prop = fwnode.property_read_bool(c_str!("test,bool-prop")); + dev_info!(dev, "'{name}'='{prop}'\n"); + + if fwnode.property_present(c_str!("test,u32-prop")) { + dev_info!(dev, "'test,u32-prop' is present\n"); + } + + let name = c_str!("test,u32-optional-prop"); + let prop = fwnode.property_read::(name).or(0x12); + dev_info!(dev, "'{name}'='{prop:#x}' (default = 0x12)\n",); + + // A missing required property will print an error. Discard the error to + // prevent properties_parse from failing in that case. + let name = c_str!("test,u32-required-prop"); + let _ = fwnode.property_read::(name).required_by(dev); + + let name = c_str!("test,u32-prop"); + let prop: u32 = fwnode.property_read(name).required_by(dev)?; + dev_info!(dev, "'{name}'='{prop:#x}'\n"); + + let name = c_str!("test,i16-array"); + let prop: [i16; 4] = fwnode.property_read(name).required_by(dev)?; + dev_info!(dev, "'{name}'='{prop:?}'\n"); + let len = fwnode.property_count_elem::(name)?; + dev_info!(dev, "'{name}' length is {len}\n",); + + let name = c_str!("test,i16-array"); + let prop: KVec = fwnode.property_read_array_vec(name, 4)?.required_by(dev)?; + dev_info!(dev, "'{name}'='{prop:?}' (KVec)\n"); + + Ok(()) + } +} + impl Drop for SampleDriver { fn drop(&mut self) { dev_dbg!(self.pdev.as_ref(), "Remove Rust Platform driver sample.\n"); From 2841ef8d9630fb9735bd219f15f33cd1c70cb0d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 30 May 2025 05:54:35 +0200 Subject: [PATCH 10/84] const_structs.checkpatch: add bin_attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the sysfs core can handle "const struct bin_attribute", make sure that new usages of the struct already enter the tree as const. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250530-sysfs-const-bin_attr-final-v3-1-724bfcf05b99@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- scripts/const_structs.checkpatch | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index e8609a03c3d8..6eb94fddc338 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -1,6 +1,7 @@ acpi_dock_ops address_space_operations backlight_ops +bin_attribute block_device_operations bus_type clk_ops From 340d8e66c43f16a51f8fbdb1762e5b40c4e29f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 30 May 2025 05:54:36 +0200 Subject: [PATCH 11/84] sysfs: constify internal references to 'struct bin_attribute' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sysfs core handles 'const struct bin_attribute *'. Adapt the internal references. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250530-sysfs-const-bin_attr-final-v3-2-724bfcf05b99@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index c3d3b079aedd..1ca143d2f22a 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -83,7 +83,7 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); loff_t size = file_inode(of->file)->i_size; @@ -149,7 +149,7 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); loff_t size = file_inode(of->file)->i_size; @@ -173,7 +173,7 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, struct vm_area_struct *vma) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); return battr->mmap(of->file, kobj, battr, vma); @@ -182,7 +182,7 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset, int whence) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); if (battr->llseek) @@ -193,7 +193,7 @@ static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset, static int sysfs_kf_bin_open(struct kernfs_open_file *of) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; if (battr->f_mapping) of->file->f_mapping = battr->f_mapping(); From 2fbe82037ab2513275b9d97fe4fd9947df26e960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 30 May 2025 05:54:37 +0200 Subject: [PATCH 12/84] sysfs: treewide: switch back to bin_attribute::read()/write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bin_attribute argument of bin_attribute::read() is now const. This makes the _new() callbacks unnecessary. Switch all users back. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250530-sysfs-const-bin_attr-final-v3-3-724bfcf05b99@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-core.c | 2 +- arch/powerpc/platforms/powernv/opal-dump.c | 2 +- arch/powerpc/platforms/powernv/opal-elog.c | 2 +- arch/powerpc/platforms/powernv/opal-flash.c | 2 +- arch/powerpc/platforms/powernv/opal-msglog.c | 2 +- arch/powerpc/platforms/powernv/opal.c | 2 +- arch/powerpc/platforms/powernv/ultravisor.c | 2 +- arch/x86/kernel/ksysfs.c | 4 +-- drivers/accel/habanalabs/common/sysfs.c | 2 +- drivers/acpi/sysfs.c | 4 +-- drivers/base/firmware_loader/sysfs.c | 4 +-- drivers/firmware/efi/mokvar-table.c | 2 +- drivers/firmware/google/gsmi.c | 2 +- drivers/firmware/google/memconsole.c | 2 +- drivers/firmware/google/vpd.c | 4 +-- drivers/firmware/qemu_fw_cfg.c | 2 +- drivers/fsi/fsi-core.c | 4 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 4 +-- .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 4 +-- drivers/gpu/drm/drm_sysfs.c | 2 +- drivers/gpu/drm/i915/i915_gpu_error.c | 4 +-- drivers/gpu/drm/i915/i915_sysfs.c | 8 ++--- drivers/gpu/drm/lima/lima_drv.c | 4 +-- drivers/hid/hid-roccat-common.h | 8 ++--- drivers/hid/hid-roccat-isku.c | 8 ++--- drivers/hid/hid-roccat-kone.c | 4 +-- drivers/hid/hid-roccat-koneplus.c | 12 +++---- drivers/hid/hid-roccat-kovaplus.c | 10 +++--- drivers/hid/hid-roccat-lua.c | 4 +-- drivers/hid/hid-roccat-pyra.c | 12 +++---- drivers/i2c/i2c-slave-eeprom.c | 4 +-- drivers/media/pci/solo6x10/solo6x10-core.c | 2 +- drivers/misc/ds1682.c | 4 +-- drivers/misc/eeprom/max6875.c | 2 +- drivers/misc/ocxl/sysfs.c | 2 +- drivers/misc/pch_phub.c | 4 +-- drivers/misc/sram.c | 4 +-- .../ethernet/qlogic/netxen/netxen_nic_main.c | 10 +++--- .../net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 34 +++++++++---------- drivers/net/phy/spi_ks8995.c | 4 +-- drivers/net/wireless/ti/wlcore/sysfs.c | 2 +- drivers/nvmem/core.c | 10 +++--- drivers/of/kobj.c | 2 +- drivers/pci/hotplug/acpiphp_ibm.c | 2 +- drivers/pci/pci-sysfs.c | 8 ++--- drivers/pcmcia/cistpl.c | 4 +-- drivers/platform/mellanox/mlxbf-bootctl.c | 2 +- drivers/platform/x86/amd/hsmp/acpi.c | 2 +- drivers/platform/x86/amd/hsmp/plat.c | 2 +- drivers/platform/x86/intel/pmt/class.c | 2 +- drivers/power/supply/ds2780_battery.c | 8 ++--- drivers/power/supply/ds2781_battery.c | 8 ++--- drivers/power/supply/olpc_battery.c | 2 +- drivers/rapidio/rio-sysfs.c | 4 +-- drivers/s390/char/sclp_config.c | 2 +- drivers/s390/char/sclp_sd.c | 2 +- drivers/scsi/3w-sas.c | 4 +-- drivers/scsi/arcmsr/arcmsr_attr.c | 6 ++-- drivers/scsi/esas2r/esas2r_main.c | 6 ++-- drivers/scsi/ibmvscsi/ibmvfc.c | 2 +- drivers/scsi/ipr.c | 10 +++--- drivers/scsi/lpfc/lpfc_attr.c | 8 ++--- drivers/scsi/qedf/qedf_attr.c | 4 +-- drivers/scsi/qla2xxx/qla_attr.c | 28 +++++++-------- drivers/scsi/qla4xxx/ql4_attr.c | 4 +-- drivers/scsi/scsi_sysfs.c | 4 +-- drivers/video/fbdev/aty/radeon_base.c | 4 +-- drivers/video/fbdev/udlfb.c | 4 +-- drivers/virt/coco/guest/tsm-mr.c | 4 +-- drivers/w1/slaves/w1_ds2406.c | 4 +-- drivers/w1/slaves/w1_ds2433.c | 8 ++--- drivers/w1/slaves/w1_ds2805.c | 4 +-- drivers/zorro/zorro-sysfs.c | 2 +- kernel/bpf/btf.c | 2 +- kernel/bpf/sysfs_btf.c | 2 +- kernel/module/sysfs.c | 4 +-- net/bridge/br_sysfs_br.c | 2 +- 77 files changed, 188 insertions(+), 188 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal-core.c b/arch/powerpc/platforms/powernv/opal-core.c index e652da8f986f..6fe121aae405 100644 --- a/arch/powerpc/platforms/powernv/opal-core.c +++ b/arch/powerpc/platforms/powernv/opal-core.c @@ -208,7 +208,7 @@ static ssize_t read_opalcore(struct file *file, struct kobject *kobj, static struct bin_attribute opal_core_attr __ro_after_init = { .attr = {.name = "core", .mode = 0400}, - .read_new = read_opalcore + .read = read_opalcore }; /* diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c index 27e25693cf39..cc3cc9ddf9d1 100644 --- a/arch/powerpc/platforms/powernv/opal-dump.c +++ b/arch/powerpc/platforms/powernv/opal-dump.c @@ -342,7 +342,7 @@ static void create_dump_obj(uint32_t id, size_t size, uint32_t type) dump->dump_attr.attr.name = "dump"; dump->dump_attr.attr.mode = 0400; dump->dump_attr.size = size; - dump->dump_attr.read_new = dump_attr_read; + dump->dump_attr.read = dump_attr_read; dump->id = id; dump->size = size; diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c index de33f354e9fd..c3fc5d258146 100644 --- a/arch/powerpc/platforms/powernv/opal-elog.c +++ b/arch/powerpc/platforms/powernv/opal-elog.c @@ -203,7 +203,7 @@ static void create_elog_obj(uint64_t id, size_t size, uint64_t type) elog->raw_attr.attr.name = "raw"; elog->raw_attr.attr.mode = 0400; elog->raw_attr.size = size; - elog->raw_attr.read_new = raw_attr_read; + elog->raw_attr.read = raw_attr_read; elog->id = id; elog->size = size; diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c index fd8c8621e973..a3f7a2928767 100644 --- a/arch/powerpc/platforms/powernv/opal-flash.c +++ b/arch/powerpc/platforms/powernv/opal-flash.c @@ -493,7 +493,7 @@ static ssize_t image_data_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute image_data_attr = { .attr = {.name = "image", .mode = 0200}, .size = MAX_IMAGE_SIZE, /* Limit image size */ - .write_new = image_data_write, + .write = image_data_write, }; static struct kobj_attribute validate_attribute = diff --git a/arch/powerpc/platforms/powernv/opal-msglog.c b/arch/powerpc/platforms/powernv/opal-msglog.c index f1988d0ab45c..992a6b379a66 100644 --- a/arch/powerpc/platforms/powernv/opal-msglog.c +++ b/arch/powerpc/platforms/powernv/opal-msglog.c @@ -102,7 +102,7 @@ static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj, static struct bin_attribute opal_msglog_attr __ro_after_init = { .attr = {.name = "msglog", .mode = 0400}, - .read_new = opal_msglog_read + .read = opal_msglog_read }; struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name) diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 9ec265fcaff4..09bd93464b4f 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -815,7 +815,7 @@ static int opal_add_one_export(struct kobject *parent, const char *export_name, sysfs_bin_attr_init(attr); attr->attr.name = name; attr->attr.mode = 0400; - attr->read_new = sysfs_bin_attr_simple_read; + attr->read = sysfs_bin_attr_simple_read; attr->private = __va(vals[0]); attr->size = vals[1]; diff --git a/arch/powerpc/platforms/powernv/ultravisor.c b/arch/powerpc/platforms/powernv/ultravisor.c index 157d9a8134e4..c526871a1229 100644 --- a/arch/powerpc/platforms/powernv/ultravisor.c +++ b/arch/powerpc/platforms/powernv/ultravisor.c @@ -40,7 +40,7 @@ static ssize_t uv_msglog_read(struct file *file, struct kobject *kobj, static struct bin_attribute uv_msglog_attr __ro_after_init = { .attr = {.name = "msglog", .mode = 0400}, - .read_new = uv_msglog_read + .read = uv_msglog_read }; static int __init uv_init(void) diff --git a/arch/x86/kernel/ksysfs.c b/arch/x86/kernel/ksysfs.c index b68d4be9464e..4ee7fd9dd69c 100644 --- a/arch/x86/kernel/ksysfs.c +++ b/arch/x86/kernel/ksysfs.c @@ -40,7 +40,7 @@ static const struct bin_attribute boot_params_data_attr = { .name = "data", .mode = S_IRUGO, }, - .read_new = boot_params_data_read, + .read = boot_params_data_read, .size = sizeof(boot_params), }; @@ -250,7 +250,7 @@ static struct bin_attribute data_attr __ro_after_init = { .name = "data", .mode = S_IRUGO, }, - .read_new = setup_data_data_read, + .read = setup_data_data_read, }; static struct attribute *setup_data_type_attrs[] = { diff --git a/drivers/accel/habanalabs/common/sysfs.c b/drivers/accel/habanalabs/common/sysfs.c index 9d58efa2ff38..678585cfef84 100644 --- a/drivers/accel/habanalabs/common/sysfs.c +++ b/drivers/accel/habanalabs/common/sysfs.c @@ -446,7 +446,7 @@ static DEVICE_ATTR_RO(parent_device); static const struct bin_attribute bin_attr_eeprom = { .attr = {.name = "eeprom", .mode = (0444)}, .size = PAGE_SIZE, - .read_new = eeprom_read_handler + .read = eeprom_read_handler }; static struct attribute *hl_dev_attrs[] = { diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index a48ebbf768f9..e596224302f4 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -372,7 +372,7 @@ static int acpi_table_attr_init(struct kobject *tables_obj, } table_attr->attr.size = table_header->length; - table_attr->attr.read_new = acpi_table_show; + table_attr->attr.read = acpi_table_show; table_attr->attr.attr.name = table_attr->filename; table_attr->attr.attr.mode = 0400; @@ -495,7 +495,7 @@ static int acpi_table_data_init(struct acpi_table_header *th) if (!data_attr) return -ENOMEM; sysfs_attr_init(&data_attr->attr.attr); - data_attr->attr.read_new = acpi_data_show; + data_attr->attr.read = acpi_data_show; data_attr->attr.attr.mode = 0400; return acpi_data_objs[i].fn(th, data_attr); } diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index d254ceb56d84..c9b1564616f4 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -359,8 +359,8 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute firmware_attr_data = { .attr = { .name = "data", .mode = 0644 }, .size = 0, - .read_new = firmware_data_read, - .write_new = firmware_data_write, + .read = firmware_data_read, + .write = firmware_data_write, }; static struct attribute *fw_dev_attrs[] = { diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c index 0a856c3f69a3..aedbbd627706 100644 --- a/drivers/firmware/efi/mokvar-table.c +++ b/drivers/firmware/efi/mokvar-table.c @@ -340,7 +340,7 @@ static int __init efi_mokvar_sysfs_init(void) mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name; mokvar_sysfs->bin_attr.attr.mode = 0400; mokvar_sysfs->bin_attr.size = mokvar_entry->data_size; - mokvar_sysfs->bin_attr.read_new = efi_mokvar_sysfs_read; + mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read; err = sysfs_create_bin_file(mokvar_kobj, &mokvar_sysfs->bin_attr); diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index e8fb00dcaf65..0ceccde5a302 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -530,7 +530,7 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute eventlog_bin_attr = { .attr = {.name = "append_to_eventlog", .mode = 0200}, - .write_new = eventlog_write, + .write = eventlog_write, }; static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj, diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c index d957af6f9349..6138a1653ec5 100644 --- a/drivers/firmware/google/memconsole.c +++ b/drivers/firmware/google/memconsole.c @@ -28,7 +28,7 @@ static ssize_t memconsole_read(struct file *filp, struct kobject *kobp, static struct bin_attribute memconsole_bin_attr = { .attr = {.name = "log", .mode = 0444}, - .read_new = memconsole_read, + .read = memconsole_read, }; void memconsole_setup(ssize_t (*read_func)(char *, loff_t, size_t)) diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 254ac6545d68..339a3f74b247 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -121,7 +121,7 @@ static int vpd_section_attrib_add(const u8 *key, u32 key_len, info->bin_attr.attr.name = info->key; info->bin_attr.attr.mode = 0444; info->bin_attr.size = value_len; - info->bin_attr.read_new = vpd_attrib_read; + info->bin_attr.read = vpd_attrib_read; info->bin_attr.private = info; info->value = value; @@ -201,7 +201,7 @@ static int vpd_section_init(const char *name, struct vpd_section *sec, sec->bin_attr.attr.name = sec->raw_name; sec->bin_attr.attr.mode = 0444; sec->bin_attr.size = size; - sec->bin_attr.read_new = vpd_section_read; + sec->bin_attr.read = vpd_section_read; sec->bin_attr.private = sec; err = sysfs_create_bin_file(vpd_kobj, &sec->bin_attr); diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 2615fb780e3c..0eebd572f9a5 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -476,7 +476,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, struct kobject *kobj, static const struct bin_attribute fw_cfg_sysfs_attr_raw = { .attr = { .name = "raw", .mode = S_IRUSR }, - .read_new = fw_cfg_sysfs_read_raw, + .read = fw_cfg_sysfs_read_raw, }; /* diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index 50e8736039fe..d303939e0b90 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -613,8 +613,8 @@ static const struct bin_attribute fsi_slave_raw_attr = { .mode = 0600, }, .size = 0, - .read_new = fsi_slave_sysfs_raw_read, - .write_new = fsi_slave_sysfs_raw_write, + .read = fsi_slave_sysfs_raw_read, + .write = fsi_slave_sysfs_raw_write, }; static void fsi_slave_release(struct device *dev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index e6f0b035e20b..be9f03bbcb36 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -4117,8 +4117,8 @@ static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj, static const struct bin_attribute psp_vbflash_bin_attr = { .attr = {.name = "psp_vbflash", .mode = 0660}, .size = 0, - .write_new = amdgpu_psp_vbflash_write, - .read_new = amdgpu_psp_vbflash_read, + .write = amdgpu_psp_vbflash_write, + .read = amdgpu_psp_vbflash_read, }; /** diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index c16962256514..b1d1897f5eaf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -723,8 +723,8 @@ static ssize_t srm_data_read(struct file *filp, struct kobject *kobj, static const struct bin_attribute data_attr = { .attr = {.name = "hdcp_srm", .mode = 0664}, .size = PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, /* Limit SRM size */ - .write_new = srm_data_write, - .read_new = srm_data_read, + .write = srm_data_write, + .read = srm_data_read, }; struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 60c1f26edb6f..8d27ba7f0d83 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -319,7 +319,7 @@ static const struct bin_attribute edid_attr = { .attr.name = "edid", .attr.mode = 0444, .size = 0, - .read_new = edid_show, + .read = edid_show, }; static const struct bin_attribute *const connector_bin_attrs[] = { diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 4f785cdbd155..568525d49428 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -2506,8 +2506,8 @@ static const struct bin_attribute error_state_attr = { .attr.name = "error", .attr.mode = S_IRUSR | S_IWUSR, .size = 0, - .read_new = error_state_read, - .write_new = error_state_write, + .read = error_state_read, + .write = error_state_write, }; void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index f936e8f1f129..622c66666935 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -140,8 +140,8 @@ i915_l3_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute dpf_attrs = { .attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)}, .size = GEN7_L3LOG_SIZE, - .read_new = i915_l3_read, - .write_new = i915_l3_write, + .read = i915_l3_read, + .write = i915_l3_write, .mmap = NULL, .private = (void *)0 }; @@ -149,8 +149,8 @@ static const struct bin_attribute dpf_attrs = { static const struct bin_attribute dpf_attrs_1 = { .attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)}, .size = GEN7_L3LOG_SIZE, - .read_new = i915_l3_read, - .write_new = i915_l3_write, + .read = i915_l3_read, + .write = i915_l3_write, .mmap = NULL, .private = (void *)1 }; diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c index 11ace5cebf4c..65210ab081bb 100644 --- a/drivers/gpu/drm/lima/lima_drv.c +++ b/drivers/gpu/drm/lima/lima_drv.c @@ -362,8 +362,8 @@ static const struct bin_attribute lima_error_state_attr = { .attr.name = "error", .attr.mode = 0600, .size = 0, - .read_new = lima_error_state_read, - .write_new = lima_error_state_write, + .read = lima_error_state_read, + .write = lima_error_state_write, }; static int lima_pdev_probe(struct platform_device *pdev) diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h index 0f9a2db04df9..e931d0b48efe 100644 --- a/drivers/hid/hid-roccat-common.h +++ b/drivers/hid/hid-roccat-common.h @@ -71,8 +71,8 @@ ROCCAT_COMMON2_SYSFS_RW(thingy, COMMAND, SIZE); \ static const struct bin_attribute bin_attr_ ## thingy = { \ .attr = { .name = #thingy, .mode = 0660 }, \ .size = SIZE, \ - .read_new = roccat_common2_sysfs_read_ ## thingy, \ - .write_new = roccat_common2_sysfs_write_ ## thingy \ + .read = roccat_common2_sysfs_read_ ## thingy, \ + .write = roccat_common2_sysfs_write_ ## thingy \ } #define ROCCAT_COMMON2_BIN_ATTRIBUTE_R(thingy, COMMAND, SIZE) \ @@ -80,7 +80,7 @@ ROCCAT_COMMON2_SYSFS_R(thingy, COMMAND, SIZE); \ static const struct bin_attribute bin_attr_ ## thingy = { \ .attr = { .name = #thingy, .mode = 0440 }, \ .size = SIZE, \ - .read_new = roccat_common2_sysfs_read_ ## thingy, \ + .read = roccat_common2_sysfs_read_ ## thingy, \ } #define ROCCAT_COMMON2_BIN_ATTRIBUTE_W(thingy, COMMAND, SIZE) \ @@ -88,7 +88,7 @@ ROCCAT_COMMON2_SYSFS_W(thingy, COMMAND, SIZE); \ static const struct bin_attribute bin_attr_ ## thingy = { \ .attr = { .name = #thingy, .mode = 0220 }, \ .size = SIZE, \ - .write_new = roccat_common2_sysfs_write_ ## thingy \ + .write = roccat_common2_sysfs_write_ ## thingy \ } #endif diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c index 65a84bfcc2f8..9fddc42f241b 100644 --- a/drivers/hid/hid-roccat-isku.c +++ b/drivers/hid/hid-roccat-isku.c @@ -181,8 +181,8 @@ ISKU_SYSFS_RW(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0660 }, \ .size = ISKU_SIZE_ ## THINGY, \ - .read_new = isku_sysfs_read_ ## thingy, \ - .write_new = isku_sysfs_write_ ## thingy \ + .read = isku_sysfs_read_ ## thingy, \ + .write = isku_sysfs_write_ ## thingy \ } #define ISKU_BIN_ATTR_R(thingy, THINGY) \ @@ -190,7 +190,7 @@ ISKU_SYSFS_R(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0440 }, \ .size = ISKU_SIZE_ ## THINGY, \ - .read_new = isku_sysfs_read_ ## thingy, \ + .read = isku_sysfs_read_ ## thingy, \ } #define ISKU_BIN_ATTR_W(thingy, THINGY) \ @@ -198,7 +198,7 @@ ISKU_SYSFS_W(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0220 }, \ .size = ISKU_SIZE_ ## THINGY, \ - .write_new = isku_sysfs_write_ ## thingy \ + .write = isku_sysfs_write_ ## thingy \ } ISKU_BIN_ATTR_RW(macro, MACRO); diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index b3c0242e5a37..af8ef42aca02 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -385,8 +385,8 @@ static ssize_t kone_sysfs_write_profilex(struct file *fp, static const struct bin_attribute bin_attr_profile##number = { \ .attr = { .name = "profile" #number, .mode = 0660 }, \ .size = sizeof(struct kone_profile), \ - .read_new = kone_sysfs_read_profilex, \ - .write_new = kone_sysfs_write_profilex, \ + .read = kone_sysfs_read_profilex, \ + .write = kone_sysfs_write_profilex, \ .private = &profile_numbers[number-1], \ } PROFILE_ATTR(1); diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 5d8a5ce88b4c..c3f01f7b7e48 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c @@ -153,8 +153,8 @@ KONEPLUS_SYSFS_RW(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0660 }, \ .size = KONEPLUS_SIZE_ ## THINGY, \ - .read_new = koneplus_sysfs_read_ ## thingy, \ - .write_new = koneplus_sysfs_write_ ## thingy \ + .read = koneplus_sysfs_read_ ## thingy, \ + .write = koneplus_sysfs_write_ ## thingy \ } #define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \ @@ -162,7 +162,7 @@ KONEPLUS_SYSFS_R(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0440 }, \ .size = KONEPLUS_SIZE_ ## THINGY, \ - .read_new = koneplus_sysfs_read_ ## thingy, \ + .read = koneplus_sysfs_read_ ## thingy, \ } #define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \ @@ -170,7 +170,7 @@ KONEPLUS_SYSFS_W(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0220 }, \ .size = KONEPLUS_SIZE_ ## THINGY, \ - .write_new = koneplus_sysfs_write_ ## thingy \ + .write = koneplus_sysfs_write_ ## thingy \ } KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL); KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK); @@ -222,13 +222,13 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp, static const struct bin_attribute bin_attr_profile##number##_settings = { \ .attr = { .name = "profile" #number "_settings", .mode = 0440 }, \ .size = KONEPLUS_SIZE_PROFILE_SETTINGS, \ - .read_new = koneplus_sysfs_read_profilex_settings, \ + .read = koneplus_sysfs_read_profilex_settings, \ .private = &profile_numbers[number-1], \ }; \ static const struct bin_attribute bin_attr_profile##number##_buttons = { \ .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \ .size = KONEPLUS_SIZE_PROFILE_BUTTONS, \ - .read_new = koneplus_sysfs_read_profilex_buttons, \ + .read = koneplus_sysfs_read_profilex_buttons, \ .private = &profile_numbers[number-1], \ }; PROFILE_ATTR(1); diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index e31e4a2e62d5..7d625ed53c9f 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -196,8 +196,8 @@ KOVAPLUS_SYSFS_RW(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0660 }, \ .size = KOVAPLUS_SIZE_ ## THINGY, \ - .read_new = kovaplus_sysfs_read_ ## thingy, \ - .write_new = kovaplus_sysfs_write_ ## thingy \ + .read = kovaplus_sysfs_read_ ## thingy, \ + .write = kovaplus_sysfs_write_ ## thingy \ } #define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \ @@ -205,7 +205,7 @@ KOVAPLUS_SYSFS_W(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0220 }, \ .size = KOVAPLUS_SIZE_ ## THINGY, \ - .write_new = kovaplus_sysfs_write_ ## thingy \ + .write = kovaplus_sysfs_write_ ## thingy \ } KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL); KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO); @@ -252,13 +252,13 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp, static const struct bin_attribute bin_attr_profile##number##_settings = { \ .attr = { .name = "profile" #number "_settings", .mode = 0440 }, \ .size = KOVAPLUS_SIZE_PROFILE_SETTINGS, \ - .read_new = kovaplus_sysfs_read_profilex_settings, \ + .read = kovaplus_sysfs_read_profilex_settings, \ .private = &profile_numbers[number-1], \ }; \ static const struct bin_attribute bin_attr_profile##number##_buttons = { \ .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \ .size = KOVAPLUS_SIZE_PROFILE_BUTTONS, \ - .read_new = kovaplus_sysfs_read_profilex_buttons, \ + .read = kovaplus_sysfs_read_profilex_buttons, \ .private = &profile_numbers[number-1], \ }; PROFILE_ATTR(1); diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c index 023ec64b4b0e..45e30549c236 100644 --- a/drivers/hid/hid-roccat-lua.c +++ b/drivers/hid/hid-roccat-lua.c @@ -88,8 +88,8 @@ LUA_SYSFS_R(thingy, THINGY) \ static const struct bin_attribute lua_ ## thingy ## _attr = { \ .attr = { .name = #thingy, .mode = 0660 }, \ .size = LUA_SIZE_ ## THINGY, \ - .read_new = lua_sysfs_read_ ## thingy, \ - .write_new = lua_sysfs_write_ ## thingy \ + .read = lua_sysfs_read_ ## thingy, \ + .write = lua_sysfs_write_ ## thingy \ }; LUA_BIN_ATTRIBUTE_RW(control, CONTROL) diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 2b53fbfbb897..dbb905585369 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -154,8 +154,8 @@ PYRA_SYSFS_RW(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0660 }, \ .size = PYRA_SIZE_ ## THINGY, \ - .read_new = pyra_sysfs_read_ ## thingy, \ - .write_new = pyra_sysfs_write_ ## thingy \ + .read = pyra_sysfs_read_ ## thingy, \ + .write = pyra_sysfs_write_ ## thingy \ } #define PYRA_BIN_ATTRIBUTE_R(thingy, THINGY) \ @@ -163,7 +163,7 @@ PYRA_SYSFS_R(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0440 }, \ .size_new = PYRA_SIZE_ ## THINGY, \ - .read_new = pyra_sysfs_read_ ## thingy, \ + .read = pyra_sysfs_read_ ## thingy, \ } #define PYRA_BIN_ATTRIBUTE_W(thingy, THINGY) \ @@ -171,7 +171,7 @@ PYRA_SYSFS_W(thingy, THINGY); \ static const struct bin_attribute bin_attr_##thingy = { \ .attr = { .name = #thingy, .mode = 0220 }, \ .size = PYRA_SIZE_ ## THINGY, \ - .write_new = pyra_sysfs_write_ ## thingy \ + .write = pyra_sysfs_write_ ## thingy \ } PYRA_BIN_ATTRIBUTE_W(control, CONTROL); @@ -219,13 +219,13 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, static const struct bin_attribute bin_attr_profile##number##_settings = { \ .attr = { .name = "profile" #number "_settings", .mode = 0440 }, \ .size = PYRA_SIZE_PROFILE_SETTINGS, \ - .read_new = pyra_sysfs_read_profilex_settings, \ + .read = pyra_sysfs_read_profilex_settings, \ .private = &profile_numbers[number-1], \ }; \ static const struct bin_attribute bin_attr_profile##number##_buttons = { \ .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \ .size = PYRA_SIZE_PROFILE_BUTTONS, \ - .read_new = pyra_sysfs_read_profilex_buttons, \ + .read = pyra_sysfs_read_profilex_buttons, \ .private = &profile_numbers[number-1], \ }; PROFILE_ATTR(1); diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index 275d1d0e910f..6bc2ef650a74 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -165,8 +165,8 @@ static int i2c_slave_eeprom_probe(struct i2c_client *client) sysfs_bin_attr_init(&eeprom->bin); eeprom->bin.attr.name = "slave-eeprom"; eeprom->bin.attr.mode = S_IRUSR | S_IWUSR; - eeprom->bin.read_new = i2c_slave_eeprom_bin_read; - eeprom->bin.write_new = i2c_slave_eeprom_bin_write; + eeprom->bin.read = i2c_slave_eeprom_bin_read; + eeprom->bin.write = i2c_slave_eeprom_bin_write; eeprom->bin.size = size; ret = sysfs_create_bin_file(&client->dev.kobj, &eeprom->bin); diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index febb2c156cf6..d1d3a83d0122 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -432,7 +432,7 @@ static int solo_sysfs_init(struct solo_dev *solo_dev) sysfs_attr_init(&sdram_attr->attr); sdram_attr->attr.name = "sdram"; sdram_attr->attr.mode = 0440; - sdram_attr->read_new = sdram_show; + sdram_attr->read = sdram_show; sdram_attr->size = solo_dev->sdram_size; if (device_create_bin_file(dev, sdram_attr)) { diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index 5d5a70a62e98..cb09e056531a 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c @@ -194,8 +194,8 @@ static const struct bin_attribute ds1682_eeprom_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = DS1682_EEPROM_SIZE, - .read_new = ds1682_eeprom_read, - .write_new = ds1682_eeprom_write, + .read = ds1682_eeprom_read, + .write = ds1682_eeprom_write, }; static int ds1682_nvmem_read(void *priv, unsigned int offset, void *val, diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c index 1c36ad153e78..a3e4cada3b51 100644 --- a/drivers/misc/eeprom/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -127,7 +127,7 @@ static const struct bin_attribute user_eeprom_attr = { .mode = S_IRUGO, }, .size = USER_EEPROM_SIZE, - .read_new = max6875_read, + .read = max6875_read, }; static int max6875_probe(struct i2c_client *client) diff --git a/drivers/misc/ocxl/sysfs.c b/drivers/misc/ocxl/sysfs.c index e849641687a0..3100f0944fd9 100644 --- a/drivers/misc/ocxl/sysfs.c +++ b/drivers/misc/ocxl/sysfs.c @@ -155,7 +155,7 @@ int ocxl_sysfs_register_afu(struct ocxl_file_info *info) info->attr_global_mmio.attr.name = "global_mmio_area"; info->attr_global_mmio.attr.mode = 0600; info->attr_global_mmio.size = info->afu->config.global_mmio_size; - info->attr_global_mmio.read_new = global_mmio_read; + info->attr_global_mmio.read = global_mmio_read; info->attr_global_mmio.mmap = global_mmio_mmap; rc = device_create_bin_file(&info->dev, &info->attr_global_mmio); if (rc) { diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 6121c0940cd1..7bee179841bc 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -655,8 +655,8 @@ static const struct bin_attribute pch_bin_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = PCH_PHUB_OROM_SIZE + 1, - .read_new = pch_phub_bin_read, - .write_new = pch_phub_bin_write, + .read = pch_phub_bin_read, + .write = pch_phub_bin_write, }; static int pch_phub_probe(struct pci_dev *pdev, diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index e5069882457e..8fb8a43de296 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -83,8 +83,8 @@ static int sram_add_export(struct sram_dev *sram, struct sram_reserve *block, return -ENOMEM; part->battr.attr.mode = S_IRUSR | S_IWUSR; - part->battr.read_new = sram_read; - part->battr.write_new = sram_write; + part->battr.read = sram_read; + part->battr.write = sram_write; part->battr.size = block->size; return device_create_bin_file(sram->dev, &part->battr); diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 3383ee1dad14..e8ff661fa4a5 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -2946,15 +2946,15 @@ static ssize_t netxen_sysfs_write_mem(struct file *filp, struct kobject *kobj, static const struct bin_attribute bin_attr_crb = { .attr = { .name = "crb", .mode = 0644 }, .size = 0, - .read_new = netxen_sysfs_read_crb, - .write_new = netxen_sysfs_write_crb, + .read = netxen_sysfs_read_crb, + .write = netxen_sysfs_write_crb, }; static const struct bin_attribute bin_attr_mem = { .attr = { .name = "mem", .mode = 0644 }, .size = 0, - .read_new = netxen_sysfs_read_mem, - .write_new = netxen_sysfs_write_mem, + .read = netxen_sysfs_read_mem, + .write = netxen_sysfs_write_mem, }; static ssize_t @@ -3082,7 +3082,7 @@ netxen_sysfs_read_dimm(struct file *filp, struct kobject *kobj, static const struct bin_attribute bin_attr_dimm = { .attr = { .name = "dimm", .mode = 0644 }, .size = sizeof(struct netxen_dimm_cfg), - .read_new = netxen_sysfs_read_dimm, + .read = netxen_sysfs_read_dimm, }; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index c0f20464fd1e..5296d9a6ee83 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -1195,63 +1195,63 @@ static const struct device_attribute dev_attr_beacon = { static const struct bin_attribute bin_attr_crb = { .attr = { .name = "crb", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_read_crb, - .write_new = qlcnic_sysfs_write_crb, + .read = qlcnic_sysfs_read_crb, + .write = qlcnic_sysfs_write_crb, }; static const struct bin_attribute bin_attr_mem = { .attr = { .name = "mem", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_read_mem, - .write_new = qlcnic_sysfs_write_mem, + .read = qlcnic_sysfs_read_mem, + .write = qlcnic_sysfs_write_mem, }; static const struct bin_attribute bin_attr_npar_config = { .attr = { .name = "npar_config", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_read_npar_config, - .write_new = qlcnic_sysfs_write_npar_config, + .read = qlcnic_sysfs_read_npar_config, + .write = qlcnic_sysfs_write_npar_config, }; static const struct bin_attribute bin_attr_pci_config = { .attr = { .name = "pci_config", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_read_pci_config, + .read = qlcnic_sysfs_read_pci_config, }; static const struct bin_attribute bin_attr_port_stats = { .attr = { .name = "port_stats", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_get_port_stats, - .write_new = qlcnic_sysfs_clear_port_stats, + .read = qlcnic_sysfs_get_port_stats, + .write = qlcnic_sysfs_clear_port_stats, }; static const struct bin_attribute bin_attr_esw_stats = { .attr = { .name = "esw_stats", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_get_esw_stats, - .write_new = qlcnic_sysfs_clear_esw_stats, + .read = qlcnic_sysfs_get_esw_stats, + .write = qlcnic_sysfs_clear_esw_stats, }; static const struct bin_attribute bin_attr_esw_config = { .attr = { .name = "esw_config", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_read_esw_config, - .write_new = qlcnic_sysfs_write_esw_config, + .read = qlcnic_sysfs_read_esw_config, + .write = qlcnic_sysfs_write_esw_config, }; static const struct bin_attribute bin_attr_pm_config = { .attr = { .name = "pm_config", .mode = 0644 }, .size = 0, - .read_new = qlcnic_sysfs_read_pm_config, - .write_new = qlcnic_sysfs_write_pm_config, + .read = qlcnic_sysfs_read_pm_config, + .write = qlcnic_sysfs_write_pm_config, }; static const struct bin_attribute bin_attr_flash = { .attr = { .name = "flash", .mode = 0644 }, .size = 0, - .read_new = qlcnic_83xx_sysfs_flash_read_handler, - .write_new = qlcnic_83xx_sysfs_flash_write_handler, + .read = qlcnic_83xx_sysfs_flash_read_handler, + .write = qlcnic_83xx_sysfs_flash_write_handler, }; #ifdef CONFIG_QLCNIC_HWMON diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index 076a370be849..d135b061d810 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -401,8 +401,8 @@ static const struct bin_attribute ks8995_registers_attr = { .mode = 0600, }, .size = KS8995_REGS_SIZE, - .read_new = ks8995_registers_read, - .write_new = ks8995_registers_write, + .read = ks8995_registers_read, + .write = ks8995_registers_write, }; /* ------------------------------------------------------------------------ */ diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index 7c57d4c8744a..65ca5dc569a0 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -121,7 +121,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, static const struct bin_attribute fwlog_attr = { .attr = { .name = "fwlog", .mode = 0400 }, - .read_new = wl1271_sysfs_read_fwlog, + .read = wl1271_sysfs_read_fwlog, }; int wlcore_sysfs_init(struct wl1271 *wl) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index fd2a9698d1c9..f0a664bcb01a 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -376,8 +376,8 @@ static const struct bin_attribute bin_attr_rw_nvmem = { .name = "nvmem", .mode = 0644, }, - .read_new = bin_attr_nvmem_read, - .write_new = bin_attr_nvmem_write, + .read = bin_attr_nvmem_read, + .write = bin_attr_nvmem_write, }; static const struct bin_attribute *const nvmem_bin_attributes[] = { @@ -402,8 +402,8 @@ static const struct bin_attribute bin_attr_nvmem_eeprom_compat = { .attr = { .name = "eeprom", }, - .read_new = bin_attr_nvmem_read, - .write_new = bin_attr_nvmem_write, + .read = bin_attr_nvmem_read, + .write = bin_attr_nvmem_write, }; /* @@ -492,7 +492,7 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) entry->bit_offset); attrs[i].attr.mode = 0444 & nvmem_bin_attr_get_umode(nvmem); attrs[i].size = entry->bytes; - attrs[i].read_new = &nvmem_cell_attr_read; + attrs[i].read = &nvmem_cell_attr_read; attrs[i].private = entry; if (!attrs[i].attr.name) { ret = -ENOMEM; diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c index aa887166f0d2..1bb61a2c3399 100644 --- a/drivers/of/kobj.c +++ b/drivers/of/kobj.c @@ -77,7 +77,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp) pp->attr.attr.name = safe_name(&np->kobj, pp->name); pp->attr.attr.mode = secure ? 0400 : 0444; pp->attr.size = secure ? 0 : pp->length; - pp->attr.read_new = of_node_property_read; + pp->attr.read = of_node_property_read; rc = sysfs_create_bin_file(&np->kobj, &pp->attr); WARN(rc, "error adding attribute %s to node %pOF\n", pp->name, np); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index b3aa34e3a4a2..18e01cd55a8e 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -98,7 +98,7 @@ static struct bin_attribute ibm_apci_table_attr __ro_after_init = { .name = "apci_table", .mode = S_IRUGO, }, - .read_new = ibm_read_apci_table, + .read = ibm_read_apci_table, .write = NULL, }; static struct acpiphp_attention_info ibm_attention_info = diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 268c69daa4d5..f2739eafef9b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1004,8 +1004,8 @@ void pci_create_legacy_files(struct pci_bus *b) b->legacy_io->attr.name = "legacy_io"; b->legacy_io->size = 0xffff; b->legacy_io->attr.mode = 0600; - b->legacy_io->read_new = pci_read_legacy_io; - b->legacy_io->write_new = pci_write_legacy_io; + b->legacy_io->read = pci_read_legacy_io; + b->legacy_io->write = pci_write_legacy_io; /* See pci_create_attr() for motivation */ b->legacy_io->llseek = pci_llseek_resource; b->legacy_io->mmap = pci_mmap_legacy_io; @@ -1211,8 +1211,8 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) } else { sprintf(res_attr_name, "resource%d", num); if (pci_resource_flags(pdev, num) & IORESOURCE_IO) { - res_attr->read_new = pci_read_resource_io; - res_attr->write_new = pci_write_resource_io; + res_attr->read = pci_read_resource_io; + res_attr->write = pci_write_resource_io; if (arch_can_pci_mmap_io()) res_attr->mmap = pci_mmap_resource_uc; } else { diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 0c801e4ccc6c..05b67fd93de6 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1605,6 +1605,6 @@ static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj, const struct bin_attribute pccard_cis_attr = { .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR }, .size = 0x200, - .read_new = pccard_show_cis, - .write_new = pccard_store_cis, + .read = pccard_show_cis, + .write = pccard_store_cis, }; diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c index c18a5b96de5c..f67c7f56ab2b 100644 --- a/drivers/platform/mellanox/mlxbf-bootctl.c +++ b/drivers/platform/mellanox/mlxbf-bootctl.c @@ -993,7 +993,7 @@ static ssize_t mlxbf_bootctl_bootfifo_read(struct file *filp, static const struct bin_attribute mlxbf_bootctl_bootfifo_sysfs_attr = { .attr = { .name = "bootfifo", .mode = 0400 }, - .read_new = mlxbf_bootctl_bootfifo_read, + .read = mlxbf_bootctl_bootfifo_read, }; static bool mlxbf_bootctl_guid_match(const guid_t *guid, diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c index 2f1faa82d13e..63af9dae0254 100644 --- a/drivers/platform/x86/amd/hsmp/acpi.c +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -509,7 +509,7 @@ static int init_acpi(struct device *dev) static const struct bin_attribute hsmp_metric_tbl_attr = { .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444}, - .read_new = hsmp_metric_tbl_acpi_read, + .read = hsmp_metric_tbl_acpi_read, .size = sizeof(struct hsmp_metric_table), }; diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c index e3874c47ed9e..b6dceca28bdb 100644 --- a/drivers/platform/x86/amd/hsmp/plat.c +++ b/drivers/platform/x86/amd/hsmp/plat.c @@ -91,7 +91,7 @@ static_assert(MAX_AMD_NUM_NODES == 8); static const struct bin_attribute attr##index = { \ .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444}, \ .private = (void *)index, \ - .read_new = hsmp_metric_tbl_plat_read, \ + .read = hsmp_metric_tbl_plat_read, \ .size = sizeof(struct hsmp_metric_table), \ }; \ static const struct bin_attribute _list[] = { \ diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index 7233b654bbad..3ed20da80a87 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -308,7 +308,7 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry, entry->pmt_bin_attr.attr.name = ns->name; entry->pmt_bin_attr.attr.mode = 0440; entry->pmt_bin_attr.mmap = intel_pmt_mmap; - entry->pmt_bin_attr.read_new = intel_pmt_read; + entry->pmt_bin_attr.read = intel_pmt_read; entry->pmt_bin_attr.size = entry->size; ret = sysfs_create_bin_file(&dev->kobj, &entry->pmt_bin_attr); diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c index dd9ac7a32967..8352c6401cbf 100644 --- a/drivers/power/supply/ds2780_battery.c +++ b/drivers/power/supply/ds2780_battery.c @@ -660,8 +660,8 @@ static const struct bin_attribute ds2780_param_eeprom_bin_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = DS2780_PARAM_EEPROM_SIZE, - .read_new = ds2780_read_param_eeprom_bin, - .write_new = ds2780_write_param_eeprom_bin, + .read = ds2780_read_param_eeprom_bin, + .write = ds2780_write_param_eeprom_bin, }; static ssize_t ds2780_read_user_eeprom_bin(struct file *filp, @@ -705,8 +705,8 @@ static const struct bin_attribute ds2780_user_eeprom_bin_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = DS2780_USER_EEPROM_SIZE, - .read_new = ds2780_read_user_eeprom_bin, - .write_new = ds2780_write_user_eeprom_bin, + .read = ds2780_read_user_eeprom_bin, + .write = ds2780_write_user_eeprom_bin, }; static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2780_get_pmod_enabled, diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c index 8a1f1f9835e0..43a6b022901e 100644 --- a/drivers/power/supply/ds2781_battery.c +++ b/drivers/power/supply/ds2781_battery.c @@ -662,8 +662,8 @@ static const struct bin_attribute ds2781_param_eeprom_bin_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = DS2781_PARAM_EEPROM_SIZE, - .read_new = ds2781_read_param_eeprom_bin, - .write_new = ds2781_write_param_eeprom_bin, + .read = ds2781_read_param_eeprom_bin, + .write = ds2781_write_param_eeprom_bin, }; static ssize_t ds2781_read_user_eeprom_bin(struct file *filp, @@ -708,8 +708,8 @@ static const struct bin_attribute ds2781_user_eeprom_bin_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = DS2781_USER_EEPROM_SIZE, - .read_new = ds2781_read_user_eeprom_bin, - .write_new = ds2781_write_user_eeprom_bin, + .read = ds2781_read_user_eeprom_bin, + .write = ds2781_write_user_eeprom_bin, }; static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2781_get_pmod_enabled, diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index b9b607822676..a9760dbb1616 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c @@ -553,7 +553,7 @@ static const struct bin_attribute olpc_bat_eeprom = { .mode = S_IRUGO, }, .size = EEPROM_SIZE, - .read_new = olpc_bat_eeprom_read, + .read = olpc_bat_eeprom_read, }; /* Allow userspace to see the specific error value pulled from the EC */ diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 6f89b232f1d5..5e8c22677e46 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -247,8 +247,8 @@ static const struct bin_attribute rio_config_attr = { .mode = S_IRUGO | S_IWUSR, }, .size = RIO_MAINT_SPACE_SZ, - .read_new = rio_read_config, - .write_new = rio_write_config, + .read = rio_read_config, + .write = rio_write_config, }; static const struct bin_attribute *const rio_dev_bin_attrs[] = { diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index ae5d28987177..356d26a09af0 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -142,7 +142,7 @@ static const struct bin_attribute ofb_bin_attr = { .name = "event_data", .mode = S_IWUSR, }, - .write_new = sysfs_ofb_data_write, + .write = sysfs_ofb_data_write, }; #endif diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c index 8524c14affed..ddd26c4da26a 100644 --- a/drivers/s390/char/sclp_sd.c +++ b/drivers/s390/char/sclp_sd.c @@ -539,7 +539,7 @@ static __init struct sclp_sd_file *sclp_sd_file_create(const char *name, u8 di) sysfs_bin_attr_init(&sd_file->data_attr); sd_file->data_attr.attr.name = "data"; sd_file->data_attr.attr.mode = 0444; - sd_file->data_attr.read_new = data_read; + sd_file->data_attr.read = data_read; rc = sysfs_create_bin_file(&sd_file->kobj, &sd_file->data_attr); if (rc) { diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index e057ab9c7b90..8d4174c7107e 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -122,7 +122,7 @@ static const struct bin_attribute twl_sysfs_aen_read_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = twl_sysfs_aen_read + .read = twl_sysfs_aen_read }; /* This function returns driver compatibility info through sysfs */ @@ -153,7 +153,7 @@ static const struct bin_attribute twl_sysfs_compat_info_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = twl_sysfs_compat_info + .read = twl_sysfs_compat_info }; /* Show some statistics about the card */ diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 8e3d4799ce93..1990af2bef95 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -194,7 +194,7 @@ static const struct bin_attribute arcmsr_sysfs_message_read_attr = { .mode = S_IRUSR , }, .size = ARCMSR_API_DATA_BUFLEN, - .read_new = arcmsr_sysfs_iop_message_read, + .read = arcmsr_sysfs_iop_message_read, }; static const struct bin_attribute arcmsr_sysfs_message_write_attr = { @@ -203,7 +203,7 @@ static const struct bin_attribute arcmsr_sysfs_message_write_attr = { .mode = S_IWUSR, }, .size = ARCMSR_API_DATA_BUFLEN, - .write_new = arcmsr_sysfs_iop_message_write, + .write = arcmsr_sysfs_iop_message_write, }; static const struct bin_attribute arcmsr_sysfs_message_clear_attr = { @@ -212,7 +212,7 @@ static const struct bin_attribute arcmsr_sysfs_message_clear_attr = { .mode = S_IWUSR, }, .size = 1, - .write_new = arcmsr_sysfs_iop_message_clear, + .write = arcmsr_sysfs_iop_message_clear, }; int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 3f31875ff46e..be6bf518eb7c 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -215,8 +215,8 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj, .attr = \ { .name = __stringify(_name), .mode = S_IRUSR | S_IWUSR }, \ .size = 0, \ - .read_new = read_ ## _name, \ - .write_new = write_ ## _name } + .read = read_ ## _name, \ + .write = write_ ## _name } ESAS2R_RW_BIN_ATTR(fw); ESAS2R_RW_BIN_ATTR(fs); @@ -227,7 +227,7 @@ ESAS2R_RW_BIN_ATTR(live_nvram); const struct bin_attribute bin_attr_default_nvram = { .attr = { .name = "default_nvram", .mode = S_IRUGO }, .size = 0, - .read_new = read_default_nvram, + .read = read_default_nvram, .write = NULL }; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 862ab0fbc893..228daffb286d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -3670,7 +3670,7 @@ static const struct bin_attribute ibmvfc_trace_attr = { .mode = S_IRUGO, }, .size = 0, - .read_new = ibmvfc_read_trace, + .read = ibmvfc_read_trace, }; #endif diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b29bec6abd72..d06b79f03538 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3389,7 +3389,7 @@ static const struct bin_attribute ipr_trace_attr = { .mode = S_IRUGO, }, .size = 0, - .read_new = ipr_read_trace, + .read = ipr_read_trace, }; #endif @@ -4140,8 +4140,8 @@ static const struct bin_attribute ipr_ioa_async_err_log = { .mode = S_IRUGO | S_IWUSR, }, .size = 0, - .read_new = ipr_read_async_err_log, - .write_new = ipr_next_async_err_log + .read = ipr_read_async_err_log, + .write = ipr_next_async_err_log }; static struct attribute *ipr_ioa_attrs[] = { @@ -4391,8 +4391,8 @@ static const struct bin_attribute ipr_dump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = ipr_read_dump, - .write_new = ipr_write_dump + .read = ipr_read_dump, + .write = ipr_write_dump }; #else static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 54ee8ecec3b3..33582d48ec09 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -6420,8 +6420,8 @@ static const struct bin_attribute sysfs_ctlreg_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 256, - .read_new = sysfs_ctlreg_read, - .write_new = sysfs_ctlreg_write, + .read = sysfs_ctlreg_read, + .write = sysfs_ctlreg_write, }; /** @@ -6478,8 +6478,8 @@ static const struct bin_attribute sysfs_mbox_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = MAILBOX_SYSFS_MAX, - .read_new = sysfs_mbox_read, - .write_new = sysfs_mbox_write, + .read = sysfs_mbox_read, + .write = sysfs_mbox_write, }; /** diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c index 769da92ee20d..7ebb46689f97 100644 --- a/drivers/scsi/qedf/qedf_attr.c +++ b/drivers/scsi/qedf/qedf_attr.c @@ -166,8 +166,8 @@ static const struct bin_attribute sysfs_grcdump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qedf_sysfs_read_grcdump, - .write_new = qedf_sysfs_write_grcdump, + .read = qedf_sysfs_read_grcdump, + .write = qedf_sysfs_write_grcdump, }; static struct sysfs_bin_attrs bin_file_entries[] = { diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index dcb0c2af1fa7..2e584a8bf66b 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -174,8 +174,8 @@ static const struct bin_attribute sysfs_fw_dump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_fw_dump, - .write_new = qla2x00_sysfs_write_fw_dump, + .read = qla2x00_sysfs_read_fw_dump, + .write = qla2x00_sysfs_write_fw_dump, }; static ssize_t @@ -288,8 +288,8 @@ static const struct bin_attribute sysfs_nvram_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 512, - .read_new = qla2x00_sysfs_read_nvram, - .write_new = qla2x00_sysfs_write_nvram, + .read = qla2x00_sysfs_read_nvram, + .write = qla2x00_sysfs_write_nvram, }; static ssize_t @@ -350,8 +350,8 @@ static const struct bin_attribute sysfs_optrom_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_optrom, - .write_new = qla2x00_sysfs_write_optrom, + .read = qla2x00_sysfs_read_optrom, + .write = qla2x00_sysfs_write_optrom, }; static ssize_t @@ -535,7 +535,7 @@ static const struct bin_attribute sysfs_optrom_ctl_attr = { .mode = S_IWUSR, }, .size = 0, - .write_new = qla2x00_sysfs_write_optrom_ctl, + .write = qla2x00_sysfs_write_optrom_ctl, }; static ssize_t @@ -648,8 +648,8 @@ static const struct bin_attribute sysfs_vpd_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_vpd, - .write_new = qla2x00_sysfs_write_vpd, + .read = qla2x00_sysfs_read_vpd, + .write = qla2x00_sysfs_write_vpd, }; static ssize_t @@ -685,7 +685,7 @@ static const struct bin_attribute sysfs_sfp_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = SFP_DEV_SIZE, - .read_new = qla2x00_sysfs_read_sfp, + .read = qla2x00_sysfs_read_sfp, }; static ssize_t @@ -829,7 +829,7 @@ static const struct bin_attribute sysfs_reset_attr = { .mode = S_IWUSR, }, .size = 0, - .write_new = qla2x00_sysfs_write_reset, + .write = qla2x00_sysfs_write_reset, }; static ssize_t @@ -872,7 +872,7 @@ static const struct bin_attribute sysfs_issue_logo_attr = { .mode = S_IWUSR, }, .size = 0, - .write_new = qla2x00_issue_logo, + .write = qla2x00_issue_logo, }; static ssize_t @@ -935,7 +935,7 @@ static const struct bin_attribute sysfs_xgmac_stats_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_xgmac_stats, + .read = qla2x00_sysfs_read_xgmac_stats, }; static ssize_t @@ -993,7 +993,7 @@ static const struct bin_attribute sysfs_dcbx_tlv_attr = { .mode = S_IRUSR, }, .size = 0, - .read_new = qla2x00_sysfs_read_dcbx_tlv, + .read = qla2x00_sysfs_read_dcbx_tlv, }; static struct sysfs_entry { diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c index e3f85d6ea0db..84f99ff8e69a 100644 --- a/drivers/scsi/qla4xxx/ql4_attr.c +++ b/drivers/scsi/qla4xxx/ql4_attr.c @@ -110,8 +110,8 @@ static const struct bin_attribute sysfs_fw_dump_attr = { .mode = S_IRUSR | S_IWUSR, }, .size = 0, - .read_new = qla4_8xxx_sysfs_read_fw_dump, - .write_new = qla4_8xxx_sysfs_write_fw_dump, + .read = qla4_8xxx_sysfs_read_fw_dump, + .write = qla4_8xxx_sysfs_write_fw_dump, }; static struct sysfs_entry { diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index d772258e29ad..deba96107d20 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -917,7 +917,7 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \ static const struct bin_attribute dev_attr_vpd_##_page = { \ .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \ .size = 0, \ - .read_new = show_vpd_##_page, \ + .read = show_vpd_##_page, \ }; sdev_vpd_pg_attr(pg83); @@ -949,7 +949,7 @@ static const struct bin_attribute dev_attr_inquiry = { .mode = S_IRUGO, }, .size = 0, - .read_new = show_inquiry, + .read = show_inquiry, }; static ssize_t diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index 0eef8c6b98c8..1d2c57ba25a3 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -2227,7 +2227,7 @@ static const struct bin_attribute edid1_attr = { .mode = 0444, }, .size = EDID_LENGTH, - .read_new = radeon_show_edid1, + .read = radeon_show_edid1, }; static const struct bin_attribute edid2_attr = { @@ -2236,7 +2236,7 @@ static const struct bin_attribute edid2_attr = { .mode = 0444, }, .size = EDID_LENGTH, - .read_new = radeon_show_edid2, + .read = radeon_show_edid2, }; static int radeonfb_pci_register(struct pci_dev *pdev, diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index acadf0eb450c..ccede85df1e1 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1482,8 +1482,8 @@ static const struct bin_attribute edid_attr = { .attr.name = "edid", .attr.mode = 0666, .size = EDID_LENGTH, - .read_new = edid_show, - .write_new = edid_store + .read = edid_show, + .write = edid_store }; static const struct device_attribute fb_device_attrs[] = { diff --git a/drivers/virt/coco/guest/tsm-mr.c b/drivers/virt/coco/guest/tsm-mr.c index feb30af90a20..74465e79be60 100644 --- a/drivers/virt/coco/guest/tsm-mr.c +++ b/drivers/virt/coco/guest/tsm-mr.c @@ -209,12 +209,12 @@ tsm_mr_create_attribute_group(const struct tsm_measurements *tm) if (tm->mrs[i].mr_flags & TSM_MR_F_READABLE) { bap->attr.mode |= 0444; - bap->read_new = tm_digest_read; + bap->read = tm_digest_read; } if (tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) { bap->attr.mode |= 0200; - bap->write_new = tm_digest_write; + bap->write = tm_digest_write; } bap->size = tm->mrs[i].mr_size; diff --git a/drivers/w1/slaves/w1_ds2406.c b/drivers/w1/slaves/w1_ds2406.c index 76026d615111..efb2e784f8d7 100644 --- a/drivers/w1/slaves/w1_ds2406.c +++ b/drivers/w1/slaves/w1_ds2406.c @@ -94,7 +94,7 @@ static const struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { .mode = 0444, }, .size = 1, - .read_new = w1_f12_read_state, + .read = w1_f12_read_state, }, { .attr = { @@ -102,7 +102,7 @@ static const struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { .mode = 0664, }, .size = 1, - .write_new = w1_f12_write_output, + .write = w1_f12_write_output, } }; diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index 22331d840ec1..a53eb34fea79 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c @@ -276,15 +276,15 @@ static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute bin_attr_f23_eeprom = { .attr = { .name = "eeprom", .mode = 0644 }, - .read_new = eeprom_read, - .write_new = eeprom_write, + .read = eeprom_read, + .write = eeprom_write, .size = W1_EEPROM_DS2433_SIZE, }; static const struct bin_attribute bin_attr_f43_eeprom = { .attr = { .name = "eeprom", .mode = 0644 }, - .read_new = eeprom_read, - .write_new = eeprom_write, + .read = eeprom_read, + .write = eeprom_write, .size = W1_EEPROM_DS28EC20_SIZE, }; diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c index 6ee895640d4a..9c86b7985d0b 100644 --- a/drivers/w1/slaves/w1_ds2805.c +++ b/drivers/w1/slaves/w1_ds2805.c @@ -267,8 +267,8 @@ static const struct bin_attribute w1_f0d_bin_attr = { .mode = 0644, }, .size = W1_F0D_EEPROM_SIZE, - .read_new = w1_f0d_read_bin, - .write_new = w1_f0d_write_bin, + .read = w1_f0d_read_bin, + .write = w1_f0d_write_bin, }; static int w1_f0d_add_slave(struct w1_slave *sl) diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 10aedcd21363..294d3642a279 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -104,7 +104,7 @@ static const struct bin_attribute zorro_config_attr = { .mode = S_IRUGO, }, .size = sizeof(struct ConfigDev), - .read_new = zorro_read_config, + .read = zorro_read_config, }; static const struct bin_attribute *const zorro_device_bin_attrs[] = { diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 1d2cf898e21e..e8e63bd025c7 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -8183,7 +8183,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op, attr->attr.mode = 0444; attr->size = btf->data_size; attr->private = btf->data; - attr->read_new = sysfs_bin_attr_simple_read; + attr->read = sysfs_bin_attr_simple_read; err = sysfs_create_bin_file(btf_kobj, attr); if (err) { diff --git a/kernel/bpf/sysfs_btf.c b/kernel/bpf/sysfs_btf.c index 941d0d2427e3..8951d8a2f2a3 100644 --- a/kernel/bpf/sysfs_btf.c +++ b/kernel/bpf/sysfs_btf.c @@ -45,7 +45,7 @@ static int btf_sysfs_vmlinux_mmap(struct file *filp, struct kobject *kobj, static struct bin_attribute bin_attr_btf_vmlinux __ro_after_init = { .attr = { .name = "vmlinux", .mode = 0444, }, - .read_new = sysfs_bin_attr_simple_read, + .read = sysfs_bin_attr_simple_read, .mmap = btf_sysfs_vmlinux_mmap, }; diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c index b401ff4b02d2..5183ae86e05e 100644 --- a/kernel/module/sysfs.c +++ b/kernel/module/sysfs.c @@ -101,7 +101,7 @@ static int add_sect_attrs(struct module *mod, const struct load_info *info) ret = -ENOMEM; goto out; } - sattr->read_new = module_sect_read; + sattr->read = module_sect_read; sattr->private = (void *)sec->sh_addr; sattr->size = MODULE_SECT_READ_SIZE; sattr->attr.mode = 0400; @@ -190,7 +190,7 @@ static int add_notes_attrs(struct module *mod, const struct load_info *info) nattr->attr.mode = 0444; nattr->size = info->sechdrs[i].sh_size; nattr->private = (void *)info->sechdrs[i].sh_addr; - nattr->read_new = sysfs_bin_attr_simple_read; + nattr->read = sysfs_bin_attr_simple_read; *(gattr++) = nattr++; } ++loaded; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c1176a5e02c4..cb4855ed9500 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -1026,7 +1026,7 @@ static ssize_t brforward_read(struct file *filp, struct kobject *kobj, static const struct bin_attribute bridge_forward = { .attr = { .name = SYSFS_BRIDGE_FDB, .mode = 0444, }, - .read_new = brforward_read, + .read = brforward_read, }; /* From fb506e31b3d52f7faaec00352c2732ce31c1f930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 30 May 2025 05:54:38 +0200 Subject: [PATCH 13/84] sysfs: treewide: switch back to attribute_group::bin_attrs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The normal bin_attrs field can now handle const pointers. This makes the _new variant unnecessary. Switch all users back. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250530-sysfs-const-bin_attr-final-v3-4-724bfcf05b99@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/secvar-sysfs.c | 2 +- arch/powerpc/perf/hv-24x7.c | 2 +- arch/powerpc/platforms/powernv/opal-core.c | 2 +- arch/s390/kernel/cpacf.c | 2 +- arch/s390/kernel/ipl.c | 18 +++++++++--------- arch/s390/pci/pci_sysfs.c | 2 +- arch/x86/kernel/ksysfs.c | 4 ++-- drivers/accel/habanalabs/common/sysfs.c | 2 +- drivers/acpi/bgrt.c | 2 +- drivers/base/devcoredump.c | 2 +- drivers/base/firmware_loader/sysfs.c | 2 +- drivers/base/node.c | 2 +- drivers/base/topology.c | 2 +- drivers/cxl/port.c | 2 +- drivers/firmware/google/cbmem.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2 +- drivers/gpu/drm/drm_sysfs.c | 2 +- drivers/hid/hid-core.c | 2 +- drivers/hid/hid-roccat-arvo.c | 2 +- drivers/hid/hid-roccat-isku.c | 2 +- drivers/hid/hid-roccat-kone.c | 2 +- drivers/hid/hid-roccat-koneplus.c | 2 +- drivers/hid/hid-roccat-konepure.c | 2 +- drivers/hid/hid-roccat-kovaplus.c | 2 +- drivers/hid/hid-roccat-pyra.c | 2 +- drivers/hid/hid-roccat-ryos.c | 2 +- drivers/hid/hid-roccat-savu.c | 2 +- drivers/iio/imu/bno055/bno055.c | 2 +- drivers/infiniband/hw/hfi1/sysfs.c | 2 +- drivers/infiniband/hw/qib/qib_sysfs.c | 2 +- drivers/input/touchscreen/goodix_berlin_core.c | 2 +- drivers/leds/led-class.c | 2 +- drivers/misc/c2port/core.c | 2 +- drivers/mtd/spi-nor/sysfs.c | 2 +- drivers/nvmem/core.c | 4 ++-- drivers/pci/p2pdma.c | 2 +- drivers/pci/pci-sysfs.c | 4 ++-- drivers/pci/vpd.c | 2 +- drivers/platform/chrome/cros_ec_vbc.c | 2 +- drivers/platform/x86/amd/hsmp/acpi.c | 2 +- drivers/platform/x86/amd/hsmp/plat.c | 2 +- drivers/platform/x86/dell/dcdbas.c | 2 +- drivers/platform/x86/dell/dell_rbu.c | 2 +- drivers/platform/x86/intel/sdsi.c | 2 +- drivers/platform/x86/wmi-bmof.c | 2 +- drivers/power/supply/ds2760_battery.c | 2 +- drivers/power/supply/ds2780_battery.c | 2 +- drivers/power/supply/ds2781_battery.c | 2 +- drivers/power/supply/olpc_battery.c | 2 +- drivers/ptp/ptp_ocp.c | 2 +- drivers/rapidio/rio-sysfs.c | 2 +- drivers/s390/cio/chp.c | 2 +- drivers/s390/crypto/pkey_sysfs.c | 8 ++++---- drivers/scsi/scsi_sysfs.c | 2 +- drivers/usb/core/sysfs.c | 2 +- drivers/usb/usbip/vudc_sysfs.c | 2 +- drivers/virt/coco/guest/tsm-mr.c | 4 ++-- drivers/w1/slaves/w1_ds2408.c | 2 +- drivers/w1/slaves/w1_ds2413.c | 2 +- drivers/w1/slaves/w1_ds2430.c | 2 +- drivers/w1/slaves/w1_ds2431.c | 2 +- drivers/w1/slaves/w1_ds2433.c | 4 ++-- drivers/w1/slaves/w1_ds2438.c | 2 +- drivers/w1/slaves/w1_ds2780.c | 2 +- drivers/w1/slaves/w1_ds2781.c | 2 +- drivers/w1/slaves/w1_ds28e04.c | 2 +- drivers/w1/w1.c | 2 +- drivers/zorro/zorro-sysfs.c | 2 +- kernel/module/sysfs.c | 10 +++++----- mm/page_idle.c | 2 +- 71 files changed, 91 insertions(+), 91 deletions(-) diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c index afb690a172b4..ec900bce0257 100644 --- a/arch/powerpc/kernel/secvar-sysfs.c +++ b/arch/powerpc/kernel/secvar-sysfs.c @@ -121,7 +121,7 @@ static struct attribute *secvar_attrs[] = { static const struct attribute_group secvar_attr_group = { .attrs = secvar_attrs, - .bin_attrs_new = secvar_bin_attrs, + .bin_attrs = secvar_bin_attrs, }; __ATTRIBUTE_GROUPS(secvar_attr); diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index b0768f3d2893..681cf85af2b3 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -1141,7 +1141,7 @@ static struct attribute *if_attrs[] = { static const struct attribute_group if_group = { .name = "interface", - .bin_attrs_new = if_bin_attrs, + .bin_attrs = if_bin_attrs, .attrs = if_attrs, }; diff --git a/arch/powerpc/platforms/powernv/opal-core.c b/arch/powerpc/platforms/powernv/opal-core.c index 6fe121aae405..784602a48afb 100644 --- a/arch/powerpc/platforms/powernv/opal-core.c +++ b/arch/powerpc/platforms/powernv/opal-core.c @@ -607,7 +607,7 @@ static const struct bin_attribute *const mpipl_bin_attr[] = { static const struct attribute_group mpipl_group = { .attrs = mpipl_attr, - .bin_attrs_new = mpipl_bin_attr, + .bin_attrs = mpipl_bin_attr, }; static int __init opalcore_init(void) diff --git a/arch/s390/kernel/cpacf.c b/arch/s390/kernel/cpacf.c index 4b9b34f95d72..3bebc47beeab 100644 --- a/arch/s390/kernel/cpacf.c +++ b/arch/s390/kernel/cpacf.c @@ -101,7 +101,7 @@ static const struct bin_attribute *const cpacf_attrs[] = { static const struct attribute_group cpacf_attr_grp = { .name = "cpacf", - .bin_attrs_new = cpacf_attrs, + .bin_attrs = cpacf_attrs, }; static int __init cpacf_init(void) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index ff15f91affde..961a3d60a4dd 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -596,7 +596,7 @@ static struct attribute *ipl_fcp_attrs[] = { static const struct attribute_group ipl_fcp_attr_group = { .attrs = ipl_fcp_attrs, - .bin_attrs_new = ipl_fcp_bin_attrs, + .bin_attrs = ipl_fcp_bin_attrs, }; static struct attribute *ipl_nvme_attrs[] = { @@ -610,7 +610,7 @@ static struct attribute *ipl_nvme_attrs[] = { static const struct attribute_group ipl_nvme_attr_group = { .attrs = ipl_nvme_attrs, - .bin_attrs_new = ipl_nvme_bin_attrs, + .bin_attrs = ipl_nvme_bin_attrs, }; static struct attribute *ipl_eckd_attrs[] = { @@ -623,7 +623,7 @@ static struct attribute *ipl_eckd_attrs[] = { static const struct attribute_group ipl_eckd_attr_group = { .attrs = ipl_eckd_attrs, - .bin_attrs_new = ipl_eckd_bin_attrs, + .bin_attrs = ipl_eckd_bin_attrs, }; /* CCW ipl device attributes */ @@ -920,7 +920,7 @@ static struct attribute *reipl_fcp_attrs[] = { static const struct attribute_group reipl_fcp_attr_group = { .attrs = reipl_fcp_attrs, - .bin_attrs_new = reipl_fcp_bin_attrs, + .bin_attrs = reipl_fcp_bin_attrs, }; static struct kobj_attribute sys_reipl_fcp_clear_attr = @@ -958,7 +958,7 @@ static struct attribute *reipl_nvme_attrs[] = { static const struct attribute_group reipl_nvme_attr_group = { .attrs = reipl_nvme_attrs, - .bin_attrs_new = reipl_nvme_bin_attrs + .bin_attrs = reipl_nvme_bin_attrs }; static ssize_t reipl_nvme_clear_show(struct kobject *kobj, @@ -1051,7 +1051,7 @@ static struct attribute *reipl_eckd_attrs[] = { static const struct attribute_group reipl_eckd_attr_group = { .attrs = reipl_eckd_attrs, - .bin_attrs_new = reipl_eckd_bin_attrs + .bin_attrs = reipl_eckd_bin_attrs }; static ssize_t reipl_eckd_clear_show(struct kobject *kobj, @@ -1596,7 +1596,7 @@ static const struct bin_attribute *const dump_fcp_bin_attrs[] = { static const struct attribute_group dump_fcp_attr_group = { .name = IPL_FCP_STR, .attrs = dump_fcp_attrs, - .bin_attrs_new = dump_fcp_bin_attrs, + .bin_attrs = dump_fcp_bin_attrs, }; /* NVME dump device attributes */ @@ -1630,7 +1630,7 @@ static const struct bin_attribute *const dump_nvme_bin_attrs[] = { static const struct attribute_group dump_nvme_attr_group = { .name = IPL_NVME_STR, .attrs = dump_nvme_attrs, - .bin_attrs_new = dump_nvme_bin_attrs, + .bin_attrs = dump_nvme_bin_attrs, }; /* ECKD dump device attributes */ @@ -1664,7 +1664,7 @@ static const struct bin_attribute *const dump_eckd_bin_attrs[] = { static const struct attribute_group dump_eckd_attr_group = { .name = IPL_ECKD_STR, .attrs = dump_eckd_attrs, - .bin_attrs_new = dump_eckd_bin_attrs, + .bin_attrs = dump_eckd_bin_attrs, }; /* CCW dump device attributes */ diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index 0ecad08e1b1e..0ee0924cfab7 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c @@ -218,7 +218,7 @@ static struct attribute *zpci_dev_attrs[] = { const struct attribute_group zpci_attr_group = { .attrs = zpci_dev_attrs, - .bin_attrs_new = zpci_bin_attrs, + .bin_attrs = zpci_bin_attrs, }; static struct attribute *pfip_attrs[] = { diff --git a/arch/x86/kernel/ksysfs.c b/arch/x86/kernel/ksysfs.c index 4ee7fd9dd69c..d547de9b3ed8 100644 --- a/arch/x86/kernel/ksysfs.c +++ b/arch/x86/kernel/ksysfs.c @@ -56,7 +56,7 @@ static const struct bin_attribute *const boot_params_data_attrs[] = { static const struct attribute_group boot_params_attr_group = { .attrs = boot_params_version_attrs, - .bin_attrs_new = boot_params_data_attrs, + .bin_attrs = boot_params_data_attrs, }; static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr) @@ -265,7 +265,7 @@ static const struct bin_attribute *const setup_data_data_attrs[] = { static const struct attribute_group setup_data_attr_group = { .attrs = setup_data_type_attrs, - .bin_attrs_new = setup_data_data_attrs, + .bin_attrs = setup_data_data_attrs, }; static int __init create_setup_data_node(struct kobject *parent, diff --git a/drivers/accel/habanalabs/common/sysfs.c b/drivers/accel/habanalabs/common/sysfs.c index 678585cfef84..82f66520ec18 100644 --- a/drivers/accel/habanalabs/common/sysfs.c +++ b/drivers/accel/habanalabs/common/sysfs.c @@ -479,7 +479,7 @@ static const struct bin_attribute *const hl_dev_bin_attrs[] = { static struct attribute_group hl_dev_attr_group = { .attrs = hl_dev_attrs, - .bin_attrs_new = hl_dev_bin_attrs, + .bin_attrs = hl_dev_bin_attrs, }; static struct attribute_group hl_dev_clks_attr_group; diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index 35ece8e9f15d..0fdd581ef96f 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -47,7 +47,7 @@ static const struct bin_attribute *const bgrt_bin_attributes[] = { static const struct attribute_group bgrt_attribute_group = { .attrs = bgrt_attributes, - .bin_attrs_new = bgrt_bin_attributes, + .bin_attrs = bgrt_bin_attributes, }; int __init acpi_parse_bgrt(struct acpi_table_header *table) diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 03a39c417dc4..37faf6156d7c 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -140,7 +140,7 @@ static const struct bin_attribute *const devcd_dev_bin_attrs[] = { }; static const struct attribute_group devcd_dev_group = { - .bin_attrs_new = devcd_dev_bin_attrs, + .bin_attrs = devcd_dev_bin_attrs, }; static const struct attribute_group *devcd_dev_groups[] = { diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index c9b1564616f4..add0b9b75edd 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -381,7 +381,7 @@ static const struct bin_attribute *const fw_dev_bin_attrs[] = { static const struct attribute_group fw_dev_attr_group = { .attrs = fw_dev_attrs, - .bin_attrs_new = fw_dev_bin_attrs, + .bin_attrs = fw_dev_bin_attrs, #ifdef CONFIG_FW_UPLOAD .is_visible = fw_upload_is_visible, #endif diff --git a/drivers/base/node.c b/drivers/base/node.c index c19094481630..9328b81c2f47 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -597,7 +597,7 @@ static const struct bin_attribute *node_dev_bin_attrs[] = { static const struct attribute_group node_dev_group = { .attrs = node_dev_attrs, - .bin_attrs_new = node_dev_bin_attrs, + .bin_attrs = node_dev_bin_attrs, }; static const struct attribute_group *node_dev_groups[] = { diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 8b42df05feff..c890e2a5b428 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -179,7 +179,7 @@ static umode_t topology_is_visible(struct kobject *kobj, static const struct attribute_group topology_attr_group = { .attrs = default_attrs, - .bin_attrs_new = bin_attrs, + .bin_attrs = bin_attrs, .is_visible = topology_is_visible, .name = "topology" }; diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index fe4b593331da..cf32dc50b7a6 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -181,7 +181,7 @@ static const struct bin_attribute *const cxl_cdat_bin_attributes[] = { }; static const struct attribute_group cxl_cdat_attribute_group = { - .bin_attrs_new = cxl_cdat_bin_attributes, + .bin_attrs = cxl_cdat_bin_attributes, .is_bin_visible = cxl_port_bin_attr_is_visible, }; diff --git a/drivers/firmware/google/cbmem.c b/drivers/firmware/google/cbmem.c index 773d05078e0a..54c3b8b05e5d 100644 --- a/drivers/firmware/google/cbmem.c +++ b/drivers/firmware/google/cbmem.c @@ -86,7 +86,7 @@ static const struct bin_attribute *const bin_attrs[] = { static const struct attribute_group cbmem_entry_group = { .attrs = attrs, - .bin_attrs_new = bin_attrs, + .bin_attrs = bin_attrs, }; static const struct attribute_group *dev_groups[] = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index be9f03bbcb36..41c150ae4143 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -4181,7 +4181,7 @@ static umode_t amdgpu_bin_flash_attr_is_visible(struct kobject *kobj, const struct attribute_group amdgpu_flash_attr_group = { .attrs = flash_attrs, - .bin_attrs_new = bin_flash_attrs, + .bin_attrs = bin_flash_attrs, .is_bin_visible = amdgpu_bin_flash_attr_is_visible, .is_visible = amdgpu_flash_attr_is_visible, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index de0944947eaf..9c8829bd5a58 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2124,7 +2124,7 @@ static int amdgpu_ras_fs_init(struct amdgpu_device *adev) con->badpages_attr = bin_attr_gpu_vram_bad_pages; sysfs_bin_attr_init(&con->badpages_attr); bin_attrs[0] = &con->badpages_attr; - group.bin_attrs_new = bin_attrs; + group.bin_attrs = bin_attrs; } r = sysfs_create_group(&adev->dev->kobj, &group); diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 8d27ba7f0d83..a455c56dbbeb 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -329,7 +329,7 @@ static const struct bin_attribute *const connector_bin_attrs[] = { static const struct attribute_group connector_dev_group = { .attrs = connector_dev_attrs, - .bin_attrs_new = connector_bin_attrs, + .bin_attrs = connector_bin_attrs, }; static const struct attribute_group *connector_dev_groups[] = { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b348d0464314..b10a28a75546 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2812,7 +2812,7 @@ static const struct bin_attribute *hid_dev_bin_attrs[] = { }; static const struct attribute_group hid_dev_group = { .attrs = hid_dev_attrs, - .bin_attrs_new = hid_dev_bin_attrs, + .bin_attrs = hid_dev_bin_attrs, }; __ATTRIBUTE_GROUPS(hid_dev); diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c index 3048297569c5..7b09adfa44a1 100644 --- a/drivers/hid/hid-roccat-arvo.c +++ b/drivers/hid/hid-roccat-arvo.c @@ -258,7 +258,7 @@ static const struct bin_attribute *const arvo_bin_attributes[] = { static const struct attribute_group arvo_group = { .attrs = arvo_attrs, - .bin_attrs_new = arvo_bin_attributes, + .bin_attrs = arvo_bin_attributes, }; static const struct attribute_group *arvo_groups[] = { diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c index 9fddc42f241b..339378771ed5 100644 --- a/drivers/hid/hid-roccat-isku.c +++ b/drivers/hid/hid-roccat-isku.c @@ -238,7 +238,7 @@ static const struct bin_attribute *const isku_bin_attributes[] = { static const struct attribute_group isku_group = { .attrs = isku_attrs, - .bin_attrs_new = isku_bin_attributes, + .bin_attrs = isku_bin_attributes, }; static const struct attribute_group *isku_groups[] = { diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index af8ef42aca02..fabc08efcfd8 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -646,7 +646,7 @@ static const struct bin_attribute *const kone_bin_attributes[] = { static const struct attribute_group kone_group = { .attrs = kone_attrs, - .bin_attrs_new = kone_bin_attributes, + .bin_attrs = kone_bin_attributes, }; static const struct attribute_group *kone_groups[] = { diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index c3f01f7b7e48..77d45d36421a 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c @@ -346,7 +346,7 @@ static const struct bin_attribute *const koneplus_bin_attributes[] = { static const struct attribute_group koneplus_group = { .attrs = koneplus_attrs, - .bin_attrs_new = koneplus_bin_attributes, + .bin_attrs = koneplus_bin_attributes, }; static const struct attribute_group *koneplus_groups[] = { diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c index 7fb705789d4e..027bfc55ef9c 100644 --- a/drivers/hid/hid-roccat-konepure.c +++ b/drivers/hid/hid-roccat-konepure.c @@ -62,7 +62,7 @@ static const struct bin_attribute *const konepure_bin_attrs[] = { }; static const struct attribute_group konepure_group = { - .bin_attrs_new = konepure_bin_attrs, + .bin_attrs = konepure_bin_attrs, }; static const struct attribute_group *konepure_groups[] = { diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 7d625ed53c9f..a66f1b4730f3 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -399,7 +399,7 @@ static const struct bin_attribute *const kovaplus_bin_attributes[] = { static const struct attribute_group kovaplus_group = { .attrs = kovaplus_attrs, - .bin_attrs_new = kovaplus_bin_attributes, + .bin_attrs = kovaplus_bin_attributes, }; static const struct attribute_group *kovaplus_groups[] = { diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index dbb905585369..de2da6086e0b 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -355,7 +355,7 @@ static const struct bin_attribute *const pyra_bin_attributes[] = { static const struct attribute_group pyra_group = { .attrs = pyra_attrs, - .bin_attrs_new = pyra_bin_attributes, + .bin_attrs = pyra_bin_attributes, }; static const struct attribute_group *pyra_groups[] = { diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c index 902dac1e714e..36911c9da4fe 100644 --- a/drivers/hid/hid-roccat-ryos.c +++ b/drivers/hid/hid-roccat-ryos.c @@ -70,7 +70,7 @@ static const struct bin_attribute *const ryos_bin_attrs[] = { }; static const struct attribute_group ryos_group = { - .bin_attrs_new = ryos_bin_attrs, + .bin_attrs = ryos_bin_attrs, }; static const struct attribute_group *ryos_groups[] = { diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c index 7399b8ffb5c7..fb2e464c3ada 100644 --- a/drivers/hid/hid-roccat-savu.c +++ b/drivers/hid/hid-roccat-savu.c @@ -42,7 +42,7 @@ static const struct bin_attribute *const savu_bin_attrs[] = { }; static const struct attribute_group savu_group = { - .bin_attrs_new = savu_bin_attrs, + .bin_attrs = savu_bin_attrs, }; static const struct attribute_group *savu_groups[] = { diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c index 597c402b98de..574657db13f6 100644 --- a/drivers/iio/imu/bno055/bno055.c +++ b/drivers/iio/imu/bno055/bno055.c @@ -1357,7 +1357,7 @@ static const struct bin_attribute *const bno055_bin_attrs[] = { static const struct attribute_group bno055_attrs_group = { .attrs = bno055_attrs, - .bin_attrs_new = bno055_bin_attrs, + .bin_attrs = bno055_bin_attrs, }; static const struct iio_info bno055_info = { diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c index d94216c7d576..372cfd13dc61 100644 --- a/drivers/infiniband/hw/hfi1/sysfs.c +++ b/drivers/infiniband/hw/hfi1/sysfs.c @@ -134,7 +134,7 @@ static struct attribute *port_cc_attributes[] = { static const struct attribute_group port_cc_group = { .name = "CCMgtA", .attrs = port_cc_attributes, - .bin_attrs_new = port_cc_bin_attributes, + .bin_attrs = port_cc_bin_attributes, }; /* Start sc2vl */ diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c index 805e37dc7621..a6571bc38366 100644 --- a/drivers/infiniband/hw/qib/qib_sysfs.c +++ b/drivers/infiniband/hw/qib/qib_sysfs.c @@ -295,7 +295,7 @@ static umode_t qib_ccmgta_is_bin_visible(struct kobject *kobj, static const struct attribute_group port_ccmgta_attribute_group = { .name = "CCMgtA", .is_bin_visible = qib_ccmgta_is_bin_visible, - .bin_attrs_new = port_ccmgta_attributes, + .bin_attrs = port_ccmgta_attributes, }; /* Start sl2vl */ diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c index 02a1d9a465f2..c78d512d97cd 100644 --- a/drivers/input/touchscreen/goodix_berlin_core.c +++ b/drivers/input/touchscreen/goodix_berlin_core.c @@ -707,7 +707,7 @@ static const struct bin_attribute *const goodix_berlin_bin_attrs[] = { }; static const struct attribute_group goodix_berlin_attr_group = { - .bin_attrs_new = goodix_berlin_bin_attrs, + .bin_attrs = goodix_berlin_bin_attrs, }; const struct attribute_group *goodix_berlin_groups[] = { diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index c20ac8ccf52b..58592593b8e9 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -91,7 +91,7 @@ static const struct bin_attribute *const led_trigger_bin_attrs[] = { NULL, }; static const struct attribute_group led_trigger_group = { - .bin_attrs_new = led_trigger_bin_attrs, + .bin_attrs = led_trigger_bin_attrs, }; #endif diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index fc64474b8241..babdb60cc46c 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -888,7 +888,7 @@ static size_t c2port_bin_attr_size(struct kobject *kobj, static const struct attribute_group c2port_group = { .attrs = c2port_attrs, - .bin_attrs_new = c2port_bin_attrs, + .bin_attrs = c2port_bin_attrs, .bin_size = c2port_bin_attr_size, }; diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c index 4f12ff755df0..643513ee891b 100644 --- a/drivers/mtd/spi-nor/sysfs.c +++ b/drivers/mtd/spi-nor/sysfs.c @@ -104,7 +104,7 @@ static const struct attribute_group spi_nor_sysfs_group = { .is_visible = spi_nor_sysfs_is_visible, .is_bin_visible = spi_nor_sysfs_is_bin_visible, .attrs = spi_nor_sysfs_entries, - .bin_attrs_new = spi_nor_sysfs_bin_entries, + .bin_attrs = spi_nor_sysfs_bin_entries, }; const struct attribute_group *spi_nor_sysfs_groups[] = { diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index f0a664bcb01a..1cd962312fa8 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -386,7 +386,7 @@ static const struct bin_attribute *const nvmem_bin_attributes[] = { }; static const struct attribute_group nvmem_bin_group = { - .bin_attrs_new = nvmem_bin_attributes, + .bin_attrs = nvmem_bin_attributes, .attrs = nvmem_attrs, .is_bin_visible = nvmem_bin_attr_is_visible, .bin_size = nvmem_bin_attr_size, @@ -503,7 +503,7 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) i++; } - group.bin_attrs_new = pattrs; + group.bin_attrs = pattrs; ret = device_add_group(&nvmem->dev, &group); if (ret) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 8d955c25aed3..da5657a02007 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -196,7 +196,7 @@ static const struct bin_attribute *const p2pmem_bin_attrs[] = { static const struct attribute_group p2pmem_group = { .attrs = p2pmem_attrs, - .bin_attrs_new = p2pmem_bin_attrs, + .bin_attrs = p2pmem_bin_attrs, .name = "p2pmem", }; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index f2739eafef9b..5eea14c1f7f5 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -857,7 +857,7 @@ static size_t pci_dev_config_attr_bin_size(struct kobject *kobj, } static const struct attribute_group pci_dev_config_attr_group = { - .bin_attrs_new = pci_dev_config_attrs, + .bin_attrs = pci_dev_config_attrs, .bin_size = pci_dev_config_attr_bin_size, }; @@ -1377,7 +1377,7 @@ static size_t pci_dev_rom_attr_bin_size(struct kobject *kobj, } static const struct attribute_group pci_dev_rom_attr_group = { - .bin_attrs_new = pci_dev_rom_attrs, + .bin_attrs = pci_dev_rom_attrs, .is_bin_visible = pci_dev_rom_attr_is_visible, .bin_size = pci_dev_rom_attr_bin_size, }; diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c index 3d29b2602d0f..153394a652d3 100644 --- a/drivers/pci/vpd.c +++ b/drivers/pci/vpd.c @@ -336,7 +336,7 @@ static umode_t vpd_attr_is_visible(struct kobject *kobj, } const struct attribute_group pci_dev_vpd_attr_group = { - .bin_attrs_new = vpd_attrs, + .bin_attrs = vpd_attrs, .is_bin_visible = vpd_attr_is_visible, }; diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index 963c4db23055..5ee8adaa6564 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -108,7 +108,7 @@ static const struct bin_attribute *const cros_ec_vbc_bin_attrs[] = { static const struct attribute_group cros_ec_vbc_attr_group = { .name = "vbc", - .bin_attrs_new = cros_ec_vbc_bin_attrs, + .bin_attrs = cros_ec_vbc_bin_attrs, }; static int cros_ec_vbc_probe(struct platform_device *pd) diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c index 63af9dae0254..9155ce35a743 100644 --- a/drivers/platform/x86/amd/hsmp/acpi.c +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -560,7 +560,7 @@ static struct attribute *hsmp_dev_attr_list[] = { }; static const struct attribute_group hsmp_attr_grp = { - .bin_attrs_new = hsmp_attr_list, + .bin_attrs = hsmp_attr_list, .attrs = hsmp_dev_attr_list, .is_bin_visible = hsmp_is_sock_attr_visible, .is_visible = hsmp_is_sock_dev_attr_visible, diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c index b6dceca28bdb..e257fb0f4143 100644 --- a/drivers/platform/x86/amd/hsmp/plat.c +++ b/drivers/platform/x86/amd/hsmp/plat.c @@ -110,7 +110,7 @@ HSMP_BIN_ATTR(7, *sock7_attr_list); #define HSMP_BIN_ATTR_GRP(index, _list, _name) \ static const struct attribute_group sock##index##_attr_grp = { \ - .bin_attrs_new = _list, \ + .bin_attrs = _list, \ .is_bin_visible = hsmp_is_sock_attr_visible, \ .name = #_name, \ } diff --git a/drivers/platform/x86/dell/dcdbas.c b/drivers/platform/x86/dell/dcdbas.c index 8149be25fa26..678f44252a45 100644 --- a/drivers/platform/x86/dell/dcdbas.c +++ b/drivers/platform/x86/dell/dcdbas.c @@ -662,7 +662,7 @@ static struct attribute *dcdbas_dev_attrs[] = { static const struct attribute_group dcdbas_attr_group = { .attrs = dcdbas_dev_attrs, - .bin_attrs_new = dcdbas_bin_attrs, + .bin_attrs = dcdbas_bin_attrs, }; static int dcdbas_probe(struct platform_device *dev) diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c index e30ca325938c..d74f2d47917c 100644 --- a/drivers/platform/x86/dell/dell_rbu.c +++ b/drivers/platform/x86/dell/dell_rbu.c @@ -636,7 +636,7 @@ static const struct bin_attribute *const rbu_bin_attrs[] = { }; static const struct attribute_group rbu_group = { - .bin_attrs_new = rbu_bin_attrs, + .bin_attrs = rbu_bin_attrs, }; static int __init dcdrbu_init(void) diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c index 30d1c2caf984..da75f53d0bcc 100644 --- a/drivers/platform/x86/intel/sdsi.c +++ b/drivers/platform/x86/intel/sdsi.c @@ -576,7 +576,7 @@ static struct attribute *sdsi_attrs[] = { static const struct attribute_group sdsi_group = { .attrs = sdsi_attrs, - .bin_attrs_new = sdsi_bin_attrs, + .bin_attrs = sdsi_bin_attrs, .is_bin_visible = sdsi_battr_is_visible, }; __ATTRIBUTE_GROUPS(sdsi); diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c index 3e33da36da8a..5b00370a9a22 100644 --- a/drivers/platform/x86/wmi-bmof.c +++ b/drivers/platform/x86/wmi-bmof.c @@ -46,7 +46,7 @@ static size_t bmof_bin_size(struct kobject *kobj, const struct bin_attribute *at static const struct attribute_group bmof_group = { .bin_size = bmof_bin_size, - .bin_attrs_new = bmof_attrs, + .bin_attrs = bmof_attrs, }; static const struct attribute_group *bmof_groups[] = { diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c index 5badf58c6edb..142c7492c3c2 100644 --- a/drivers/power/supply/ds2760_battery.c +++ b/drivers/power/supply/ds2760_battery.c @@ -209,7 +209,7 @@ static const struct bin_attribute *const w1_ds2760_bin_attrs[] = { }; static const struct attribute_group w1_ds2760_group = { - .bin_attrs_new = w1_ds2760_bin_attrs, + .bin_attrs = w1_ds2760_bin_attrs, }; static const struct attribute_group *w1_ds2760_groups[] = { diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c index 8352c6401cbf..5b57bbba79d4 100644 --- a/drivers/power/supply/ds2780_battery.c +++ b/drivers/power/supply/ds2780_battery.c @@ -734,7 +734,7 @@ static const struct bin_attribute *const ds2780_sysfs_bin_attrs[] = { static const struct attribute_group ds2780_sysfs_group = { .attrs = ds2780_sysfs_attrs, - .bin_attrs_new = ds2780_sysfs_bin_attrs, + .bin_attrs = ds2780_sysfs_bin_attrs, }; static const struct attribute_group *ds2780_sysfs_groups[] = { diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c index 43a6b022901e..1319e02f3f95 100644 --- a/drivers/power/supply/ds2781_battery.c +++ b/drivers/power/supply/ds2781_battery.c @@ -737,7 +737,7 @@ static const struct bin_attribute *const ds2781_sysfs_bin_attrs[] = { static const struct attribute_group ds2781_sysfs_group = { .attrs = ds2781_sysfs_attrs, - .bin_attrs_new = ds2781_sysfs_bin_attrs, + .bin_attrs = ds2781_sysfs_bin_attrs, }; diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index a9760dbb1616..202c4fa9b903 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c @@ -591,7 +591,7 @@ static const struct bin_attribute *const olpc_bat_sysfs_bin_attrs[] = { static const struct attribute_group olpc_bat_sysfs_group = { .attrs = olpc_bat_sysfs_attrs, - .bin_attrs_new = olpc_bat_sysfs_bin_attrs, + .bin_attrs = olpc_bat_sysfs_bin_attrs, }; static const struct attribute_group *olpc_bat_sysfs_groups[] = { diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 1e7f72e57557..d39073dc4072 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -3938,7 +3938,7 @@ static const struct bin_attribute *const bin_art_timecard_attrs[] = { static const struct attribute_group art_timecard_group = { .attrs = art_timecard_attrs, - .bin_attrs_new = bin_art_timecard_attrs, + .bin_attrs = bin_art_timecard_attrs, }; static const struct ocp_attr_group art_timecard_groups[] = { diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 5e8c22677e46..0949c869b2f1 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -278,7 +278,7 @@ static umode_t rio_dev_is_attr_visible(struct kobject *kobj, static const struct attribute_group rio_dev_group = { .attrs = rio_dev_attrs, .is_visible = rio_dev_is_attr_visible, - .bin_attrs_new = rio_dev_bin_attrs, + .bin_attrs = rio_dev_bin_attrs, }; const struct attribute_group *rio_dev_groups[] = { diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 4f01b1929240..caa300160b17 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -470,7 +470,7 @@ static struct attribute *chp_attrs[] = { }; static const struct attribute_group chp_attr_group = { .attrs = chp_attrs, - .bin_attrs_new = chp_bin_attrs, + .bin_attrs = chp_bin_attrs, }; static const struct attribute_group *chp_attr_groups[] = { &chp_attr_group, diff --git a/drivers/s390/crypto/pkey_sysfs.c b/drivers/s390/crypto/pkey_sysfs.c index cea772973649..792c0fce88fa 100644 --- a/drivers/s390/crypto/pkey_sysfs.c +++ b/drivers/s390/crypto/pkey_sysfs.c @@ -297,7 +297,7 @@ static const struct bin_attribute *const protkey_attrs[] = { static const struct attribute_group protkey_attr_group = { .name = "protkey", - .bin_attrs_new = protkey_attrs, + .bin_attrs = protkey_attrs, }; /* @@ -406,7 +406,7 @@ static const struct bin_attribute *const ccadata_attrs[] = { static const struct attribute_group ccadata_attr_group = { .name = "ccadata", - .bin_attrs_new = ccadata_attrs, + .bin_attrs = ccadata_attrs, }; #define CCACIPHERTOKENSIZE (sizeof(struct cipherkeytoken) + 80) @@ -520,7 +520,7 @@ static const struct bin_attribute *const ccacipher_attrs[] = { static const struct attribute_group ccacipher_attr_group = { .name = "ccacipher", - .bin_attrs_new = ccacipher_attrs, + .bin_attrs = ccacipher_attrs, }; /* @@ -635,7 +635,7 @@ static const struct bin_attribute *const ep11_attrs[] = { static const struct attribute_group ep11_attr_group = { .name = "ep11", - .bin_attrs_new = ep11_attrs, + .bin_attrs = ep11_attrs, }; const struct attribute_group *pkey_attr_groups[] = { diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index deba96107d20..169af7d47ce7 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1362,7 +1362,7 @@ static const struct bin_attribute *const scsi_sdev_bin_attrs[] = { }; static struct attribute_group scsi_sdev_attr_group = { .attrs = scsi_sdev_attrs, - .bin_attrs_new = scsi_sdev_bin_attrs, + .bin_attrs = scsi_sdev_bin_attrs, .is_visible = scsi_sdev_attr_is_visible, .is_bin_visible = scsi_sdev_bin_attr_is_visible, }; diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 23f3cb1989f4..a07866f1060c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -944,7 +944,7 @@ static umode_t dev_bin_attrs_are_visible(struct kobject *kobj, } static const struct attribute_group dev_bin_attr_grp = { - .bin_attrs_new = dev_bin_attrs, + .bin_attrs = dev_bin_attrs, .is_bin_visible = dev_bin_attrs_are_visible, }; diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c index 2aae3edfc813..47f3a7d51736 100644 --- a/drivers/usb/usbip/vudc_sysfs.c +++ b/drivers/usb/usbip/vudc_sysfs.c @@ -259,7 +259,7 @@ static const struct bin_attribute *const dev_bin_attrs[] = { static const struct attribute_group vudc_attr_group = { .attrs = dev_attrs, - .bin_attrs_new = dev_bin_attrs, + .bin_attrs = dev_bin_attrs, }; const struct attribute_group *vudc_groups[] = { diff --git a/drivers/virt/coco/guest/tsm-mr.c b/drivers/virt/coco/guest/tsm-mr.c index 74465e79be60..bc509df04db1 100644 --- a/drivers/virt/coco/guest/tsm-mr.c +++ b/drivers/virt/coco/guest/tsm-mr.c @@ -228,7 +228,7 @@ tsm_mr_create_attribute_group(const struct tsm_measurements *tm) init_rwsem(&ctx->rwsem); ctx->agrp.name = "measurements"; - ctx->agrp.bin_attrs_new = no_free_ptr(attrs); + ctx->agrp.bin_attrs = no_free_ptr(attrs); ctx->tm = tm; return &no_free_ptr(ctx)->agrp; } @@ -244,7 +244,7 @@ EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group); void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp) { if (!IS_ERR_OR_NULL(attr_grp)) { - kfree(attr_grp->bin_attrs_new); + kfree(attr_grp->bin_attrs); kfree(container_of(attr_grp, struct tm_context, agrp)); } } diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c index beccd2912d2a..30d1d574d2e5 100644 --- a/drivers/w1/slaves/w1_ds2408.c +++ b/drivers/w1/slaves/w1_ds2408.c @@ -328,7 +328,7 @@ static const struct bin_attribute *const w1_f29_bin_attrs[] = { }; static const struct attribute_group w1_f29_group = { - .bin_attrs_new = w1_f29_bin_attrs, + .bin_attrs = w1_f29_bin_attrs, }; static const struct attribute_group *w1_f29_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c index 5fa46017ca7c..94d3cd2a0ec9 100644 --- a/drivers/w1/slaves/w1_ds2413.c +++ b/drivers/w1/slaves/w1_ds2413.c @@ -137,7 +137,7 @@ static const struct bin_attribute *const w1_f3a_bin_attrs[] = { }; static const struct attribute_group w1_f3a_group = { - .bin_attrs_new = w1_f3a_bin_attrs, + .bin_attrs = w1_f3a_bin_attrs, }; static const struct attribute_group *w1_f3a_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2430.c b/drivers/w1/slaves/w1_ds2430.c index ff56e2e68e58..3d8c2b238aed 100644 --- a/drivers/w1/slaves/w1_ds2430.c +++ b/drivers/w1/slaves/w1_ds2430.c @@ -271,7 +271,7 @@ static const struct bin_attribute *const w1_f14_bin_attrs[] = { }; static const struct attribute_group w1_f14_group = { - .bin_attrs_new = w1_f14_bin_attrs, + .bin_attrs = w1_f14_bin_attrs, }; static const struct attribute_group *w1_f14_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c index 27b390fb59da..5749880b67c5 100644 --- a/drivers/w1/slaves/w1_ds2431.c +++ b/drivers/w1/slaves/w1_ds2431.c @@ -270,7 +270,7 @@ static const struct bin_attribute *const w1_f2d_bin_attrs[] = { }; static const struct attribute_group w1_f2d_group = { - .bin_attrs_new = w1_f2d_bin_attrs, + .bin_attrs = w1_f2d_bin_attrs, }; static const struct attribute_group *w1_f2d_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index a53eb34fea79..3371d804dc6c 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c @@ -294,7 +294,7 @@ static const struct bin_attribute *const w1_f23_bin_attributes[] = { }; static const struct attribute_group w1_f23_group = { - .bin_attrs_new = w1_f23_bin_attributes, + .bin_attrs = w1_f23_bin_attributes, }; static const struct attribute_group *w1_f23_groups[] = { @@ -308,7 +308,7 @@ static const struct bin_attribute *const w1_f43_bin_attributes[] = { }; static const struct attribute_group w1_f43_group = { - .bin_attrs_new = w1_f43_bin_attributes, + .bin_attrs = w1_f43_bin_attributes, }; static const struct attribute_group *w1_f43_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c index 630a6db5045e..86860f727e96 100644 --- a/drivers/w1/slaves/w1_ds2438.c +++ b/drivers/w1/slaves/w1_ds2438.c @@ -492,7 +492,7 @@ static const struct bin_attribute *const w1_ds2438_bin_attrs[] = { }; static const struct attribute_group w1_ds2438_group = { - .bin_attrs_new = w1_ds2438_bin_attrs, + .bin_attrs = w1_ds2438_bin_attrs, }; static const struct attribute_group *w1_ds2438_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c index ba7beb7b01f9..889a6099c314 100644 --- a/drivers/w1/slaves/w1_ds2780.c +++ b/drivers/w1/slaves/w1_ds2780.c @@ -103,7 +103,7 @@ static const struct bin_attribute *const w1_ds2780_bin_attrs[] = { }; static const struct attribute_group w1_ds2780_group = { - .bin_attrs_new = w1_ds2780_bin_attrs, + .bin_attrs = w1_ds2780_bin_attrs, }; static const struct attribute_group *w1_ds2780_groups[] = { diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c index acd04ee96e81..88f3abd5cd4b 100644 --- a/drivers/w1/slaves/w1_ds2781.c +++ b/drivers/w1/slaves/w1_ds2781.c @@ -100,7 +100,7 @@ static const struct bin_attribute *const w1_ds2781_bin_attrs[] = { }; static const struct attribute_group w1_ds2781_group = { - .bin_attrs_new = w1_ds2781_bin_attrs, + .bin_attrs = w1_ds2781_bin_attrs, }; static const struct attribute_group *w1_ds2781_groups[] = { diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c index d99ffadbe29b..c577b5973032 100644 --- a/drivers/w1/slaves/w1_ds28e04.c +++ b/drivers/w1/slaves/w1_ds28e04.c @@ -371,7 +371,7 @@ static const struct bin_attribute *const w1_f1C_bin_attrs[] = { static const struct attribute_group w1_f1C_group = { .attrs = w1_f1C_attrs, - .bin_attrs_new = w1_f1C_bin_attrs, + .bin_attrs = w1_f1C_bin_attrs, }; static const struct attribute_group *w1_f1C_groups[] = { diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 29f200bbab41..d0474a0532ec 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -149,7 +149,7 @@ static const struct bin_attribute *const w1_slave_bin_attrs[] = { }; static const struct attribute_group w1_slave_default_group = { - .bin_attrs_new = w1_slave_bin_attrs, + .bin_attrs = w1_slave_bin_attrs, }; static const struct attribute_group *w1_slave_default_groups[] = { diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 294d3642a279..4e967754d8ad 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -114,7 +114,7 @@ static const struct bin_attribute *const zorro_device_bin_attrs[] = { static const struct attribute_group zorro_device_attr_group = { .attrs = zorro_device_attrs, - .bin_attrs_new = zorro_device_bin_attrs, + .bin_attrs = zorro_device_bin_attrs, }; const struct attribute_group *zorro_device_attribute_groups[] = { diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c index 5183ae86e05e..c7622ff5226a 100644 --- a/kernel/module/sysfs.c +++ b/kernel/module/sysfs.c @@ -56,9 +56,9 @@ static void free_sect_attrs(struct module_sect_attrs *sect_attrs) { const struct bin_attribute *const *bin_attr; - for (bin_attr = sect_attrs->grp.bin_attrs_new; *bin_attr; bin_attr++) + for (bin_attr = sect_attrs->grp.bin_attrs; *bin_attr; bin_attr++) kfree((*bin_attr)->attr.name); - kfree(sect_attrs->grp.bin_attrs_new); + kfree(sect_attrs->grp.bin_attrs); kfree(sect_attrs); } @@ -86,7 +86,7 @@ static int add_sect_attrs(struct module *mod, const struct load_info *info) /* Setup section attributes. */ sect_attrs->grp.name = "sections"; - sect_attrs->grp.bin_attrs_new = gattr; + sect_attrs->grp.bin_attrs = gattr; sattr = §_attrs->attrs[0]; for (i = 0; i < info->hdr->e_shnum; i++) { @@ -144,7 +144,7 @@ struct module_notes_attrs { static void free_notes_attrs(struct module_notes_attrs *notes_attrs) { - kfree(notes_attrs->grp.bin_attrs_new); + kfree(notes_attrs->grp.bin_attrs); kfree(notes_attrs); } @@ -178,7 +178,7 @@ static int add_notes_attrs(struct module *mod, const struct load_info *info) } notes_attrs->grp.name = "notes"; - notes_attrs->grp.bin_attrs_new = gattr; + notes_attrs->grp.bin_attrs = gattr; nattr = ¬es_attrs->attrs[0]; for (loaded = i = 0; i < info->hdr->e_shnum; ++i) { diff --git a/mm/page_idle.c b/mm/page_idle.c index 408aaf29a3ea..a82b340dc204 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c @@ -208,7 +208,7 @@ static const struct bin_attribute *const page_idle_bin_attrs[] = { }; static const struct attribute_group page_idle_attr_group = { - .bin_attrs_new = page_idle_bin_attrs, + .bin_attrs = page_idle_bin_attrs, .name = "page_idle", }; From b29929b819f35503024c6a7e6ad442f6e36c68a0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 16 Jun 2025 20:16:21 +0200 Subject: [PATCH 14/84] driver core: Add device_link_test() for testing device link flags To avoid coding mistakes like the one fixed by commit 3860cbe23963 ("PM: sleep: Fix bit masking operation"), introduce device_link_test() for testing device link flags and use it where applicable. No intentional functional impact. Signed-off-by: "Rafael J. Wysocki" Link: https://lore.kernel.org/r/2793309.mvXUDI8C0e@rjwysocki.net Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 73 ++++++++++++++++++------------------ drivers/base/power/main.c | 2 +- drivers/base/power/runtime.c | 6 +-- include/linux/device.h | 5 +++ 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index cbc0099d8ef2..3809baed42f3 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -460,9 +460,9 @@ static ssize_t auto_remove_on_show(struct device *dev, struct device_link *link = to_devlink(dev); const char *output; - if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) + if (device_link_test(link, DL_FLAG_AUTOREMOVE_SUPPLIER)) output = "supplier unbind"; - else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) + else if (device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER)) output = "consumer unbind"; else output = "never"; @@ -476,7 +476,7 @@ static ssize_t runtime_pm_show(struct device *dev, { struct device_link *link = to_devlink(dev); - return sysfs_emit(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME)); + return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_PM_RUNTIME)); } static DEVICE_ATTR_RO(runtime_pm); @@ -485,8 +485,7 @@ static ssize_t sync_state_only_show(struct device *dev, { struct device_link *link = to_devlink(dev); - return sysfs_emit(buf, "%d\n", - !!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); + return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); } static DEVICE_ATTR_RO(sync_state_only); @@ -792,12 +791,12 @@ struct device_link *device_link_add(struct device *consumer, if (link->consumer != consumer) continue; - if (link->flags & DL_FLAG_INFERRED && + if (device_link_test(link, DL_FLAG_INFERRED) && !(flags & DL_FLAG_INFERRED)) link->flags &= ~DL_FLAG_INFERRED; if (flags & DL_FLAG_PM_RUNTIME) { - if (!(link->flags & DL_FLAG_PM_RUNTIME)) { + if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) { pm_runtime_new_link(consumer); link->flags |= DL_FLAG_PM_RUNTIME; } @@ -807,8 +806,8 @@ struct device_link *device_link_add(struct device *consumer, if (flags & DL_FLAG_STATELESS) { kref_get(&link->kref); - if (link->flags & DL_FLAG_SYNC_STATE_ONLY && - !(link->flags & DL_FLAG_STATELESS)) { + if (device_link_test(link, DL_FLAG_SYNC_STATE_ONLY) && + !device_link_test(link, DL_FLAG_STATELESS)) { link->flags |= DL_FLAG_STATELESS; goto reorder; } else { @@ -823,7 +822,7 @@ struct device_link *device_link_add(struct device *consumer, * update the existing link to stay around longer. */ if (flags & DL_FLAG_AUTOREMOVE_SUPPLIER) { - if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) { + if (device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER)) { link->flags &= ~DL_FLAG_AUTOREMOVE_CONSUMER; link->flags |= DL_FLAG_AUTOREMOVE_SUPPLIER; } @@ -831,12 +830,12 @@ struct device_link *device_link_add(struct device *consumer, link->flags &= ~(DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER); } - if (!(link->flags & DL_FLAG_MANAGED)) { + if (!device_link_test(link, DL_FLAG_MANAGED)) { kref_get(&link->kref); link->flags |= DL_FLAG_MANAGED; device_link_init_status(link, consumer, supplier); } - if (link->flags & DL_FLAG_SYNC_STATE_ONLY && + if (device_link_test(link, DL_FLAG_SYNC_STATE_ONLY) && !(flags & DL_FLAG_SYNC_STATE_ONLY)) { link->flags &= ~DL_FLAG_SYNC_STATE_ONLY; goto reorder; @@ -940,7 +939,7 @@ static void __device_link_del(struct kref *kref) static void device_link_put_kref(struct device_link *link) { - if (link->flags & DL_FLAG_STATELESS) + if (device_link_test(link, DL_FLAG_STATELESS)) kref_put(&link->kref, __device_link_del); else if (!device_is_registered(link->consumer)) __device_link_del(&link->kref); @@ -1004,7 +1003,7 @@ static void device_links_missing_supplier(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { - WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); + WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } } @@ -1072,14 +1071,14 @@ int device_links_check_suppliers(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.suppliers, c_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; if (link->status != DL_STATE_AVAILABLE && - !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) { + !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)) { if (dev_is_best_effort(dev) && - link->flags & DL_FLAG_INFERRED && + device_link_test(link, DL_FLAG_INFERRED) && !link->supplier->can_match) { ret = -EAGAIN; continue; @@ -1128,7 +1127,7 @@ static void __device_links_queue_sync_state(struct device *dev, return; list_for_each_entry(link, &dev->links.consumers, s_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; if (link->status != DL_STATE_ACTIVE) return; @@ -1268,7 +1267,7 @@ void device_links_force_bind(struct device *dev) device_links_write_lock(); list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; if (link->status != DL_STATE_AVAILABLE) { @@ -1329,7 +1328,7 @@ void device_links_driver_bound(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; /* @@ -1345,7 +1344,7 @@ void device_links_driver_bound(struct device *dev) WARN_ON(link->status != DL_STATE_DORMANT); WRITE_ONCE(link->status, DL_STATE_AVAILABLE); - if (link->flags & DL_FLAG_AUTOPROBE_CONSUMER) + if (device_link_test(link, DL_FLAG_AUTOPROBE_CONSUMER)) driver_deferred_probe_add(link->consumer); } @@ -1357,11 +1356,11 @@ void device_links_driver_bound(struct device *dev) list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) { struct device *supplier; - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; supplier = link->supplier; - if (link->flags & DL_FLAG_SYNC_STATE_ONLY) { + if (device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)) { /* * When DL_FLAG_SYNC_STATE_ONLY is set, it means no * other DL_MANAGED_LINK_FLAGS have been set. So, it's @@ -1369,7 +1368,7 @@ void device_links_driver_bound(struct device *dev) */ device_link_drop_managed(link); } else if (dev_is_best_effort(dev) && - link->flags & DL_FLAG_INFERRED && + device_link_test(link, DL_FLAG_INFERRED) && link->status != DL_STATE_CONSUMER_PROBE && !link->supplier->can_match) { /* @@ -1421,10 +1420,10 @@ static void __device_links_no_driver(struct device *dev) struct device_link *link, *ln; list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; - if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) { + if (device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER)) { device_link_drop_managed(link); continue; } @@ -1436,7 +1435,7 @@ static void __device_links_no_driver(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { - WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); + WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } } @@ -1461,7 +1460,7 @@ void device_links_no_driver(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; /* @@ -1498,10 +1497,10 @@ void device_links_driver_cleanup(struct device *dev) device_links_write_lock(); list_for_each_entry_safe(link, ln, &dev->links.consumers, s_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; - WARN_ON(link->flags & DL_FLAG_AUTOREMOVE_CONSUMER); + WARN_ON(device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER)); WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND); /* @@ -1510,7 +1509,7 @@ void device_links_driver_cleanup(struct device *dev) * has moved to DL_STATE_SUPPLIER_UNBIND. */ if (link->status == DL_STATE_SUPPLIER_UNBIND && - link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) + device_link_test(link, DL_FLAG_AUTOREMOVE_SUPPLIER)) device_link_drop_managed(link); WRITE_ONCE(link->status, DL_STATE_DORMANT); @@ -1544,7 +1543,7 @@ bool device_links_busy(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (!(link->flags & DL_FLAG_MANAGED)) + if (!device_link_test(link, DL_FLAG_MANAGED)) continue; if (link->status == DL_STATE_CONSUMER_PROBE @@ -1586,8 +1585,8 @@ void device_links_unbind_consumers(struct device *dev) list_for_each_entry(link, &dev->links.consumers, s_node) { enum device_link_state status; - if (!(link->flags & DL_FLAG_MANAGED) || - link->flags & DL_FLAG_SYNC_STATE_ONLY) + if (!device_link_test(link, DL_FLAG_MANAGED) || + device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)) continue; status = link->status; @@ -1743,7 +1742,7 @@ static void fw_devlink_parse_fwtree(struct fwnode_handle *fwnode) static void fw_devlink_relax_link(struct device_link *link) { - if (!(link->flags & DL_FLAG_INFERRED)) + if (!device_link_test(link, DL_FLAG_INFERRED)) return; if (device_link_flag_is_sync_state_only(link->flags)) @@ -1779,7 +1778,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) struct device_link *link = to_devlink(dev); struct device *sup = link->supplier; - if (!(link->flags & DL_FLAG_MANAGED) || + if (!device_link_test(link, DL_FLAG_MANAGED) || link->status == DL_STATE_ACTIVE || sup->state_synced || !dev_has_sync_state(sup)) return 0; @@ -2063,7 +2062,7 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle, * such due to a cycle. */ if (device_link_flag_is_sync_state_only(dev_link->flags) && - !(dev_link->flags & DL_FLAG_CYCLE)) + !device_link_test(dev_link, DL_FLAG_CYCLE)) continue; if (__fw_devlink_relax_cycles(con_handle, diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eebe699fdf4f..6c6f8ded6877 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1998,7 +1998,7 @@ static bool device_prepare_smart_suspend(struct device *dev) idx = device_links_read_lock(); list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) { - if (!(link->flags & DL_FLAG_PM_RUNTIME)) + if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) continue; if (!dev_pm_smart_suspend(link->supplier) && diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index c55a7c70bc1a..c67e7a6b8ed0 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -290,7 +290,7 @@ static int rpm_get_suppliers(struct device *dev) device_links_read_lock_held()) { int retval; - if (!(link->flags & DL_FLAG_PM_RUNTIME)) + if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) continue; retval = pm_runtime_get_sync(link->supplier); @@ -1879,7 +1879,7 @@ void pm_runtime_get_suppliers(struct device *dev) list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, device_links_read_lock_held()) - if (link->flags & DL_FLAG_PM_RUNTIME) { + if (device_link_test(link, DL_FLAG_PM_RUNTIME)) { link->supplier_preactivated = true; pm_runtime_get_sync(link->supplier); } @@ -1933,7 +1933,7 @@ static void pm_runtime_drop_link_count(struct device *dev) */ void pm_runtime_drop_link(struct device_link *link) { - if (!(link->flags & DL_FLAG_PM_RUNTIME)) + if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) return; pm_runtime_drop_link_count(link->consumer); diff --git a/include/linux/device.h b/include/linux/device.h index 4940db137fff..afdd4f7c0d94 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1162,6 +1162,11 @@ void device_links_supplier_sync_state_pause(void); void device_links_supplier_sync_state_resume(void); void device_link_wait_removal(void); +static inline bool device_link_test(const struct device_link *link, u32 flags) +{ + return !!(link->flags & flags); +} + /* Create alias, so I can be autoloaded. */ #define MODULE_ALIAS_CHARDEV(major,minor) \ MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) From c942dba38064cd35214c6b3249120f3f2945e810 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 16 Jun 2025 17:45:09 +0200 Subject: [PATCH 15/84] rust: device: Add child accessor and iterator Allow Rust drivers to access children of a fwnode either by name or by iterating over all of them. In C, there is the function `fwnode_get_next_child_node` for iteration and the macro `fwnode_for_each_child_node` that helps with handling the pointers. Instead of a macro, a native iterator is used in Rust such that regular for-loops can be used. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250616154511.1862909-2-remo@buenzli.dev Signed-off-by: Danilo Krummrich --- rust/kernel/device/property.rs | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 838509111e57..04a13d05785a 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -190,6 +190,62 @@ pub fn property_read<'fwnode, 'name, T: Property>( name, } } + + /// Returns first matching named child node handle. + pub fn get_child_by_name(&self, name: &CStr) -> Option> { + // SAFETY: `self` and `name` are valid by their type invariants. + let child = + unsafe { bindings::fwnode_get_named_child_node(self.as_raw(), name.as_char_ptr()) }; + if child.is_null() { + return None; + } + // SAFETY: + // - `fwnode_get_named_child_node` returns a pointer with its refcount + // incremented. + // - That increment is relinquished, i.e. the underlying object is not + // used anymore except via the newly created `ARef`. + Some(unsafe { Self::from_raw(child) }) + } + + /// Returns an iterator over a node's children. + pub fn children<'a>(&'a self) -> impl Iterator> + 'a { + let mut prev: Option> = None; + + core::iter::from_fn(move || { + let prev_ptr = match prev.take() { + None => ptr::null_mut(), + Some(prev) => { + // We will pass `prev` to `fwnode_get_next_child_node`, + // which decrements its refcount, so we use + // `ARef::into_raw` to avoid decrementing the refcount + // twice. + let prev = ARef::into_raw(prev); + prev.as_ptr().cast() + } + }; + // SAFETY: + // - `self.as_raw()` is valid by its type invariant. + // - `prev_ptr` may be null, which is allowed and corresponds to + // getting the first child. Otherwise, `prev_ptr` is valid, as it + // is the stored return value from the previous invocation. + // - `prev_ptr` has its refount incremented. + // - The increment of `prev_ptr` is relinquished, i.e. the + // underlying object won't be used anymore. + let next = unsafe { bindings::fwnode_get_next_child_node(self.as_raw(), prev_ptr) }; + if next.is_null() { + return None; + } + // SAFETY: + // - `next` is valid because `fwnode_get_next_child_node` returns a + // pointer with its refcount incremented. + // - That increment is relinquished, i.e. the underlying object + // won't be used anymore, except via the newly created + // `ARef`. + let next = unsafe { FwNode::from_raw(next) }; + prev = Some(next.clone()); + Some(next) + }) + } } // SAFETY: Instances of `FwNode` are always reference-counted. From c3e05bd15e0c99f3ff45e0b1f01814778bc1128c Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 16 Jun 2025 17:45:10 +0200 Subject: [PATCH 16/84] rust: device: Add property_get_reference_args Allow Rust code to read reference args from device properties. The wrapper type `FwNodeReferenceArgs` allows callers to access the buffer of read args safely. Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250616154511.1862909-3-remo@buenzli.dev [ Move up NArgs; refer to FwNodeReferenceArgs in NArgs doc-comment. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device/property.rs | 102 +++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 04a13d05785a..2f6f3ef17db7 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -246,6 +246,108 @@ pub fn children<'a>(&'a self) -> impl Iterator> + 'a { Some(next) }) } + + /// Finds a reference with arguments. + pub fn property_get_reference_args( + &self, + prop: &CStr, + nargs: NArgs<'_>, + index: u32, + ) -> Result { + let mut out_args = FwNodeReferenceArgs::default(); + + let (nargs_prop, nargs) = match nargs { + NArgs::Prop(nargs_prop) => (nargs_prop.as_char_ptr(), 0), + NArgs::N(nargs) => (ptr::null(), nargs), + }; + + // SAFETY: + // - `self.0.get()` is valid. + // - `prop.as_char_ptr()` is valid and zero-terminated. + // - `nargs_prop` is valid and zero-terminated if `nargs` + // is zero, otherwise it is allowed to be a null-pointer. + // - The function upholds the type invariants of `out_args`, + // namely: + // - It may fill the field `fwnode` with a valid pointer, + // in which case its refcount is incremented. + // - It may modify the field `nargs`, in which case it + // initializes at least as many elements in `args`. + let ret = unsafe { + bindings::fwnode_property_get_reference_args( + self.0.get(), + prop.as_char_ptr(), + nargs_prop, + nargs, + index, + &mut out_args.0, + ) + }; + to_result(ret)?; + + Ok(out_args) + } +} + +/// The number of arguments to request [`FwNodeReferenceArgs`]. +pub enum NArgs<'a> { + /// The name of the property of the reference indicating the number of + /// arguments. + Prop(&'a CStr), + /// The known number of arguments. + N(u32), +} + +/// The return value of [`FwNode::property_get_reference_args`]. +/// +/// This structure represents the Rust abstraction for a C +/// `struct fwnode_reference_args` which was initialized by the C side. +/// +/// # Invariants +/// +/// If the field `fwnode` is valid, it owns an increment of its refcount. +/// +/// The field `args` contains at least as many initialized elements as indicated +/// by the field `nargs`. +#[repr(transparent)] +#[derive(Default)] +pub struct FwNodeReferenceArgs(bindings::fwnode_reference_args); + +impl Drop for FwNodeReferenceArgs { + fn drop(&mut self) { + if !self.0.fwnode.is_null() { + // SAFETY: + // - By the type invariants of `FwNodeReferenceArgs`, its field + // `fwnode` owns an increment of its refcount. + // - That increment is relinquished. The underlying object won't be + // used anymore because we are dropping it. + let _ = unsafe { FwNode::from_raw(self.0.fwnode) }; + } + } +} + +impl FwNodeReferenceArgs { + /// Returns the slice of reference arguments. + pub fn as_slice(&self) -> &[u64] { + // SAFETY: As per the safety invariant of `FwNodeReferenceArgs`, `nargs` + // is the minimum number of elements in `args` that is valid. + unsafe { core::slice::from_raw_parts(self.0.args.as_ptr(), self.0.nargs as usize) } + } + + /// Returns the number of reference arguments. + pub fn len(&self) -> usize { + self.0.nargs as usize + } + + /// Returns `true` if there are no reference arguments. + pub fn is_empty(&self) -> bool { + self.0.nargs == 0 + } +} + +impl core::fmt::Debug for FwNodeReferenceArgs { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.as_slice()) + } } // SAFETY: Instances of `FwNode` are always reference-counted. From c79cbde9b7bc7a650af96269588518950e3c2441 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 16 Jun 2025 17:45:11 +0200 Subject: [PATCH 17/84] samples: rust: platform: Add property child and reference args examples Add some example usage of the device property methods for reading DT/ACPI/swnode child nodes and reference args. Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250616154511.1862909-4-remo@buenzli.dev [ Convert 'child@{0,1}' to 'child-{0,1}'; skip child nodes without 'compatible' property in of_unittest_platform_populate() as proposed by Rob Herring. - Danilo] Signed-off-by: Danilo Krummrich --- drivers/of/unittest-data/tests-platform.dtsi | 7 +++++++ drivers/of/unittest.c | 2 ++ samples/rust/rust_driver_platform.rs | 13 ++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/of/unittest-data/tests-platform.dtsi b/drivers/of/unittest-data/tests-platform.dtsi index 50a51f38afb6..59aa2a9731a7 100644 --- a/drivers/of/unittest-data/tests-platform.dtsi +++ b/drivers/of/unittest-data/tests-platform.dtsi @@ -40,6 +40,13 @@ test-device@2 { test,u32-prop = <0xdeadbeef>; test,i16-array = /bits/ 16 <1 2 (-3) (-4)>; + + ref_child_0: child-0 { + test,ref-arg = <&ref_child_1 0x20 0x32>; + }; + ref_child_1: child-1 { + test,ref-arg = <&ref_child_0 0x10 0x64>; + }; }; }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index eeb370e0f507..e3503ec20f6c 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1856,6 +1856,8 @@ static void __init of_unittest_platform_populate(void) of_platform_populate(np, match, NULL, &test_bus->dev); for_each_child_of_node(np, child) { for_each_child_of_node(child, grandchild) { + if (!of_property_present(grandchild, "compatible")) + continue; pdev = of_find_device_by_node(grandchild); unittest(pdev, "Could not create device for node '%pOFn'\n", diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index c0abf78d0683..4dcedb22a4bb 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -4,7 +4,11 @@ use kernel::{ c_str, - device::{self, Core}, + device::{ + self, + property::{FwNodeReferenceArgs, NArgs}, + Core, + }, of, platform, prelude::*, str::CString, @@ -91,6 +95,13 @@ fn properties_parse(dev: &device::Device) -> Result { let prop: KVec = fwnode.property_read_array_vec(name, 4)?.required_by(dev)?; dev_info!(dev, "'{name}'='{prop:?}' (KVec)\n"); + for child in fwnode.children() { + let name = c_str!("test,ref-arg"); + let nargs = NArgs::N(2); + let prop: FwNodeReferenceArgs = child.property_get_reference_args(name, nargs, 0)?; + dev_info!(dev, "'{name}'='{prop:?}'\n"); + } + Ok(()) } } From 56a789f776f24e6b132ec00d4c27672ed4e2ec57 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 20 Jun 2025 16:15:04 +0100 Subject: [PATCH 18/84] rust: device: implement FwNode::is_of_node() Implement FwNode::is_of_node() in order to check whether a FwNode instance is embedded in a struct device_node. Reviewed-by: Rob Herring (Arm) Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620151504.278766-1-igor.korotin.linux@gmail.com Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + rust/helpers/helpers.c | 1 + rust/helpers/of.c | 8 ++++++++ rust/kernel/device/property.rs | 7 +++++++ 4 files changed, 17 insertions(+) create mode 100644 rust/helpers/of.c diff --git a/MAINTAINERS b/MAINTAINERS index 68d2a32759ec..ac68531befed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18580,6 +18580,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git F: Documentation/ABI/testing/sysfs-firmware-ofw F: drivers/of/ F: include/linux/of*.h +F: rust/helpers/of.c F: rust/kernel/of.rs F: scripts/dtc/ F: tools/testing/selftests/dt/ diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 393ad201befb..0b09bd0e3561 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -28,6 +28,7 @@ #include "kunit.c" #include "mm.c" #include "mutex.c" +#include "of.c" #include "page.c" #include "platform.c" #include "pci.c" diff --git a/rust/helpers/of.c b/rust/helpers/of.c new file mode 100644 index 000000000000..86b51167c913 --- /dev/null +++ b/rust/helpers/of.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +bool rust_helper_is_of_node(const struct fwnode_handle *fwnode) +{ + return is_of_node(fwnode); +} diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 2f6f3ef17db7..49ee12a906db 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -61,6 +61,13 @@ pub(crate) fn as_raw(&self) -> *mut bindings::fwnode_handle { self.0.get() } + /// Returns `true` if `&self` is an OF node, `false` otherwise. + pub fn is_of_node(&self) -> bool { + // SAFETY: The type invariant of `Self` guarantees that `self.as_raw() is a pointer to a + // valid `struct fwnode_handle`. + unsafe { bindings::is_of_node(self.as_raw()) } + } + /// Returns an object that implements [`Display`](core::fmt::Display) for /// printing the name of a node. /// From c69072d3a10976e48da97758a78c35305c24eeba Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 20 Jun 2025 16:18:49 +0100 Subject: [PATCH 19/84] samples: rust: platform: don't call as_ref() repeatedly In SampleDriver::probe() don't call pdev.as_ref() repeatedly, instead introduce a dedicated &Device. Signed-off-by: Igor Korotin Reviewed-by: Dirk Behme Link: https://lore.kernel.org/r/20250620151849.281238-1-igor.korotin.linux@gmail.com Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_platform.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 4dcedb22a4bb..db2edcd49a48 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -36,13 +36,15 @@ fn probe( pdev: &platform::Device, info: Option<&Self::IdInfo>, ) -> Result>> { - dev_dbg!(pdev.as_ref(), "Probe Rust Platform driver sample.\n"); + let dev = pdev.as_ref(); + + dev_dbg!(dev, "Probe Rust Platform driver sample.\n"); if let Some(info) = info { - dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0); + dev_info!(dev, "Probed with info: '{}'.\n", info.0); } - Self::properties_parse(pdev.as_ref())?; + Self::properties_parse(dev)?; let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?; From 9da36b9faed26f634c9f04a0f2cf7625c08f5d65 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 20 Jun 2025 16:21:03 +0100 Subject: [PATCH 20/84] samples: rust: platform: conditionally call Self::properties_parse() Only call Self::properties_parse() when the FwNode is an OF node. Once we add ACPI support, we don't want the ACPI device to fail probing in Self::properties_parse(). Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620152103.282763-1-igor.korotin.linux@gmail.com Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_platform.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index db2edcd49a48..73f8673a987e 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -44,7 +44,9 @@ fn probe( dev_info!(dev, "Probed with info: '{}'.\n", info.0); } - Self::properties_parse(dev)?; + if dev.fwnode().is_some_and(|node| node.is_of_node()) { + Self::properties_parse(dev)?; + } let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?; From a74931eb59cf6b914e1b9471d9abd4429176f6af Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:24:25 +0100 Subject: [PATCH 21/84] rust: acpi: add `acpi::DeviceId` abstraction `acpi::DeviceId` is an abstraction around `struct acpi_device_id`. Enable drivers to build ACPI device ID tables, to be consumed by the corresponding bus abstractions, such as platform or I2C. Signed-off-by: Igor Korotin Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20250620152425.285683-1-igor.korotin.linux@gmail.com [ Always inline DeviceId::new() and use &'static CStr; slightly reword commit message. - Danilo ] Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + rust/kernel/acpi.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 67 insertions(+) create mode 100644 rust/kernel/acpi.rs diff --git a/MAINTAINERS b/MAINTAINERS index ac68531befed..7f8ddeec3b17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -302,6 +302,7 @@ F: include/linux/acpi.h F: include/linux/fwnode.h F: include/linux/fw_table.h F: lib/fw_table.c +F: rust/kernel/acpi.rs F: tools/power/acpi/ ACPI APEI diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs new file mode 100644 index 000000000000..eaae3bc8e54c --- /dev/null +++ b/rust/kernel/acpi.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Advanced Configuration and Power Interface abstractions. + +use crate::{bindings, device_id::RawDeviceId, prelude::*}; + +/// IdTable type for ACPI drivers. +pub type IdTable = &'static dyn kernel::device_id::IdTable; + +/// An ACPI device id. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::acpi_device_id); + +// SAFETY: +// * `DeviceId` is a `#[repr(transparent)` wrapper of `struct acpi_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. +// * `DRIVER_DATA_OFFSET` is the offset to the `data` field. +unsafe impl RawDeviceId for DeviceId { + type RawType = bindings::acpi_device_id; + + const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::acpi_device_id, driver_data); + + fn index(&self) -> usize { + self.0.driver_data as _ + } +} + +impl DeviceId { + const ACPI_ID_LEN: usize = 16; + + /// Create a new device id from an ACPI 'id' string. + #[inline(always)] + pub const fn new(id: &'static CStr) -> Self { + build_assert!( + id.len_with_nul() <= Self::ACPI_ID_LEN, + "ID exceeds 16 bytes" + ); + let src = id.as_bytes_with_nul(); + // Replace with `bindings::acpi_device_id::default()` once stabilized for `const`. + // SAFETY: FFI type is valid to be zero-initialized. + let mut acpi: bindings::acpi_device_id = unsafe { core::mem::zeroed() }; + let mut i = 0; + while i < src.len() { + acpi.id[i] = src[i]; + i += 1; + } + + Self(acpi) + } +} + +/// Create an ACPI `IdTable` with an "alias" for modpost. +#[macro_export] +macro_rules! acpi_device_table { + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { + const $table_name: $crate::device_id::IdArray< + $crate::acpi::DeviceId, + $id_info_type, + { $table_data.len() }, + > = $crate::device_id::IdArray::new($table_data); + + $crate::module_device_table!("acpi", $module_table_name, $table_name); + }; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 6b4774b2b1c3..5bbf3627212f 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -51,6 +51,7 @@ pub use ffi; +pub mod acpi; pub mod alloc; #[cfg(CONFIG_AUXILIARY_BUS)] pub mod auxiliary; From 0f549d25858dfef9decd0b99a82ff4bc9095a51f Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:36:56 +0100 Subject: [PATCH 22/84] rust: driver: Consolidate `Adapter::of_id_info` methods using `#[cfg]` Refactor the `of_id_info` methods in the `Adapter` trait to reduce duplication. Previously, the method had two versions selected via `#[cfg(...)]` and `#[cfg(not(...))]`. This change merges them into a single method by using `#[cfg]` blocks within the method body. Suggested-by: Benno Lossin Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620153656.294468-1-igor.korotin.linux@gmail.com [ Fix clippy warning if #[cfg(not(CONFIG_OF))]; fix checkpatch.pl line length warnings. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/driver.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index ec9166cedfa7..b072b88e7cc1 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -147,30 +147,32 @@ pub trait Adapter { /// Returns the driver's private data from the matching entry in the [`of::IdTable`], if any. /// /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`]. - #[cfg(CONFIG_OF)] fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { - let table = Self::of_id_table()?; - - // SAFETY: - // - `table` has static lifetime, hence it's valid for read, - // - `dev` is guaranteed to be valid while it's alive, and so is `pdev.as_ref().as_raw()`. - let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) }; - - if raw_id.is_null() { + #[cfg(not(CONFIG_OF))] + { + let _ = dev; None - } else { - // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` and - // does not add additional invariants, so it's safe to transmute. - let id = unsafe { &*raw_id.cast::() }; - - Some(table.info(::index(id))) } - } - #[cfg(not(CONFIG_OF))] - #[allow(missing_docs)] - fn of_id_info(_dev: &device::Device) -> Option<&'static Self::IdInfo> { - None + #[cfg(CONFIG_OF)] + { + let table = Self::of_id_table()?; + + // SAFETY: + // - `table` has static lifetime, hence it's valid for read, + // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. + let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) }; + + if raw_id.is_null() { + None + } else { + // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` + // and does not add additional invariants, so it's safe to transmute. + let id = unsafe { &*raw_id.cast::() }; + + Some(table.info(::index(id))) + } + } } /// Returns the driver's private data from the matching entry of any of the ID tables, if any. From 7a5cb145a9ce844be41ca5ed26e7d8d7c41dec7d Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:39:13 +0100 Subject: [PATCH 23/84] rust: driver: Add ACPI id table support to Adapter trait Extend the `Adapter` trait to support ACPI device identification. This mirrors the existing Open Firmware (OF) support (`of_id_table`) and enables Rust drivers to match and retrieve ACPI-specific device data when `CONFIG_ACPI` is enabled. To avoid breaking compilation, a stub implementation of `acpi_id_table()` is added to the Platform adapter; the full implementation will be provided in a subsequent patch. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620153914.295679-1-igor.korotin.linux@gmail.com [ Fix clippy warning if #[cfg(not(CONFIG_OF))]; fix checkpatch.pl line length warnings. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 1 + rust/kernel/driver.rs | 41 ++++++++++++++++++++++++++++++++- rust/kernel/platform.rs | 6 ++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 8cbb660e2ec2..7e8f22850647 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -28,6 +28,7 @@ */ #include +#include #include #include #include diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index b072b88e7cc1..a4bf4498e592 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -6,7 +6,7 @@ //! register using the [`Registration`] class. use crate::error::{Error, Result}; -use crate::{device, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; +use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; use core::pin::Pin; use pin_init::{pin_data, pinned_drop, PinInit}; @@ -141,6 +141,40 @@ pub trait Adapter { /// The type holding driver private data about each device id supported by the driver. type IdInfo: 'static; + /// The [`acpi::IdTable`] of the corresponding driver + fn acpi_id_table() -> Option>; + + /// Returns the driver's private data from the matching entry in the [`acpi::IdTable`], if any. + /// + /// If this returns `None`, it means there is no match with an entry in the [`acpi::IdTable`]. + fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { + #[cfg(not(CONFIG_ACPI))] + { + let _ = dev; + None + } + + #[cfg(CONFIG_ACPI)] + { + let table = Self::acpi_id_table()?; + + // SAFETY: + // - `table` has static lifetime, hence it's valid for read, + // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. + let raw_id = unsafe { bindings::acpi_match_device(table.as_ptr(), dev.as_raw()) }; + + if raw_id.is_null() { + None + } else { + // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct acpi_device_id` + // and does not add additional invariants, so it's safe to transmute. + let id = unsafe { &*raw_id.cast::() }; + + Some(table.info(::index(id))) + } + } + } + /// The [`of::IdTable`] of the corresponding driver. fn of_id_table() -> Option>; @@ -180,6 +214,11 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { /// If this returns `None`, it means that there is no match in any of the ID tables directly /// associated with a [`device::Device`]. fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { + let id = Self::acpi_id_info(dev); + if id.is_some() { + return id; + } + let id = Self::of_id_info(dev); if id.is_some() { return id; diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 5b21fa517e55..5923d29a0511 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -5,7 +5,7 @@ //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) use crate::{ - bindings, container_of, device, driver, + acpi, bindings, container_of, device, driver, error::{to_result, Result}, of, prelude::*, @@ -94,6 +94,10 @@ impl driver::Adapter for Adapter { fn of_id_table() -> Option> { T::OF_ID_TABLE } + + fn acpi_id_table() -> Option> { + None + } } /// Declares a kernel module that exposes a single platform driver. From ec3ef2175e16360605c7e1b409ceaa77be6521a8 Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:41:24 +0100 Subject: [PATCH 24/84] rust: platform: Set `OF_ID_TABLE` default to `None` in `Driver` trait Provide a default value of `None` for `Driver::OF_ID_TABLE` to simplify driver implementations. Drivers that do not require OpenFirmware matching no longer need to import the `of` module or define the constant explicitly. This reduces unnecessary boilerplate and avoids pulling in unused dependencies. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620154124.297158-1-igor.korotin.linux@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 5923d29a0511..2436f55b579b 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -162,7 +162,7 @@ pub trait Driver: Send { type IdInfo: 'static; /// The table of OF device ids supported by the driver. - const OF_ID_TABLE: Option>; + const OF_ID_TABLE: Option> = None; /// Platform driver probe. /// From 8411e6f06a022679a642c236724944057b90e60e Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:43:34 +0100 Subject: [PATCH 25/84] rust: platform: Add ACPI match table support to `Driver` trait Extend the `platform::Driver` trait to support ACPI device matching by adding the `ACPI_ID_TABLE` constant. This allows Rust platform drivers to define ACPI match tables alongside their existing OF match tables. These changes mirror the existing OF support and allow Rust platform drivers to match devices based on ACPI identifiers. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620154334.298320-1-igor.korotin.linux@gmail.com [ Use 'LNUXBEEF' as ACPI ID. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 2436f55b579b..86f9d73c64b3 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -37,12 +37,18 @@ unsafe fn register( None => core::ptr::null(), }; + let acpi_table = match T::ACPI_ID_TABLE { + Some(table) => table.as_ptr(), + None => core::ptr::null(), + }; + // SAFETY: It's safe to set the fields of `struct platform_driver` on initialization. unsafe { (*pdrv.get()).driver.name = name.as_char_ptr(); (*pdrv.get()).probe = Some(Self::probe_callback); (*pdrv.get()).remove = Some(Self::remove_callback); (*pdrv.get()).driver.of_match_table = of_table; + (*pdrv.get()).driver.acpi_match_table = acpi_table; } // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. @@ -96,7 +102,7 @@ fn of_id_table() -> Option> { } fn acpi_id_table() -> Option> { - None + T::ACPI_ID_TABLE } } @@ -127,7 +133,7 @@ macro_rules! module_platform_driver { /// # Example /// ///``` -/// # use kernel::{bindings, c_str, device::Core, of, platform}; +/// # use kernel::{acpi, bindings, c_str, device::Core, of, platform}; /// /// struct MyDriver; /// @@ -140,9 +146,19 @@ macro_rules! module_platform_driver { /// ] /// ); /// +/// kernel::acpi_device_table!( +/// ACPI_TABLE, +/// MODULE_ACPI_TABLE, +/// ::IdInfo, +/// [ +/// (acpi::DeviceId::new(c_str!("LNUXBEEF")), ()) +/// ] +/// ); +/// /// impl platform::Driver for MyDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option> = Some(&OF_TABLE); +/// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// /// fn probe( /// _pdev: &platform::Device, @@ -164,6 +180,9 @@ pub trait Driver: Send { /// The table of OF device ids supported by the driver. const OF_ID_TABLE: Option> = None; + /// The table of ACPI device ids supported by the driver. + const ACPI_ID_TABLE: Option> = None; + /// Platform driver probe. /// /// Called when a new platform device is added or discovered. From 140a9d0437b2a0d82e05b33973d9fc42c1d1c2ea Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:45:52 +0100 Subject: [PATCH 26/84] samples: rust: add ACPI match table example to platform driver Extend the Rust sample platform driver to probe using device/driver name matching, OF ID table matching, or ACPI ID table matching. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620154552.299932-1-igor.korotin.linux@gmail.com [ Use 'LNUXBEEF' as ACPI ID. - Danilo ] Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_platform.rs | 70 +++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 73f8673a987e..69ed55b7b0fa 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -2,8 +2,68 @@ //! Rust Platform driver sample. +//! ACPI match table test +//! +//! This demonstrates how to test an ACPI-based Rust platform driver using QEMU +//! with a custom SSDT. +//! +//! Steps: +//! +//! 1. **Create an SSDT source file** (`ssdt.dsl`) with the following content: +//! +//! ```asl +//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001) +//! { +//! Scope (\_SB) +//! { +//! Device (T432) +//! { +//! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match +//! Name (_UID, 1) +//! Name (_STA, 0x0F) // Device present, enabled +//! Name (_CRS, ResourceTemplate () +//! { +//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000) +//! }) +//! } +//! } +//! } +//! ``` +//! +//! 2. **Compile the table**: +//! +//! ```sh +//! iasl -tc ssdt.dsl +//! ``` +//! +//! This generates `ssdt.aml` +//! +//! 3. **Run QEMU** with the compiled AML file: +//! +//! ```sh +//! qemu-system-x86_64 -m 512M \ +//! -enable-kvm \ +//! -kernel path/to/bzImage \ +//! -append "root=/dev/sda console=ttyS0" \ +//! -hda rootfs.img \ +//! -serial stdio \ +//! -acpitable file=ssdt.aml +//! ``` +//! +//! Requirements: +//! - The `rust_driver_platform` must be present either: +//! - built directly into the kernel (`bzImage`), or +//! - available as a `.ko` file and loadable from `rootfs.img` +//! +//! 4. **Verify it worked** by checking `dmesg`: +//! +//! ``` +//! rust_driver_platform LNUXBEEF:00: Probed with info: '0'. +//! ``` +//! + use kernel::{ - c_str, + acpi, c_str, device::{ self, property::{FwNodeReferenceArgs, NArgs}, @@ -28,9 +88,17 @@ struct SampleDriver { [(of::DeviceId::new(c_str!("test,rust-device")), Info(42))] ); +kernel::acpi_device_table!( + ACPI_TABLE, + MODULE_ACPI_TABLE, + ::IdInfo, + [(acpi::DeviceId::new(c_str!("LNUXBEEF")), Info(0))] +); + impl platform::Driver for SampleDriver { type IdInfo = Info; const OF_ID_TABLE: Option> = Some(&OF_TABLE); + const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); fn probe( pdev: &platform::Device, From 0dab138d0f4c0b3ce7f835d577e52a2b5ebdd536 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 26 Jun 2025 15:24:46 +0200 Subject: [PATCH 27/84] rust: devres: require T: Send for Devres Due to calling Revocable::revoke() from Devres::devres_callback() T may be dropped from Devres::devres_callback() and hence must be Send. Fix this by adding the corresponding bound to Devres and DevresInner. Reported-by: Boqun Feng Closes: https://lore.kernel.org/lkml/aFzI5L__OcB9hqdG@Mac.home/ Fixes: 76c01ded724b ("rust: add devres abstraction") Reviewed-by: Boqun Feng Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250626132544.72866-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 57502534d985..8ede607414fd 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -18,7 +18,7 @@ }; #[pin_data] -struct DevresInner { +struct DevresInner { dev: ARef, callback: unsafe extern "C" fn(*mut c_void), #[pin] @@ -95,9 +95,9 @@ struct DevresInner { /// # Ok(()) /// # } /// ``` -pub struct Devres(Arc>); +pub struct Devres(Arc>); -impl DevresInner { +impl DevresInner { fn new(dev: &Device, data: T, flags: Flags) -> Result>> { let inner = Arc::pin_init( pin_init!( DevresInner { @@ -175,7 +175,7 @@ fn remove_action(this: &Arc) -> bool { } } -impl Devres { +impl Devres { /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the /// returned `Devres` instance' `data` will be revoked once the device is detached. pub fn new(dev: &Device, data: T, flags: Flags) -> Result { @@ -247,7 +247,7 @@ pub fn try_access_with_guard<'a>(&'a self, guard: &'a rcu::Guard) -> Option<&'a } } -impl Drop for Devres { +impl Drop for Devres { fn drop(&mut self) { // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data // anymore, hence it is safe not to wait for the grace period to finish. From 64888dfdfac7f7d2013a9734755c11322ff6eaa5 Mon Sep 17 00:00:00 2001 From: Christian Schrefl Date: Tue, 10 Jun 2025 22:27:55 +0200 Subject: [PATCH 28/84] rust: implement `Wrapper` for `Opaque` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves the implementation for `pin-init` from an associated function to the trait function of the `Wrapper` trait and extends the implementation to support pin-initializers with error types. Adds a use for the `Wrapper` trait in `revocable.rs`, to use the new `pin-init` function. This is currently the only usage in the kernel. Reviewed-by: Gerald Wisböck Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Acked-by: Miguel Ojeda Signed-off-by: Christian Schrefl Link: https://lore.kernel.org/r/20250610-b4-rust_miscdevice_registrationdata-v6-1-b03f5dfce998@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/revocable.rs | 2 ++ rust/kernel/types.rs | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs index 06a3cdfce344..fa1fd70efa27 100644 --- a/rust/kernel/revocable.rs +++ b/rust/kernel/revocable.rs @@ -5,6 +5,8 @@ //! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence //! of a [`RevocableGuard`] ensures that objects remain valid. +use pin_init::Wrapper; + use crate::{bindings, prelude::*, sync::rcu, types::Opaque}; use core::{ marker::PhantomData, diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 22985b6f6982..3958a5f44d56 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -9,7 +9,7 @@ ops::{Deref, DerefMut}, ptr::NonNull, }; -use pin_init::{PinInit, Zeroable}; +use pin_init::{PinInit, Wrapper, Zeroable}; /// Used to transfer ownership to and from foreign (non-Rust) languages. /// @@ -353,17 +353,6 @@ pub const fn zeroed() -> Self { } } - /// Create an opaque pin-initializer from the given pin-initializer. - pub fn pin_init(slot: impl PinInit) -> impl PinInit { - Self::ffi_init(|ptr: *mut T| { - // SAFETY: - // - `ptr` is a valid pointer to uninitialized memory, - // - `slot` is not accessed on error; the call is infallible, - // - `slot` is pinned in memory. - let _ = unsafe { PinInit::::__pinned_init(slot, ptr) }; - }) - } - /// Creates a pin-initializer from the given initializer closure. /// /// The returned initializer calls the given closure with the pointer to the inner `T` of this @@ -415,6 +404,19 @@ pub const fn raw_get(this: *const Self) -> *mut T { } } +impl Wrapper for Opaque { + /// Create an opaque pin-initializer from the given pin-initializer. + fn pin_init(slot: impl PinInit) -> impl PinInit { + Self::try_ffi_init(|ptr: *mut T| { + // SAFETY: + // - `ptr` is a valid pointer to uninitialized memory, + // - `slot` is not accessed on error, + // - `slot` is pinned in memory. + unsafe { PinInit::::__pinned_init(slot, ptr) } + }) + } +} + /// Types that are _always_ reference counted. /// /// It allows such types to define their own custom ref increment and decrement functions. From ce7c22b2e1fb1db467d33bd050546941ce82f21f Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 26 Jun 2025 22:00:39 +0200 Subject: [PATCH 29/84] rust: revocable: support fallible PinInit types Currently, Revocable::new() only supports infallible PinInit implementations, i.e. impl PinInit. This has been sufficient so far, since users such as Devres do not support fallibility. Since this is about to change, make Revocable::new() generic over the error type E. Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Acked-by: Miguel Ojeda Link: https://lore.kernel.org/r/20250626200054.243480-2-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 2 +- rust/kernel/revocable.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 8ede607414fd..fd8b75aa03bc 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -100,7 +100,7 @@ struct DevresInner { impl DevresInner { fn new(dev: &Device, data: T, flags: Flags) -> Result>> { let inner = Arc::pin_init( - pin_init!( DevresInner { + try_pin_init!( DevresInner { dev: dev.into(), callback: Self::devres_callback, data <- Revocable::new(data), diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs index fa1fd70efa27..46768b374656 100644 --- a/rust/kernel/revocable.rs +++ b/rust/kernel/revocable.rs @@ -82,11 +82,11 @@ unsafe impl Sync for Revocable {} impl Revocable { /// Creates a new revocable instance of the given data. - pub fn new(data: impl PinInit) -> impl PinInit { - pin_init!(Self { + pub fn new(data: impl PinInit) -> impl PinInit { + try_pin_init!(Self { is_available: AtomicBool::new(true), data <- Opaque::pin_init(data), - }) + }? E) } /// Tries to access the revocable wrapped object. From 46ae8fd7386abf809355d1857abac5cf2d7c3f62 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 26 Jun 2025 22:00:40 +0200 Subject: [PATCH 30/84] rust: devres: replace Devres::new_foreign_owned() Replace Devres::new_foreign_owned() with devres::register(). The current implementation of Devres::new_foreign_owned() creates a full Devres container instance, including the internal Revocable and completion. However, none of that is necessary for the intended use of giving full ownership of an object to devres and getting it dropped once the given device is unbound. Hence, implement devres::register(), which is limited to consume the given data, wrap it in a KBox and drop the KBox once the given device is unbound, without any other synchronization. Cc: Dave Airlie Cc: Simona Vetter Cc: Viresh Kumar Acked-by: Viresh Kumar Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250626200054.243480-3-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/helpers/device.c | 7 ++++ rust/kernel/cpufreq.rs | 11 +++--- rust/kernel/devres.rs | 73 +++++++++++++++++++++++++++++++++------ rust/kernel/drm/driver.rs | 14 ++++---- 4 files changed, 85 insertions(+), 20 deletions(-) diff --git a/rust/helpers/device.c b/rust/helpers/device.c index b2135c6686b0..502fef7e9ae8 100644 --- a/rust/helpers/device.c +++ b/rust/helpers/device.c @@ -8,3 +8,10 @@ int rust_helper_devm_add_action(struct device *dev, { return devm_add_action(dev, action, data); } + +int rust_helper_devm_add_action_or_reset(struct device *dev, + void (*action)(void *), + void *data) +{ + return devm_add_action_or_reset(dev, action, data); +} diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 11b03e9d7e89..dd84e2b4d7ae 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -13,7 +13,7 @@ cpu::CpuId, cpumask, device::{Bound, Device}, - devres::Devres, + devres, error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR}, ffi::{c_char, c_ulong}, prelude::*, @@ -1046,10 +1046,13 @@ pub fn new() -> Result { /// Same as [`Registration::new`], but does not return a [`Registration`] instance. /// - /// Instead the [`Registration`] is owned by [`Devres`] and will be revoked / dropped, once the + /// Instead the [`Registration`] is owned by [`devres::register`] and will be dropped, once the /// device is detached. - pub fn new_foreign_owned(dev: &Device) -> Result { - Devres::new_foreign_owned(dev, Self::new()?, GFP_KERNEL) + pub fn new_foreign_owned(dev: &Device) -> Result + where + T: 'static, + { + devres::register(dev, Self::new()?, GFP_KERNEL) } } diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index fd8b75aa03bc..64458ca3d69f 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -9,12 +9,12 @@ alloc::Flags, bindings, device::{Bound, Device}, - error::{Error, Result}, + error::{to_result, Error, Result}, ffi::c_void, prelude::*, revocable::{Revocable, RevocableGuard}, sync::{rcu, Arc, Completion}, - types::ARef, + types::{ARef, ForeignOwnable}, }; #[pin_data] @@ -184,14 +184,6 @@ pub fn new(dev: &Device, data: T, flags: Flags) -> Result { Ok(Devres(inner)) } - /// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data` - /// is owned by devres and will be revoked / dropped, once the device is detached. - pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result { - let _ = DevresInner::new(dev, data, flags)?; - - Ok(()) - } - /// Obtain `&'a T`, bypassing the [`Revocable`]. /// /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting @@ -261,3 +253,64 @@ fn drop(&mut self) { } } } + +/// Consume `data` and [`Drop::drop`] `data` once `dev` is unbound. +fn register_foreign

(dev: &Device, data: P) -> Result +where + P: ForeignOwnable + Send + 'static, +{ + let ptr = data.into_foreign(); + + #[allow(clippy::missing_safety_doc)] + unsafe extern "C" fn callback(ptr: *mut kernel::ffi::c_void) { + // SAFETY: `ptr` is the pointer to the `ForeignOwnable` leaked above and hence valid. + drop(unsafe { P::from_foreign(ptr.cast()) }); + } + + // SAFETY: + // - `dev.as_raw()` is a pointer to a valid and bound device. + // - `ptr` is a valid pointer the `ForeignOwnable` devres takes ownership of. + to_result(unsafe { + // `devm_add_action_or_reset()` also calls `callback` on failure, such that the + // `ForeignOwnable` is released eventually. + bindings::devm_add_action_or_reset(dev.as_raw(), Some(callback::

), ptr.cast()) + }) +} + +/// Encapsulate `data` in a [`KBox`] and [`Drop::drop`] `data` once `dev` is unbound. +/// +/// # Examples +/// +/// ```no_run +/// use kernel::{device::{Bound, Device}, devres}; +/// +/// /// Registration of e.g. a class device, IRQ, etc. +/// struct Registration; +/// +/// impl Registration { +/// fn new() -> Self { +/// // register +/// +/// Self +/// } +/// } +/// +/// impl Drop for Registration { +/// fn drop(&mut self) { +/// // unregister +/// } +/// } +/// +/// fn from_bound_context(dev: &Device) -> Result { +/// devres::register(dev, Registration::new(), GFP_KERNEL) +/// } +/// ``` +pub fn register(dev: &Device, data: impl PinInit, flags: Flags) -> Result +where + T: Send + 'static, + Error: From, +{ + let data = KBox::pin_init(data, flags)?; + + register_foreign(dev, data) +} diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs index acb638086131..f63addaf7235 100644 --- a/rust/kernel/drm/driver.rs +++ b/rust/kernel/drm/driver.rs @@ -5,9 +5,7 @@ //! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h) use crate::{ - bindings, device, - devres::Devres, - drm, + bindings, device, devres, drm, error::{to_result, Result}, prelude::*, str::CStr, @@ -130,18 +128,22 @@ fn new(drm: &drm::Device, flags: usize) -> Result { } /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to - /// [`Devres`]. + /// [`devres::register`]. pub fn new_foreign_owned( drm: &drm::Device, dev: &device::Device, flags: usize, - ) -> Result { + ) -> Result + where + T: 'static, + { if drm.as_ref().as_raw() != dev.as_raw() { return Err(EINVAL); } let reg = Registration::::new(drm, flags)?; - Devres::new_foreign_owned(dev, reg, GFP_KERNEL) + + devres::register(dev, reg, GFP_KERNEL) } /// Returns a reference to the `Device` instance for this registration. From f5d3ef25d238901a76fe0277787afa44f7714739 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 26 Jun 2025 22:00:41 +0200 Subject: [PATCH 31/84] rust: devres: get rid of Devres' inner Arc So far Devres uses an inner memory allocation and reference count, i.e. an inner Arc, in order to ensure that the devres callback can't run into a use-after-free in case where the Devres object is dropped while the devres callback runs concurrently. Instead, use a completion in order to avoid a potential UAF: In Devres::drop(), if we detect that we can't remove the devres action anymore, we wait for the completion that is completed from the devres callback. If, in turn, we were able to successfully remove the devres action, we can just go ahead. This, again, allows us to get rid of the internal Arc, and instead let Devres consume an `impl PinInit` in order to return an `impl PinInit, E>`, which enables us to get away with less memory allocations. Additionally, having the resulting explicit synchronization in Devres::drop() prevents potential subtle undesired side effects of the devres callback dropping the final Arc reference asynchronously within the devres callback. Reviewed-by: Benno Lossin Reviewed-by: Boqun Feng Link: https://lore.kernel.org/r/20250626200054.243480-4-dakr@kernel.org [ Move '# Invariants' below '# Examples'. - Danilo ] Signed-off-by: Danilo Krummrich --- drivers/gpu/nova-core/driver.rs | 7 +- drivers/gpu/nova-core/gpu.rs | 6 +- rust/kernel/devres.rs | 213 +++++++++++++++++++------------- rust/kernel/pci.rs | 20 +-- samples/rust/rust_driver_pci.rs | 19 +-- 5 files changed, 154 insertions(+), 111 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 8c86101c26cb..110f2b355db4 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::{auxiliary, bindings, c_str, device::Core, pci, prelude::*}; +use kernel::{auxiliary, bindings, c_str, device::Core, pci, prelude::*, sync::Arc}; use crate::gpu::Gpu; @@ -34,7 +34,10 @@ fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> Result(0, c_str!("nova-core/bar0"))?; + let bar = Arc::pin_init( + pdev.iomap_region_sized::(0, c_str!("nova-core/bar0")), + GFP_KERNEL, + )?; let this = KBox::pin_init( try_pin_init!(Self { diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 60b86f370284..47653c14838b 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -use kernel::{device, devres::Devres, error::code::*, pci, prelude::*}; +use kernel::{device, devres::Devres, error::code::*, pci, prelude::*, sync::Arc}; use crate::driver::Bar0; use crate::firmware::{Firmware, FIRMWARE_VERSION}; @@ -161,14 +161,14 @@ fn new(bar: &Bar0) -> Result { pub(crate) struct Gpu { spec: Spec, /// MMIO mapping of PCI BAR 0 - bar: Devres, + bar: Arc>, fw: Firmware, } impl Gpu { pub(crate) fn new( pdev: &pci::Device, - devres_bar: Devres, + devres_bar: Arc>, ) -> Result> { let bar = devres_bar.access(pdev.as_ref())?; let spec = Spec::new(bar)?; diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 64458ca3d69f..7c5c5de8bcb6 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -13,16 +13,21 @@ ffi::c_void, prelude::*, revocable::{Revocable, RevocableGuard}, - sync::{rcu, Arc, Completion}, - types::{ARef, ForeignOwnable}, + sync::{rcu, Completion}, + types::{ARef, ForeignOwnable, Opaque, ScopeGuard}, }; +use pin_init::Wrapper; + +/// [`Devres`] inner data accessed from [`Devres::callback`]. #[pin_data] -struct DevresInner { - dev: ARef, - callback: unsafe extern "C" fn(*mut c_void), +struct Inner { #[pin] data: Revocable, + /// Tracks whether [`Devres::callback`] has been completed. + #[pin] + devm: Completion, + /// Tracks whether revoking [`Self::data`] has been completed. #[pin] revoke: Completion, } @@ -88,100 +93,115 @@ struct DevresInner { /// # fn no_run(dev: &Device) -> Result<(), Error> { /// // SAFETY: Invalid usage for example purposes. /// let iomem = unsafe { IoMem::<{ core::mem::size_of::() }>::new(0xBAAAAAAD)? }; -/// let devres = Devres::new(dev, iomem, GFP_KERNEL)?; +/// let devres = KBox::pin_init(Devres::new(dev, iomem), GFP_KERNEL)?; /// /// let res = devres.try_access().ok_or(ENXIO)?; /// res.write8(0x42, 0x0); /// # Ok(()) /// # } /// ``` -pub struct Devres(Arc>); +/// +/// # Invariants +/// +/// [`Self::inner`] is guaranteed to be initialized and is always accessed read-only. +#[pin_data(PinnedDrop)] +pub struct Devres { + dev: ARef, + /// Pointer to [`Self::devres_callback`]. + /// + /// Has to be stored, since Rust does not guarantee to always return the same address for a + /// function. However, the C API uses the address as a key. + callback: unsafe extern "C" fn(*mut c_void), + /// Contains all the fields shared with [`Self::callback`]. + // TODO: Replace with `UnsafePinned`, once available. + // + // Subsequently, the `drop_in_place()` in `Devres::drop` and the explicit `Send` and `Sync' + // impls can be removed. + #[pin] + inner: Opaque>, +} -impl DevresInner { - fn new(dev: &Device, data: T, flags: Flags) -> Result>> { - let inner = Arc::pin_init( - try_pin_init!( DevresInner { - dev: dev.into(), - callback: Self::devres_callback, +impl Devres { + /// Creates a new [`Devres`] instance of the given `data`. + /// + /// The `data` encapsulated within the returned `Devres` instance' `data` will be + /// (revoked)[`Revocable`] once the device is detached. + pub fn new<'a, E>( + dev: &'a Device, + data: impl PinInit + 'a, + ) -> impl PinInit + 'a + where + T: 'a, + Error: From, + { + let callback = Self::devres_callback; + + try_pin_init!(&this in Self { + // INVARIANT: `inner` is properly initialized. + inner <- Opaque::pin_init(try_pin_init!(Inner { data <- Revocable::new(data), + devm <- Completion::new(), revoke <- Completion::new(), - }), - flags, - )?; + })), + callback, + dev: { + // SAFETY: `this` is a valid pointer to uninitialized memory. + let inner = unsafe { &raw mut (*this.as_ptr()).inner }; - // Convert `Arc` into a raw pointer and make devres own this reference until - // `Self::devres_callback` is called. - let data = inner.clone().into_raw(); + // SAFETY: + // - `dev.as_raw()` is a pointer to a valid bound device. + // - `inner` is guaranteed to be a valid for the duration of the lifetime of `Self`. + // - `devm_add_action()` is guaranteed not to call `callback` until `this` has been + // properly initialized, because we require `dev` (i.e. the *bound* device) to + // live at least as long as the returned `impl PinInit`. + to_result(unsafe { + bindings::devm_add_action(dev.as_raw(), Some(callback), inner.cast()) + })?; - // SAFETY: `devm_add_action` guarantees to call `Self::devres_callback` once `dev` is - // detached. - let ret = - unsafe { bindings::devm_add_action(dev.as_raw(), Some(inner.callback), data as _) }; - - if ret != 0 { - // SAFETY: We just created another reference to `inner` in order to pass it to - // `bindings::devm_add_action`. If `bindings::devm_add_action` fails, we have to drop - // this reference accordingly. - let _ = unsafe { Arc::from_raw(data) }; - return Err(Error::from_errno(ret)); - } - - Ok(inner) + dev.into() + }, + }) } - fn as_ptr(&self) -> *const Self { - self as _ + fn inner(&self) -> &Inner { + // SAFETY: By the type invairants of `Self`, `inner` is properly initialized and always + // accessed read-only. + unsafe { &*self.inner.get() } } - fn remove_action(this: &Arc) -> bool { - // SAFETY: - // - `self.inner.dev` is a valid `Device`, - // - the `action` and `data` pointers are the exact same ones as given to devm_add_action() - // previously, - // - `self` is always valid, even if the action has been released already. - let success = unsafe { - bindings::devm_remove_action_nowarn( - this.dev.as_raw(), - Some(this.callback), - this.as_ptr() as _, - ) - } == 0; - - if success { - // SAFETY: We leaked an `Arc` reference to devm_add_action() in `DevresInner::new`; if - // devm_remove_action_nowarn() was successful we can (and have to) claim back ownership - // of this reference. - let _ = unsafe { Arc::from_raw(this.as_ptr()) }; - } - - success + fn data(&self) -> &Revocable { + &self.inner().data } #[allow(clippy::missing_safety_doc)] unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) { - let ptr = ptr as *mut DevresInner; - // Devres owned this memory; now that we received the callback, drop the `Arc` and hence the - // reference. - // SAFETY: Safe, since we leaked an `Arc` reference to devm_add_action() in - // `DevresInner::new`. - let inner = unsafe { Arc::from_raw(ptr) }; + // SAFETY: In `Self::new` we've passed a valid pointer to `Inner` to `devm_add_action()`, + // hence `ptr` must be a valid pointer to `Inner`. + let inner = unsafe { &*ptr.cast::>() }; + + // Ensure that `inner` can't be used anymore after we signal completion of this callback. + let inner = ScopeGuard::new_with_data(inner, |inner| inner.devm.complete_all()); if !inner.data.revoke() { // If `revoke()` returns false, it means that `Devres::drop` already started revoking - // `inner.data` for us. Hence we have to wait until `Devres::drop()` signals that it - // completed revoking `inner.data`. + // `data` for us. Hence we have to wait until `Devres::drop` signals that it + // completed revoking `data`. inner.revoke.wait_for_completion(); } } -} -impl Devres { - /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the - /// returned `Devres` instance' `data` will be revoked once the device is detached. - pub fn new(dev: &Device, data: T, flags: Flags) -> Result { - let inner = DevresInner::new(dev, data, flags)?; - - Ok(Devres(inner)) + fn remove_action(&self) -> bool { + // SAFETY: + // - `self.dev` is a valid `Device`, + // - the `action` and `data` pointers are the exact same ones as given to + // `devm_add_action()` previously, + (unsafe { + bindings::devm_remove_action_nowarn( + self.dev.as_raw(), + Some(self.callback), + core::ptr::from_ref(self.inner()).cast_mut().cast(), + ) + } == 0) } /// Obtain `&'a T`, bypassing the [`Revocable`]. @@ -213,44 +233,63 @@ pub fn new(dev: &Device, data: T, flags: Flags) -> Result { /// } /// ``` pub fn access<'a>(&'a self, dev: &'a Device) -> Result<&'a T> { - if self.0.dev.as_raw() != dev.as_raw() { + if self.dev.as_raw() != dev.as_raw() { return Err(EINVAL); } // SAFETY: `dev` being the same device as the device this `Devres` has been created for - // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as - // long as `dev` lives; `dev` lives at least as long as `self`. - Ok(unsafe { self.0.data.access() }) + // proves that `self.data` hasn't been revoked and is guaranteed to not be revoked as long + // as `dev` lives; `dev` lives at least as long as `self`. + Ok(unsafe { self.data().access() }) } /// [`Devres`] accessor for [`Revocable::try_access`]. pub fn try_access(&self) -> Option> { - self.0.data.try_access() + self.data().try_access() } /// [`Devres`] accessor for [`Revocable::try_access_with`]. pub fn try_access_with R>(&self, f: F) -> Option { - self.0.data.try_access_with(f) + self.data().try_access_with(f) } /// [`Devres`] accessor for [`Revocable::try_access_with_guard`]. pub fn try_access_with_guard<'a>(&'a self, guard: &'a rcu::Guard) -> Option<&'a T> { - self.0.data.try_access_with_guard(guard) + self.data().try_access_with_guard(guard) } } -impl Drop for Devres { - fn drop(&mut self) { +// SAFETY: `Devres` can be send to any task, if `T: Send`. +unsafe impl Send for Devres {} + +// SAFETY: `Devres` can be shared with any task, if `T: Sync`. +unsafe impl Sync for Devres {} + +#[pinned_drop] +impl PinnedDrop for Devres { + fn drop(self: Pin<&mut Self>) { // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data // anymore, hence it is safe not to wait for the grace period to finish. - if unsafe { self.0.data.revoke_nosync() } { - // We revoked `self.0.data` before the devres action did, hence try to remove it. - if !DevresInner::remove_action(&self.0) { + if unsafe { self.data().revoke_nosync() } { + // We revoked `self.data` before the devres action did, hence try to remove it. + if !self.remove_action() { // We could not remove the devres action, which means that it now runs concurrently, - // hence signal that `self.0.data` has been revoked successfully. - self.0.revoke.complete_all(); + // hence signal that `self.data` has been revoked by us successfully. + self.inner().revoke.complete_all(); + + // Wait for `Self::devres_callback` to be done using this object. + self.inner().devm.wait_for_completion(); } + } else { + // `Self::devres_callback` revokes `self.data` for us, hence wait for it to be done + // using this object. + self.inner().devm.wait_for_completion(); } + + // INVARIANT: At this point it is guaranteed that `inner` can't be accessed any more. + // + // SAFETY: `inner` is valid for dropping. + unsafe { core::ptr::drop_in_place(self.inner.get()) }; } } diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 8435f8132e38..db0eb7eaf9b1 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -5,7 +5,6 @@ //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use crate::{ - alloc::flags::*, bindings, container_of, device, device_id::RawDeviceId, devres::Devres, @@ -398,19 +397,20 @@ pub fn resource_len(&self, bar: u32) -> Result { impl Device { /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks /// can be performed on compile time for offsets (plus the requested type size) < SIZE. - pub fn iomap_region_sized( - &self, + pub fn iomap_region_sized<'a, const SIZE: usize>( + &'a self, bar: u32, - name: &CStr, - ) -> Result>> { - let bar = Bar::::new(self, bar, name)?; - let devres = Devres::new(self.as_ref(), bar, GFP_KERNEL)?; - - Ok(devres) + name: &'a CStr, + ) -> impl PinInit>, Error> + 'a { + Devres::new(self.as_ref(), Bar::::new(self, bar, name)) } /// Mapps an entire PCI-BAR after performing a region-request on it. - pub fn iomap_region(&self, bar: u32, name: &CStr) -> Result> { + pub fn iomap_region<'a>( + &'a self, + bar: u32, + name: &'a CStr, + ) -> impl PinInit, Error> + 'a { self.iomap_region_sized::<0>(bar, name) } } diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 15147e4401b2..5c35f1414172 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -25,8 +25,10 @@ impl TestIndex { const NO_EVENTFD: Self = Self(0); } +#[pin_data(PinnedDrop)] struct SampleDriver { pdev: ARef, + #[pin] bar: Devres, } @@ -73,13 +75,11 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> Result pdev.enable_device_mem()?; pdev.set_master(); - let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?; - - let drvdata = KBox::new( - Self { + let drvdata = KBox::pin_init( + try_pin_init!(Self { pdev: pdev.into(), - bar, - }, + bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")), + }), GFP_KERNEL, )?; @@ -90,12 +90,13 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> Result Self::testdev(info, bar)? ); - Ok(drvdata.into()) + Ok(drvdata) } } -impl Drop for SampleDriver { - fn drop(&mut self) { +#[pinned_drop] +impl PinnedDrop for SampleDriver { + fn drop(self: Pin<&mut Self>) { dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n"); } } From 9b5cdd5f40191d11d3b535ab7978751a4a3e4bc5 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 24 Jun 2025 07:58:46 +0900 Subject: [PATCH 32/84] rust: fix typo in #[repr(transparent)] comments Fix a typo in several comments where `#[repr(transparent)]` was mistakenly written as `#[repr(transparent)` (missing closing bracket). Signed-off-by: FUJITA Tomonori Link: https://lore.kernel.org/r/20250623225846.169805-1-fujita.tomonori@gmail.com Signed-off-by: Greg Kroah-Hartman --- rust/kernel/driver.rs | 4 ++-- rust/kernel/of.rs | 2 +- rust/kernel/pci.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index a4bf4498e592..f8dd7593e8dc 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -166,7 +166,7 @@ fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { if raw_id.is_null() { None } else { - // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct acpi_device_id` + // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct acpi_device_id` // and does not add additional invariants, so it's safe to transmute. let id = unsafe { &*raw_id.cast::() }; @@ -200,7 +200,7 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { if raw_id.is_null() { None } else { - // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` + // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` // and does not add additional invariants, so it's safe to transmute. let id = unsafe { &*raw_id.cast::() }; diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs index 04f2d8ef29cb..52fe0c77b9a1 100644 --- a/rust/kernel/of.rs +++ b/rust/kernel/of.rs @@ -13,7 +13,7 @@ pub struct DeviceId(bindings::of_device_id); // SAFETY: -// * `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` and does not add +// * `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` and does not add // additional invariants, so it's safe to transmute to `RawType`. // * `DRIVER_DATA_OFFSET` is the offset to the `data` field. unsafe impl RawDeviceId for DeviceId { diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index db0eb7eaf9b1..9afe2a8ed637 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -67,7 +67,7 @@ extern "C" fn probe_callback( // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. let pdev = unsafe { &*pdev.cast::>() }; - // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct pci_device_id` and + // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and // does not add additional invariants, so it's safe to transmute. let id = unsafe { &*id.cast::() }; let info = T::ID_TABLE.info(id.index()); @@ -161,7 +161,7 @@ pub const fn from_class(class: u32, class_mask: u32) -> Self { } // SAFETY: -// * `DeviceId` is a `#[repr(transparent)` wrapper of `pci_device_id` and does not add +// * `DeviceId` is a `#[repr(transparent)]` wrapper of `pci_device_id` and does not add // additional invariants, so it's safe to transmute to `RawType`. // * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. unsafe impl RawDeviceId for DeviceId { From b9ff1c2a26fa31216be18e9b14c419ff8fe39e72 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Thu, 26 Jun 2025 16:15:20 +0530 Subject: [PATCH 33/84] rust: miscdevice: clarify invariant for `MiscDeviceRegistration` Reword and expand the invariant documentation for `MiscDeviceRegistration` to clarify what it means for the inner device to be "registered". It expands to explain: - `inner` points to a `miscdevice` registered via `misc_register`. - This registration stays valid for the entire lifetime of the object. - Deregistration is guaranteed on `Drop`, via `misc_deregister`. Reported-by: Benno Lossin Closes: https://github.com/Rust-for-Linux/linux/issues/1168 Fixes: f893691e7426 ("rust: miscdevice: add base miscdevice abstraction") Signed-off-by: Shankari Anand Link: https://lore.kernel.org/r/20250626104520.563036-1-shankari.ak0208@gmail.com Signed-off-by: Greg Kroah-Hartman --- rust/kernel/miscdevice.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 939278bc7b03..4f7a8714ad36 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -45,7 +45,13 @@ pub const fn into_raw(self) -> bindings::miscdevice { /// /// # Invariants /// -/// `inner` is a registered misc device. +/// - `inner` contains a `struct miscdevice` that is registered using +/// `misc_register()`. +/// - This registration remains valid for the entire lifetime of the +/// [`MiscDeviceRegistration`] instance. +/// - Deregistration occurs exactly once in [`Drop`] via `misc_deregister()`. +/// - `inner` wraps a valid, pinned `miscdevice` created using +/// [`MiscDeviceOptions::into_raw`]. #[repr(transparent)] #[pin_data(PinnedDrop)] pub struct MiscDeviceRegistration { From 5accfca0e5ba26fd1113ecf461ffff607244e3b7 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 8 Apr 2025 13:58:21 +0200 Subject: [PATCH 34/84] Docs/ABI: Fix sysfs-kernel-address_bits path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's address_bits, not address_bit. Fixes: 00142bfd5a91 ("kernels/ksysfs.c: export kernel address bits") Signed-off-by: Richard Weinberger Acked-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250408115823.1358597-1-richard@nod.at Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-kernel-address_bits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-kernel-address_bits b/Documentation/ABI/testing/sysfs-kernel-address_bits index 5d09ff84d4d6..3b72e48086aa 100644 --- a/Documentation/ABI/testing/sysfs-kernel-address_bits +++ b/Documentation/ABI/testing/sysfs-kernel-address_bits @@ -1,4 +1,4 @@ -What: /sys/kernel/address_bit +What: /sys/kernel/address_bits Date: May 2023 KernelVersion: 6.3 Contact: Thomas Weißschuh From b75e1f0619bd707e027812e262af3fbce445e71a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 9 Jun 2025 10:26:47 +0300 Subject: [PATCH 35/84] device property: Use tidy for_each_named_* macros Implementing if-conditions inside for_each_x() macros requires some thinking to avoid side effects in the calling code. Resulting code may look somewhat awkward, and there are couple of different ways it is usually done. Standardizing this to one way can help making it more obvious for a code reader and writer. The newly added for_each_if() is a way to achieve this. Use for_each_if() to make these macros look like many others which should in the long run help reading the code. Signed-off-by: Matti Vaittinen Acked-by: Sakari Ailus Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/c98b39a7195006fdd24590b8d11bb271a72a0c8a.1749453752.git.mazziesaccount@gmail.com Signed-off-by: Greg Kroah-Hartman --- include/linux/property.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/property.h b/include/linux/property.h index f718dd4789e5..82f0cb3abd1e 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -17,6 +17,7 @@ #include #include #include +#include struct device; @@ -169,7 +170,7 @@ struct fwnode_handle *fwnode_get_next_available_child_node( #define fwnode_for_each_named_child_node(fwnode, child, name) \ fwnode_for_each_child_node(fwnode, child) \ - if (!fwnode_name_eq(child, name)) { } else + for_each_if(fwnode_name_eq(child, name)) #define fwnode_for_each_available_child_node(fwnode, child) \ for (child = fwnode_get_next_available_child_node(fwnode, NULL); child;\ @@ -184,7 +185,7 @@ struct fwnode_handle *device_get_next_child_node(const struct device *dev, #define device_for_each_named_child_node(dev, child, name) \ device_for_each_child_node(dev, child) \ - if (!fwnode_name_eq(child, name)) { } else + for_each_if(fwnode_name_eq(child, name)) #define device_for_each_child_node_scoped(dev, child) \ for (struct fwnode_handle *child __free(fwnode_handle) = \ @@ -193,7 +194,7 @@ struct fwnode_handle *device_get_next_child_node(const struct device *dev, #define device_for_each_named_child_node_scoped(dev, child, name) \ device_for_each_child_node_scoped(dev, child) \ - if (!fwnode_name_eq(child, name)) { } else + for_each_if(fwnode_name_eq(child, name)) struct fwnode_handle *fwnode_get_named_child_node(const struct fwnode_handle *fwnode, const char *childname); From 97ba207a994f7d0cc58f19d448e98db6735f5e77 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Tue, 1 Jul 2025 19:46:56 +0200 Subject: [PATCH 36/84] rust: acpi: remove unneeded cast to clean future Clippy warning A future Clippy warning, `clippy::as_underscore`, is getting enabled in parallel in the rust-next tree: error: using `as _` conversion --> rust/kernel/acpi.rs:25:9 | 25 | self.0.driver_data as _ | ^^^^^^^^^^^^^^^^^^^^^^- | | | help: consider giving the type explicitly: `usize` The type is already `ulong`, which nowadays is always `usize`, so the cast is unneeded. Thus remove it, which in turn will avoid the warning in the future. Other abstractions of device tables do not use a cast here either. Signed-off-by: Miguel Ojeda Reviewed-by: Trevor Gross Link: https://lore.kernel.org/r/20250701174656.62205-1-ojeda@kernel.org Signed-off-by: Greg Kroah-Hartman --- rust/kernel/acpi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs index eaae3bc8e54c..2af4d4f92924 100644 --- a/rust/kernel/acpi.rs +++ b/rust/kernel/acpi.rs @@ -22,7 +22,7 @@ unsafe impl RawDeviceId for DeviceId { const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::acpi_device_id, driver_data); fn index(&self) -> usize { - self.0.driver_data as _ + self.0.driver_data } } From 8ae33576ead8fb71505515df8c938b3e0ae5b37c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 4 Jul 2025 15:49:54 -0400 Subject: [PATCH 37/84] rust: platform: remove unnecessary import `kernel::str::CStr` is included in the prelude. Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20250704-cstr-include-platform-v1-1-ff7803ee7a81@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 86f9d73c64b3..7484d7e5c2cf 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -9,7 +9,6 @@ error::{to_result, Result}, of, prelude::*, - str::CStr, types::{ForeignOwnable, Opaque}, ThisModule, }; From 65f8f0d4e0b45dc784f18a7ca4739e1df12b950a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 4 Jul 2025 15:50:44 -0400 Subject: [PATCH 38/84] rust: auxiliary: remove unnecessary import `kernel::str::CStr` is included in the prelude. Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20250704-cstr-include-aux-v1-1-e1a404ae92ac@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/auxiliary.rs | 1 - samples/rust/rust_driver_auxiliary.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index d2cfe1eeefb6..4fe62bbf8b3a 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -10,7 +10,6 @@ driver, error::{to_result, Result}, prelude::*, - str::CStr, types::{ForeignOwnable, Opaque}, ThisModule, }; diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 3e15e6d002bb..b25628604a93 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -5,8 +5,7 @@ //! To make this driver probe, QEMU must be run with `-device pci-testdev`. use kernel::{ - auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, str::CStr, - InPlaceModule, + auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule, }; use pin_init::PinInit; From 6d16cd5769bbb5eb62974e8eddb97fca830b49fd Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 4 Jul 2025 16:11:02 -0400 Subject: [PATCH 39/84] rust: devres: remove unused import As far as I can tell, `c_str` was never used, hence remove it. Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20250704-cstr-include-devres-v1-1-4ee9e56fca09@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 7c5c5de8bcb6..f43de3d77d61 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -52,7 +52,7 @@ struct Inner { /// # Example /// /// ```no_run -/// # use kernel::{bindings, c_str, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}}; +/// # use kernel::{bindings, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}}; /// # use core::ops::Deref; /// /// // See also [`pci::Bar`] for a real example. From 5cddd546df0fa21316735d1d60fe826886e0dc21 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sun, 6 Jul 2025 04:00:32 +0000 Subject: [PATCH 40/84] rust: pci: fix documentation related to Device instances Device instances in the pci crate represent a valid struct pci_dev, not a struct device. Fixes: 7b948a2af6b5 ("rust: pci: fix unrestricted &mut pci::Device") Signed-off-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20250706035944.18442-3-sergeantsagara@protonmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 9afe2a8ed637..a1febfbfc7d7 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -250,7 +250,8 @@ pub trait Driver: Send { /// /// # Invariants /// -/// A [`Device`] instance represents a valid `struct device` created by the C portion of the kernel. +/// A [`Device`] instance represents a valid `struct pci_dev` created by the C portion of the +/// kernel. #[repr(transparent)] pub struct Device( Opaque, From fa7486d3f9470c58c5971caba7244cc8773672e0 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:27 +0200 Subject: [PATCH 41/84] rust: device: introduce device::CoreInternal Introduce an internal device context, which is semantically equivalent to the Core device context, but reserved for bus abstractions. This allows implementing methods for the Device type, which are limited to be used within the core context of bus abstractions, i.e. restrict the availability for drivers. Link: https://lore.kernel.org/r/20250621195118.124245-2-dakr@kernel.org [ Rename device::Internal to device::CoreInternal. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 665f5ceadecc..6b8acee4a378 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -261,6 +261,10 @@ pub trait DeviceContext: private::Sealed {} /// any of the bus callbacks, such as `probe()`. pub struct Core; +/// Semantically the same as [`Core`] but reserved for internal usage of the corresponding bus +/// abstraction. +pub struct CoreInternal; + /// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to /// be bound for the duration of its lifetime. pub struct Bound; @@ -270,11 +274,13 @@ pub trait Sealed {} impl Sealed for super::Bound {} impl Sealed for super::Core {} + impl Sealed for super::CoreInternal {} impl Sealed for super::Normal {} } impl DeviceContext for Bound {} impl DeviceContext for Core {} +impl DeviceContext for CoreInternal {} impl DeviceContext for Normal {} /// # Safety @@ -312,6 +318,13 @@ fn deref(&self) -> &Self::Target { #[macro_export] macro_rules! impl_device_context_deref { (unsafe { $device:ident }) => { + // SAFETY: This macro has the exact same safety requirement as + // `__impl_device_context_deref!`. + ::kernel::__impl_device_context_deref!(unsafe { + $device, + $crate::device::CoreInternal => $crate::device::Core + }); + // SAFETY: This macro has the exact same safety requirement as // `__impl_device_context_deref!`. ::kernel::__impl_device_context_deref!(unsafe { @@ -345,6 +358,7 @@ fn from(dev: &$device<$src>) -> Self { #[macro_export] macro_rules! impl_device_context_into_aref { ($device:tt) => { + ::kernel::__impl_device_context_into_aref!($crate::device::CoreInternal, $device); ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device); ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device); }; From 880dec12a25890e8f5626f04c58d38003f1a5585 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:28 +0200 Subject: [PATCH 42/84] rust: device: add drvdata accessors Implement generic accessors for the private data of a driver bound to a device. Those accessors should be used by bus abstractions from their corresponding core callbacks, such as probe(), remove(), etc. Implementing them for device::CoreInternal guarantees that driver's can't interfere with the logic implemented by the bus abstraction. Acked-by: Benno Lossin Link: https://lore.kernel.org/r/20250621195118.124245-3-dakr@kernel.org [ Improve safety comment as proposed by Benno. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/helpers/device.c | 10 +++++++++ rust/kernel/device.rs | 49 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/rust/helpers/device.c b/rust/helpers/device.c index 502fef7e9ae8..9a4316bafedf 100644 --- a/rust/helpers/device.c +++ b/rust/helpers/device.c @@ -15,3 +15,13 @@ int rust_helper_devm_add_action_or_reset(struct device *dev, { return devm_add_action_or_reset(dev, action, data); } + +void *rust_helper_dev_get_drvdata(const struct device *dev) +{ + return dev_get_drvdata(dev); +} + +void rust_helper_dev_set_drvdata(struct device *dev, void *data) +{ + dev_set_drvdata(dev, data); +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 6b8acee4a378..d527ceef829e 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -6,7 +6,7 @@ use crate::{ bindings, - types::{ARef, Opaque}, + types::{ARef, ForeignOwnable, Opaque}, }; use core::{fmt, marker::PhantomData, ptr}; @@ -62,6 +62,53 @@ pub unsafe fn get_device(ptr: *mut bindings::device) -> ARef { } } +impl Device { + /// Store a pointer to the bound driver's private data. + pub fn set_drvdata(&self, data: impl ForeignOwnable) { + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreign().cast()) } + } + + /// Take ownership of the private data stored in this [`Device`]. + /// + /// # Safety + /// + /// - Must only be called once after a preceding call to [`Device::set_drvdata`]. + /// - The type `T` must match the type of the `ForeignOwnable` previously stored by + /// [`Device::set_drvdata`]. + pub unsafe fn drvdata_obtain(&self) -> T { + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; + + // SAFETY: + // - By the safety requirements of this function, `ptr` comes from a previous call to + // `into_foreign()`. + // - `dev_get_drvdata()` guarantees to return the same pointer given to `dev_set_drvdata()` + // in `into_foreign()`. + unsafe { T::from_foreign(ptr.cast()) } + } + + /// Borrow the driver's private data bound to this [`Device`]. + /// + /// # Safety + /// + /// - Must only be called after a preceding call to [`Device::set_drvdata`] and before + /// [`Device::drvdata_obtain`]. + /// - The type `T` must match the type of the `ForeignOwnable` previously stored by + /// [`Device::set_drvdata`]. + pub unsafe fn drvdata_borrow(&self) -> T::Borrowed<'_> { + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; + + // SAFETY: + // - By the safety requirements of this function, `ptr` comes from a previous call to + // `into_foreign()`. + // - `dev_get_drvdata()` guarantees to return the same pointer given to `dev_set_drvdata()` + // in `into_foreign()`. + unsafe { T::borrow(ptr.cast()) } + } +} + impl Device { /// Obtain the raw `struct device *`. pub(crate) fn as_raw(&self) -> *mut bindings::device { From f0a68a912c673d8899d863c2f01f1ef7006e0b11 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:29 +0200 Subject: [PATCH 43/84] rust: platform: use generic device drvdata accessors Take advantage of the generic drvdata accessors of the generic Device type. While at it, use from_result() instead of match. Link: https://lore.kernel.org/r/20250621195118.124245-4-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/helpers/platform.c | 10 ---------- rust/kernel/platform.rs | 36 +++++++++++++++++------------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/rust/helpers/platform.c b/rust/helpers/platform.c index 82171233d12f..1ce89c1a36f7 100644 --- a/rust/helpers/platform.c +++ b/rust/helpers/platform.c @@ -2,16 +2,6 @@ #include -void *rust_helper_platform_get_drvdata(const struct platform_device *pdev) -{ - return platform_get_drvdata(pdev); -} - -void rust_helper_platform_set_drvdata(struct platform_device *pdev, void *data) -{ - platform_set_drvdata(pdev, data); -} - bool rust_helper_dev_is_platform(const struct device *dev) { return dev_is_platform(dev); diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 7484d7e5c2cf..e9e95c5bb02b 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -6,10 +6,10 @@ use crate::{ acpi, bindings, container_of, device, driver, - error::{to_result, Result}, + error::{from_result, to_result, Result}, of, prelude::*, - types::{ForeignOwnable, Opaque}, + types::Opaque, ThisModule, }; @@ -66,30 +66,28 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; - + let pdev = unsafe { &*pdev.cast::>() }; let info = ::id_info(pdev.as_ref()); - match T::probe(pdev, info) { - Ok(data) => { - // Let the `struct platform_device` own a reference of the driver's private data. - // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a - // `struct platform_device`. - unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; - } - Err(err) => return Error::to_errno(err), - } - 0 + from_result(|| { + let data = T::probe(pdev, info)?; + + pdev.as_ref().set_drvdata(data); + Ok(0) + }) } extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { - // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. - let ptr = unsafe { bindings::platform_get_drvdata(pdev) }.cast(); + // SAFETY: The platform bus only ever calls the remove callback with a valid pointer to a + // `struct platform_device`. + // + // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. + let pdev = unsafe { &*pdev.cast::>() }; // SAFETY: `remove_callback` is only ever called after a successful call to - // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized - // `KBox` pointer created through `KBox::into_foreign`. - let _ = unsafe { KBox::::from_foreign(ptr) }; + // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called + // and stored a `Pin>`. + let _ = unsafe { pdev.as_ref().drvdata_obtain::>>() }; } } From 4231712c8e9840c023192032d438f98061b9ee1f Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:30 +0200 Subject: [PATCH 44/84] rust: pci: use generic device drvdata accessors Take advantage of the generic drvdata accessors of the generic Device type. While at it, use from_result() instead of match. Link: https://lore.kernel.org/r/20250621195118.124245-5-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/helpers/pci.c | 10 ---------- rust/kernel/pci.rs | 31 ++++++++++++++----------------- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c index cd0e6bf2cc4d..ef9cb38c81a6 100644 --- a/rust/helpers/pci.c +++ b/rust/helpers/pci.c @@ -2,16 +2,6 @@ #include -void rust_helper_pci_set_drvdata(struct pci_dev *pdev, void *data) -{ - pci_set_drvdata(pdev, data); -} - -void *rust_helper_pci_get_drvdata(struct pci_dev *pdev) -{ - return pci_get_drvdata(pdev); -} - resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, int bar) { return pci_resource_len(pdev, bar); diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index a1febfbfc7d7..34f0db8054fe 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -9,11 +9,11 @@ device_id::RawDeviceId, devres::Devres, driver, - error::{to_result, Result}, + error::{from_result, to_result, Result}, io::Io, io::IoRaw, str::CStr, - types::{ARef, ForeignOwnable, Opaque}, + types::{ARef, Opaque}, ThisModule, }; use core::{ @@ -65,35 +65,32 @@ extern "C" fn probe_callback( // `struct pci_dev`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; + let pdev = unsafe { &*pdev.cast::>() }; // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and // does not add additional invariants, so it's safe to transmute. let id = unsafe { &*id.cast::() }; let info = T::ID_TABLE.info(id.index()); - match T::probe(pdev, info) { - Ok(data) => { - // Let the `struct pci_dev` own a reference of the driver's private data. - // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a - // `struct pci_dev`. - unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; - } - Err(err) => return Error::to_errno(err), - } + from_result(|| { + let data = T::probe(pdev, info)?; - 0 + pdev.as_ref().set_drvdata(data); + Ok(0) + }) } extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { // SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a // `struct pci_dev`. - let ptr = unsafe { bindings::pci_get_drvdata(pdev) }.cast(); + // + // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. + let pdev = unsafe { &*pdev.cast::>() }; // SAFETY: `remove_callback` is only ever called after a successful call to - // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized - // `KBox` pointer created through `KBox::into_foreign`. - let _ = unsafe { KBox::::from_foreign(ptr) }; + // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called + // and stored a `Pin>`. + let _ = unsafe { pdev.as_ref().drvdata_obtain::>>() }; } } From c46f60246f9ae372ecc1f10976a8af3914b3f79e Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:31 +0200 Subject: [PATCH 45/84] rust: auxiliary: use generic device drvdata accessors Take advantage of the generic drvdata accessors of the generic Device type. While at it, use from_result() instead of match. Link: https://lore.kernel.org/r/20250621195118.124245-6-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/helpers/auxiliary.c | 10 ---------- rust/kernel/auxiliary.rs | 35 +++++++++++++++-------------------- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/rust/helpers/auxiliary.c b/rust/helpers/auxiliary.c index 0db3860d774e..8b5e0fea4493 100644 --- a/rust/helpers/auxiliary.c +++ b/rust/helpers/auxiliary.c @@ -2,16 +2,6 @@ #include -void rust_helper_auxiliary_set_drvdata(struct auxiliary_device *adev, void *data) -{ - auxiliary_set_drvdata(adev, data); -} - -void *rust_helper_auxiliary_get_drvdata(struct auxiliary_device *adev) -{ - return auxiliary_get_drvdata(adev); -} - void rust_helper_auxiliary_device_uninit(struct auxiliary_device *adev) { return auxiliary_device_uninit(adev); diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 4fe62bbf8b3a..2985673181b7 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -8,9 +8,9 @@ bindings, container_of, device, device_id::RawDeviceId, driver, - error::{to_result, Result}, + error::{from_result, to_result, Result}, prelude::*, - types::{ForeignOwnable, Opaque}, + types::Opaque, ThisModule, }; use core::{ @@ -60,37 +60,32 @@ extern "C" fn probe_callback( // `struct auxiliary_device`. // // INVARIANT: `adev` is valid for the duration of `probe_callback()`. - let adev = unsafe { &*adev.cast::>() }; + let adev = unsafe { &*adev.cast::>() }; // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` // and does not add additional invariants, so it's safe to transmute. let id = unsafe { &*id.cast::() }; let info = T::ID_TABLE.info(id.index()); - match T::probe(adev, info) { - Ok(data) => { - // Let the `struct auxiliary_device` own a reference of the driver's private data. - // SAFETY: By the type invariant `adev.as_raw` returns a valid pointer to a - // `struct auxiliary_device`. - unsafe { - bindings::auxiliary_set_drvdata(adev.as_raw(), data.into_foreign().cast()) - }; - } - Err(err) => return Error::to_errno(err), - } + from_result(|| { + let data = T::probe(adev, info)?; - 0 + adev.as_ref().set_drvdata(data); + Ok(0) + }) } extern "C" fn remove_callback(adev: *mut bindings::auxiliary_device) { - // SAFETY: The auxiliary bus only ever calls the remove callback with a valid pointer to a + // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a // `struct auxiliary_device`. - let ptr = unsafe { bindings::auxiliary_get_drvdata(adev) }; + // + // INVARIANT: `adev` is valid for the duration of `probe_callback()`. + let adev = unsafe { &*adev.cast::>() }; // SAFETY: `remove_callback` is only ever called after a successful call to - // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized - // `KBox` pointer created through `KBox::into_foreign`. - drop(unsafe { KBox::::from_foreign(ptr.cast()) }); + // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called + // and stored a `Pin>`. + drop(unsafe { adev.as_ref().drvdata_obtain::>>() }); } } From 4be5f3fff151e49b0e7a82d33d4d12e91840abde Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:32 +0200 Subject: [PATCH 46/84] rust: platform: implement Driver::unbind() Currently, there's really only one core callback for drivers, which is probe(). Now, this isn't entirely true, since there is also the drop() callback of the driver type (serving as the driver's private data), which is returned by probe() and is dropped in remove(). On the C side remove() mainly serves two purposes: (1) Tear down the device that is operated by the driver, e.g. call bus specific functions, write I/O memory to reset the device, etc. (2) Free the resources that have been allocated by a driver for a specific device. The drop() callback mentioned above is intended to cover (2) as the Rust idiomatic way. However, it is partially insufficient and inefficient to cover (1) properly, since drop() can't be called with additional arguments, such as the reference to the corresponding device that has the correct device context, i.e. the Core device context. This makes it inefficient (but not impossible) to access device resources, e.g. to write device registers, and impossible to call device methods, which are only accessible under the Core device context. In order to solve this, add an additional callback for (1), which we call unbind(). The reason for calling it unbind() is that, unlike remove(), it is *only* meant to be used to perform teardown operations on the device (1), but *not* to release resources (2). Link: https://lore.kernel.org/r/20250621195118.124245-7-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index e9e95c5bb02b..ced43367d900 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -87,7 +87,9 @@ extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let _ = unsafe { pdev.as_ref().drvdata_obtain::>>() }; + let data = unsafe { pdev.as_ref().drvdata_obtain::>>() }; + + T::unbind(pdev, data.as_ref()); } } @@ -186,6 +188,20 @@ pub trait Driver: Send { /// Implementers should attempt to initialize the device here. fn probe(dev: &Device, id_info: Option<&Self::IdInfo>) -> Result>>; + + /// Platform driver unbind. + /// + /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown operations that require a + /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be performed in `Self::drop`. + fn unbind(dev: &Device, this: Pin<&Self>) { + let _ = (dev, this); + } } /// The platform device representation. From 18ebb25dfa18c09474fed78b20808fa445370666 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:33 +0200 Subject: [PATCH 47/84] rust: pci: implement Driver::unbind() Currently, there's really only one core callback for drivers, which is probe(). Now, this isn't entirely true, since there is also the drop() callback of the driver type (serving as the driver's private data), which is returned by probe() and is dropped in remove(). On the C side remove() mainly serves two purposes: (1) Tear down the device that is operated by the driver, e.g. call bus specific functions, write I/O memory to reset the device, etc. (2) Free the resources that have been allocated by a driver for a specific device. The drop() callback mentioned above is intended to cover (2) as the Rust idiomatic way. However, it is partially insufficient and inefficient to cover (1) properly, since drop() can't be called with additional arguments, such as the reference to the corresponding device that has the correct device context, i.e. the Core device context. This makes it inefficient (but not impossible) to access device resources, e.g. to write device registers, and impossible to call device methods, which are only accessible under the Core device context. In order to solve this, add an additional callback for (1), which we call unbind(). The reason for calling it unbind() is that, unlike remove(), it is *only* meant to be used to perform teardown operations on the device (1), but *not* to release resources (2). Link: https://lore.kernel.org/r/20250621195118.124245-8-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 34f0db8054fe..8b884e324dcf 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -90,7 +90,9 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let _ = unsafe { pdev.as_ref().drvdata_obtain::>>() }; + let data = unsafe { pdev.as_ref().drvdata_obtain::>>() }; + + T::unbind(pdev, data.as_ref()); } } @@ -237,6 +239,20 @@ pub trait Driver: Send { /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. fn probe(dev: &Device, id_info: &Self::IdInfo) -> Result>>; + + /// Platform driver unbind. + /// + /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown operations that require a + /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be performed in `Self::drop`. + fn unbind(dev: &Device, this: Pin<&Self>) { + let _ = (dev, this); + } } /// The PCI device representation. From 5f512533b7aa780488c15e001791d1b8000ad50e Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:34 +0200 Subject: [PATCH 48/84] samples: rust: pci: reset pci-testdev in unbind() Reset the pci-testdev when the driver is unbound from its device. Link: https://lore.kernel.org/r/20250621195118.124245-9-dakr@kernel.org Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_pci.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 5c35f1414172..606946ff4d7f 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -18,7 +18,7 @@ impl Regs { type Bar0 = pci::Bar<{ Regs::END }>; -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] struct TestIndex(u8); impl TestIndex { @@ -30,6 +30,7 @@ struct SampleDriver { pdev: ARef, #[pin] bar: Devres, + index: TestIndex, } kernel::pci_device_table!( @@ -79,6 +80,7 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> Result try_pin_init!(Self { pdev: pdev.into(), bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")), + index: *info, }), GFP_KERNEL, )?; @@ -92,6 +94,13 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> Result Ok(drvdata) } + + fn unbind(pdev: &pci::Device, this: Pin<&Self>) { + if let Ok(bar) = this.bar.access(pdev.as_ref()) { + // Reset pci-testdev by writing a new test index. + bar.write8(this.index.0, Regs::TEST); + } + } } #[pinned_drop] From 327a206c0e1484b960e7804954d568bf80bad93c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:14:08 +0100 Subject: [PATCH 49/84] zynqmp: don't bother with debugfs_file_{get,put}() in proxied fops When debugfs file has been created by debugfs_create_file_unsafe(), we do need the file_operations methods to use debugfs_file_{get,put}() to prevent concurrent removal; for files created by debugfs_create_file() that is done in the wrappers that call underlying methods, so there's no point whatsoever duplicating that in the underlying methods themselves. Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250702211408.GA3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 38 ++++---------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 238cbb49963e..197defe4f928 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1869,20 +1869,14 @@ static int zynqmp_dp_test_setup(struct zynqmp_dp *dp) static ssize_t zynqmp_dp_pattern_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct dentry *dentry = file->f_path.dentry; struct zynqmp_dp *dp = file->private_data; char buf[16]; ssize_t ret; - ret = debugfs_file_get(dentry); - if (unlikely(ret)) - return ret; - scoped_guard(mutex, &dp->lock) ret = snprintf(buf, sizeof(buf), "%s\n", test_pattern_str[dp->test.pattern]); - debugfs_file_put(dentry); return simple_read_from_buffer(user_buf, count, ppos, buf, ret); } @@ -1890,27 +1884,20 @@ static ssize_t zynqmp_dp_pattern_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct dentry *dentry = file->f_path.dentry; struct zynqmp_dp *dp = file->private_data; char buf[16]; ssize_t ret; int pattern; - ret = debugfs_file_get(dentry); - if (unlikely(ret)) - return ret; - ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); if (ret < 0) - goto out; + return ret; buf[ret] = '\0'; pattern = sysfs_match_string(test_pattern_str, buf); - if (pattern < 0) { - ret = -EINVAL; - goto out; - } + if (pattern < 0) + return -EINVAL; mutex_lock(&dp->lock); dp->test.pattern = pattern; @@ -1919,8 +1906,6 @@ static ssize_t zynqmp_dp_pattern_write(struct file *file, dp->test.custom) ?: ret; mutex_unlock(&dp->lock); -out: - debugfs_file_put(dentry); return ret; } @@ -2026,20 +2011,13 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_active, zynqmp_dp_active_get, static ssize_t zynqmp_dp_custom_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct dentry *dentry = file->f_path.dentry; struct zynqmp_dp *dp = file->private_data; ssize_t ret; - ret = debugfs_file_get(dentry); - if (unlikely(ret)) - return ret; - mutex_lock(&dp->lock); ret = simple_read_from_buffer(user_buf, count, ppos, &dp->test.custom, sizeof(dp->test.custom)); mutex_unlock(&dp->lock); - - debugfs_file_put(dentry); return ret; } @@ -2047,18 +2025,13 @@ static ssize_t zynqmp_dp_custom_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct dentry *dentry = file->f_path.dentry; struct zynqmp_dp *dp = file->private_data; ssize_t ret; char buf[sizeof(dp->test.custom)]; - ret = debugfs_file_get(dentry); - if (unlikely(ret)) - return ret; - ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count); if (ret < 0) - goto out; + return ret; mutex_lock(&dp->lock); memcpy(dp->test.custom, buf, ret); @@ -2066,9 +2039,6 @@ static ssize_t zynqmp_dp_custom_write(struct file *file, ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, dp->test.custom) ?: ret; mutex_unlock(&dp->lock); - -out: - debugfs_file_put(dentry); return ret; } From 2b4b80cfcf25e613148a2cd6b273b200b0064b40 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:15:08 +0100 Subject: [PATCH 50/84] hfi1: get rid of redundant debugfs_file_{get,put}() All files in question are created via debugfs_create_file(), so exclusion with removals is provided by debugfs wrappers; as the matter of fact, hfi1-private wrappers had been redundant at least since 2017... Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250702211508.GB3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/debugfs.c | 28 ---------------------------- drivers/infiniband/hw/hfi1/debugfs.h | 9 ++------- drivers/infiniband/hw/hfi1/fault.c | 9 --------- 3 files changed, 2 insertions(+), 44 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c index a1e01b447265..ac37ab7f8995 100644 --- a/drivers/infiniband/hw/hfi1/debugfs.c +++ b/drivers/infiniband/hw/hfi1/debugfs.c @@ -22,34 +22,6 @@ static struct dentry *hfi1_dbg_root; -/* wrappers to enforce srcu in seq file */ -ssize_t hfi1_seq_read(struct file *file, char __user *buf, size_t size, - loff_t *ppos) -{ - struct dentry *d = file->f_path.dentry; - ssize_t r; - - r = debugfs_file_get(d); - if (unlikely(r)) - return r; - r = seq_read(file, buf, size, ppos); - debugfs_file_put(d); - return r; -} - -loff_t hfi1_seq_lseek(struct file *file, loff_t offset, int whence) -{ - struct dentry *d = file->f_path.dentry; - loff_t r; - - r = debugfs_file_get(d); - if (unlikely(r)) - return r; - r = seq_lseek(file, offset, whence); - debugfs_file_put(d); - return r; -} - #define private2dd(file) (file_inode(file)->i_private) #define private2ppd(file) (file_inode(file)->i_private) diff --git a/drivers/infiniband/hw/hfi1/debugfs.h b/drivers/infiniband/hw/hfi1/debugfs.h index 54d952a4016c..65b48839abc6 100644 --- a/drivers/infiniband/hw/hfi1/debugfs.h +++ b/drivers/infiniband/hw/hfi1/debugfs.h @@ -33,16 +33,11 @@ static int _##name##_open(struct inode *inode, struct file *s) \ static const struct file_operations _##name##_file_ops = { \ .owner = THIS_MODULE, \ .open = _##name##_open, \ - .read = hfi1_seq_read, \ - .llseek = hfi1_seq_lseek, \ + .read = seq_read, \ + .llseek = seq_lseek, \ .release = seq_release \ } - -ssize_t hfi1_seq_read(struct file *file, char __user *buf, size_t size, - loff_t *ppos); -loff_t hfi1_seq_lseek(struct file *file, loff_t offset, int whence); - #ifdef CONFIG_DEBUG_FS void hfi1_dbg_ibdev_init(struct hfi1_ibdev *ibd); void hfi1_dbg_ibdev_exit(struct hfi1_ibdev *ibd); diff --git a/drivers/infiniband/hw/hfi1/fault.c b/drivers/infiniband/hw/hfi1/fault.c index ec9ee59fcf0c..a45cbffd52c7 100644 --- a/drivers/infiniband/hw/hfi1/fault.c +++ b/drivers/infiniband/hw/hfi1/fault.c @@ -104,9 +104,6 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf, goto free_data; } - ret = debugfs_file_get(file->f_path.dentry); - if (unlikely(ret)) - goto free_data; ptr = data; token = ptr; for (ptr = data; *ptr; ptr = end + 1, token = ptr) { @@ -154,7 +151,6 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf, } ret = len; - debugfs_file_put(file->f_path.dentry); free_data: kfree(data); return ret; @@ -173,9 +169,6 @@ static ssize_t fault_opcodes_read(struct file *file, char __user *buf, data = kcalloc(datalen, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - ret = debugfs_file_get(file->f_path.dentry); - if (unlikely(ret)) - goto free_data; bit = find_first_bit(fault->opcodes, bitsize); while (bit < bitsize) { zero = find_next_zero_bit(fault->opcodes, bitsize, bit); @@ -189,11 +182,9 @@ static ssize_t fault_opcodes_read(struct file *file, char __user *buf, bit); bit = find_next_bit(fault->opcodes, bitsize, zero); } - debugfs_file_put(file->f_path.dentry); data[size - 1] = '\n'; data[size] = '\0'; ret = simple_read_from_buffer(buf, len, pos, data, size); -free_data: kfree(data); return ret; } From 8009fb751d2c355b4fb83ca158c6b75590d3a3c1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:16:02 +0100 Subject: [PATCH 51/84] regmap: get rid of redundant debugfs_file_{get,put}() pointless in ->read()/->write() of file_operations used only via debugfs_create_file() Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250702211602.GC3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- drivers/base/regmap/regmap-debugfs.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index fb84cda92a75..c9b4c04b1cf6 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -470,10 +470,6 @@ static ssize_t regmap_cache_only_write_file(struct file *file, if (err) return count; - err = debugfs_file_get(file->f_path.dentry); - if (err) - return err; - map->lock(map->lock_arg); if (new_val && !map->cache_only) { @@ -486,7 +482,6 @@ static ssize_t regmap_cache_only_write_file(struct file *file, map->cache_only = new_val; map->unlock(map->lock_arg); - debugfs_file_put(file->f_path.dentry); if (require_sync) { err = regcache_sync(map); @@ -517,10 +512,6 @@ static ssize_t regmap_cache_bypass_write_file(struct file *file, if (err) return count; - err = debugfs_file_get(file->f_path.dentry); - if (err) - return err; - map->lock(map->lock_arg); if (new_val && !map->cache_bypass) { @@ -532,7 +523,6 @@ static ssize_t regmap_cache_bypass_write_file(struct file *file, map->cache_bypass = new_val; map->unlock(map->lock_arg); - debugfs_file_put(file->f_path.dentry); return count; } From 460e36ee6f84c2df4d194ee788e3ca116e8c563b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:16:50 +0100 Subject: [PATCH 52/84] resctrl: get rid of pointless debugfs_file_{get,put}() ->write() of file_operations that gets used only via debugfs_create_file() is called only under debugfs_file_get() Signed-off-by: Al Viro Acked-by: Reinette Chatre Link: https://lore.kernel.org/r/20250702211650.GD3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- fs/resctrl/pseudo_lock.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c index ccc2f9213b4b..87bbc2605de1 100644 --- a/fs/resctrl/pseudo_lock.c +++ b/fs/resctrl/pseudo_lock.c @@ -764,13 +764,9 @@ static ssize_t pseudo_lock_measure_trigger(struct file *file, if (ret == 0) { if (sel != 1 && sel != 2 && sel != 3) return -EINVAL; - ret = debugfs_file_get(file->f_path.dentry); - if (ret) - return ret; ret = pseudo_lock_measure_cycles(rdtgrp, sel); if (ret == 0) ret = count; - debugfs_file_put(file->f_path.dentry); } return ret; From a7694ff11aa9d97d0f690351a964544849e5158d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:17:39 +0100 Subject: [PATCH 53/84] vmscan: don't bother with debugfs_real_fops() ... not when it's used only to check which file is used; debugfs_create_file_aux_num() allows to stash a number into debugfs entry and debugfs_get_aux_num() extracts it. Signed-off-by: Al Viro Braino-spotted-by: Matthew Wilcox Link: https://lore.kernel.org/r/20250702211739.GE3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index f8dfd2864bbf..0e661672cbb9 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -5420,7 +5420,7 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, static int lru_gen_seq_show(struct seq_file *m, void *v) { unsigned long seq; - bool full = !debugfs_real_fops(m->file)->write; + bool full = debugfs_get_aux_num(m->file); struct lruvec *lruvec = v; struct lru_gen_folio *lrugen = &lruvec->lrugen; int nid = lruvec_pgdat(lruvec)->node_id; @@ -5756,8 +5756,10 @@ static int __init init_lru_gen(void) if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) pr_err("lru_gen: failed to create sysfs group\n"); - debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); - debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); + debugfs_create_file_aux_num("lru_gen", 0644, NULL, NULL, 1, + &lru_gen_rw_fops); + debugfs_create_file_aux_num("lru_gen_full", 0444, NULL, NULL, 0, + &lru_gen_ro_fops); return 0; }; From 1c1ec6f00e20296a9db044977dafaada070c581f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:22:05 +0100 Subject: [PATCH 54/84] netronome: don't bother with debugfs_real_fops() Just turn nfp_tx_q_show() into a wrapper for helper that gets told whether it's tx or xdp via an explicit argument and have nfp_xdp_q_show() call the underlying helper instead. Signed-off-by: Al Viro Reviewed-by: Louis Peens Link: https://lore.kernel.org/r/20250702212205.GF3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/netronome/nfp/nfp_net_debugfs.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index d8b735ccf899..d843d1e19715 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -77,7 +77,7 @@ DEFINE_SHOW_ATTRIBUTE(nfp_rx_q); static int nfp_tx_q_show(struct seq_file *file, void *data); DEFINE_SHOW_ATTRIBUTE(nfp_tx_q); -static int nfp_tx_q_show(struct seq_file *file, void *data) +static int __nfp_tx_q_show(struct seq_file *file, void *data, bool is_xdp) { struct nfp_net_r_vector *r_vec = file->private; struct nfp_net_tx_ring *tx_ring; @@ -86,10 +86,10 @@ static int nfp_tx_q_show(struct seq_file *file, void *data) rtnl_lock(); - if (debugfs_real_fops(file->file) == &nfp_tx_q_fops) - tx_ring = r_vec->tx_ring; - else + if (is_xdp) tx_ring = r_vec->xdp_ring; + else + tx_ring = r_vec->tx_ring; if (!r_vec->nfp_net || !tx_ring) goto out; nn = r_vec->nfp_net; @@ -115,9 +115,14 @@ static int nfp_tx_q_show(struct seq_file *file, void *data) return 0; } +static int nfp_tx_q_show(struct seq_file *file, void *data) +{ + return __nfp_tx_q_show(file, data, false); +} + static int nfp_xdp_q_show(struct seq_file *file, void *data) { - return nfp_tx_q_show(file, data); + return __nfp_tx_q_show(file, data, true); } DEFINE_SHOW_ATTRIBUTE(nfp_xdp_q); From d9bc88aa54d6aa22ff1e850a86be7a37f0503889 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:24:19 +0100 Subject: [PATCH 55/84] debugfs: split short and full proxy wrappers, kill debugfs_real_fops() All users outside of fs/debugfs/file.c are gone, in there we can just fully split the wrappers for full and short cases and be done with that. Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250702212419.GG3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- fs/debugfs/file.c | 87 ++++++++++++++++++----------------------- include/linux/debugfs.h | 2 - 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 69e9ddcb113d..77784091a10f 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -53,23 +53,6 @@ const void *debugfs_get_aux(const struct file *file) } EXPORT_SYMBOL_GPL(debugfs_get_aux); -const struct file_operations *debugfs_real_fops(const struct file *filp) -{ - struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; - - if (!fsd) { - /* - * Urgh, we've been called w/o a protecting - * debugfs_file_get(). - */ - WARN_ON(1); - return NULL; - } - - return fsd->real_fops; -} -EXPORT_SYMBOL_GPL(debugfs_real_fops); - enum dbgfs_get_mode { DBGFS_GET_ALREADY, DBGFS_GET_REGULAR, @@ -302,15 +285,13 @@ static int debugfs_locked_down(struct inode *inode, static int open_proxy_open(struct inode *inode, struct file *filp) { struct dentry *dentry = F_DENTRY(filp); - const struct file_operations *real_fops = NULL; + const struct file_operations *real_fops = DEBUGFS_I(inode)->real_fops; int r; r = __debugfs_file_get(dentry, DBGFS_GET_REGULAR); if (r) return r == -EIO ? -ENOENT : r; - real_fops = debugfs_real_fops(filp); - r = debugfs_locked_down(inode, filp, real_fops); if (r) goto out; @@ -352,7 +333,6 @@ static ret_type full_proxy_ ## name(proto) \ { \ struct dentry *dentry = F_DENTRY(filp); \ struct debugfs_fsdata *fsd = dentry->d_fsdata; \ - const struct file_operations *real_fops; \ ret_type r; \ \ if (!(fsd->methods & bit)) \ @@ -360,14 +340,13 @@ static ret_type full_proxy_ ## name(proto) \ r = debugfs_file_get(dentry); \ if (unlikely(r)) \ return r; \ - real_fops = debugfs_real_fops(filp); \ - r = real_fops->name(args); \ + r = fsd->real_fops->name(args); \ debugfs_file_put(dentry); \ return r; \ } -#define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args, bit, ret) \ -static ret_type full_proxy_ ## name(proto) \ +#define SHORT_PROXY_FUNC(name, ret_type, filp, proto, args, bit, ret) \ +static ret_type short_proxy_ ## name(proto) \ { \ struct dentry *dentry = F_DENTRY(filp); \ struct debugfs_fsdata *fsd = dentry->d_fsdata; \ @@ -378,27 +357,38 @@ static ret_type full_proxy_ ## name(proto) \ r = debugfs_file_get(dentry); \ if (unlikely(r)) \ return r; \ - if (fsd->real_fops) \ - r = fsd->real_fops->name(args); \ - else \ - r = fsd->short_fops->name(args); \ + r = fsd->short_fops->name(args); \ debugfs_file_put(dentry); \ return r; \ } -FULL_PROXY_FUNC_BOTH(llseek, loff_t, filp, - PROTO(struct file *filp, loff_t offset, int whence), - ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); +SHORT_PROXY_FUNC(llseek, loff_t, filp, + PROTO(struct file *filp, loff_t offset, int whence), + ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); -FULL_PROXY_FUNC_BOTH(read, ssize_t, filp, - PROTO(struct file *filp, char __user *buf, size_t size, - loff_t *ppos), - ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); +FULL_PROXY_FUNC(llseek, loff_t, filp, + PROTO(struct file *filp, loff_t offset, int whence), + ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); -FULL_PROXY_FUNC_BOTH(write, ssize_t, filp, - PROTO(struct file *filp, const char __user *buf, - size_t size, loff_t *ppos), - ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); +SHORT_PROXY_FUNC(read, ssize_t, filp, + PROTO(struct file *filp, char __user *buf, size_t size, + loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); + +FULL_PROXY_FUNC(read, ssize_t, filp, + PROTO(struct file *filp, char __user *buf, size_t size, + loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); + +SHORT_PROXY_FUNC(write, ssize_t, filp, + PROTO(struct file *filp, const char __user *buf, + size_t size, loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); + +FULL_PROXY_FUNC(write, ssize_t, filp, + PROTO(struct file *filp, const char __user *buf, + size_t size, loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); FULL_PROXY_FUNC(unlocked_ioctl, long, filp, PROTO(struct file *filp, unsigned int cmd, unsigned long arg), @@ -410,22 +400,21 @@ static __poll_t full_proxy_poll(struct file *filp, struct dentry *dentry = F_DENTRY(filp); struct debugfs_fsdata *fsd = dentry->d_fsdata; __poll_t r = 0; - const struct file_operations *real_fops; if (!(fsd->methods & HAS_POLL)) return DEFAULT_POLLMASK; if (debugfs_file_get(dentry)) return EPOLLHUP; - real_fops = debugfs_real_fops(filp); - r = real_fops->poll(filp, wait); + r = fsd->real_fops->poll(filp, wait); debugfs_file_put(dentry); return r; } -static int full_proxy_release(struct inode *inode, struct file *filp) +static int full_proxy_release(struct inode *inode, struct file *file) { - const struct file_operations *real_fops = debugfs_real_fops(filp); + struct debugfs_fsdata *fsd = F_DENTRY(file)->d_fsdata; + const struct file_operations *real_fops = fsd->real_fops; int r = 0; /* @@ -435,7 +424,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp) * ->i_private is still being meaningful here. */ if (real_fops->release) - r = real_fops->release(inode, filp); + r = real_fops->release(inode, file); fops_put(real_fops); return r; @@ -517,9 +506,9 @@ static int full_proxy_open_short(struct inode *inode, struct file *filp) const struct file_operations debugfs_full_short_proxy_file_operations = { .open = full_proxy_open_short, - .llseek = full_proxy_llseek, - .read = full_proxy_read, - .write = full_proxy_write, + .llseek = short_proxy_llseek, + .read = short_proxy_read, + .write = short_proxy_write, }; ssize_t debugfs_attr_read(struct file *file, char __user *buf, diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index fa2568b4380d..a420152105d0 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -162,7 +162,6 @@ void debugfs_remove(struct dentry *dentry); void debugfs_lookup_and_remove(const char *name, struct dentry *parent); -const struct file_operations *debugfs_real_fops(const struct file *filp); const void *debugfs_get_aux(const struct file *file); int debugfs_file_get(struct dentry *dentry); @@ -329,7 +328,6 @@ static inline void debugfs_lookup_and_remove(const char *name, struct dentry *parent) { } -const struct file_operations *debugfs_real_fops(const struct file *filp); void *debugfs_get_aux(const struct file *file); static inline int debugfs_file_get(struct dentry *dentry) From 00bbe512e60f681aef132f0dd2c92eb6521acef1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:25:42 +0100 Subject: [PATCH 56/84] fix tt_command_write() 1) unbalanced debugfs_file_get(). Not needed in the first place - file_operations are accessed only via debugfs_create_file(), so debugfs wrappers will take care of that itself. 2) kmalloc() for a buffer used only for duration of a function is not a problem, but for a buffer no longer than 16 bytes? 3) strstr() is for finding substrings; for finding a character there's strchr(). Signed-off-by: Al Viro Acked-by: "Rafael J. Wysocki" Link: https://lore.kernel.org/r/20250702212542.GH3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/testing/command.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/thermal/testing/command.c b/drivers/thermal/testing/command.c index ba11d70e8021..1159ecea57e7 100644 --- a/drivers/thermal/testing/command.c +++ b/drivers/thermal/testing/command.c @@ -139,31 +139,21 @@ static int tt_command_exec(int index, const char *arg) return ret; } -static ssize_t tt_command_process(struct dentry *dentry, const char __user *user_buf, - size_t count) +static ssize_t tt_command_process(char *s) { - char *buf __free(kfree); char *arg; int i; - buf = kmalloc(count + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; + strim(s); - if (copy_from_user(buf, user_buf, count)) - return -EFAULT; - - buf[count] = '\0'; - strim(buf); - - arg = strstr(buf, ":"); + arg = strchr(s, ':'); if (arg) { *arg = '\0'; arg++; } for (i = 0; i < ARRAY_SIZE(tt_command_strings); i++) { - if (!strcmp(buf, tt_command_strings[i])) + if (!strcmp(s, tt_command_strings[i])) return tt_command_exec(i, arg); } @@ -173,20 +163,20 @@ static ssize_t tt_command_process(struct dentry *dentry, const char __user *user static ssize_t tt_command_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct dentry *dentry = file->f_path.dentry; + char buf[TT_COMMAND_SIZE]; ssize_t ret; if (*ppos) return -EINVAL; - if (count + 1 > TT_COMMAND_SIZE) + if (count > TT_COMMAND_SIZE - 1) return -E2BIG; - ret = debugfs_file_get(dentry); - if (unlikely(ret)) - return ret; + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + buf[count] = '\0'; - ret = tt_command_process(dentry, user_buf, count); + ret = tt_command_process(buf); if (ret) return ret; From 9d3b96be2ee81a7d6ad08cb5094753f06382db1b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:26:16 +0100 Subject: [PATCH 57/84] debugfs_get_aux(): allow storing non-const void * typechecking is up to users, anyway... Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250702212616.GI3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/camera.c | 2 +- fs/debugfs/file.c | 2 +- fs/debugfs/inode.c | 2 +- fs/debugfs/internal.h | 2 +- include/linux/debugfs.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index ec9fddfc0b14..5ac19c0055d9 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1128,7 +1128,7 @@ static ssize_t gb_camera_debugfs_write(struct file *file, static int gb_camera_debugfs_open(struct inode *inode, struct file *file) { - file->private_data = (void *)debugfs_get_aux(file); + file->private_data = debugfs_get_aux(file); return 0; } diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 77784091a10f..3ec3324c2060 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -47,7 +47,7 @@ const struct file_operations debugfs_noop_file_operations = { #define F_DENTRY(filp) ((filp)->f_path.dentry) -const void *debugfs_get_aux(const struct file *file) +void *debugfs_get_aux(const struct file *file) { return DEBUGFS_I(file_inode(file))->aux; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 30c4944e1862..43e5d1bf1f32 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -459,7 +459,7 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, proxy_fops = &debugfs_noop_file_operations; inode->i_fop = proxy_fops; DEBUGFS_I(inode)->raw = real_fops; - DEBUGFS_I(inode)->aux = aux; + DEBUGFS_I(inode)->aux = (void *)aux; d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 93483fe84425..427987f81571 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -19,7 +19,7 @@ struct debugfs_inode_info { const struct debugfs_short_fops *short_fops; debugfs_automount_t automount; }; - const void *aux; + void *aux; }; static inline struct debugfs_inode_info *DEBUGFS_I(struct inode *inode) diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index a420152105d0..7cecda29447e 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -162,7 +162,7 @@ void debugfs_remove(struct dentry *dentry); void debugfs_lookup_and_remove(const char *name, struct dentry *parent); -const void *debugfs_get_aux(const struct file *file); +void *debugfs_get_aux(const struct file *file); int debugfs_file_get(struct dentry *dentry); void debugfs_file_put(struct dentry *dentry); From 4c0727e56831cf3646c604131e2eea25c734c9eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jul 2025 22:28:18 +0100 Subject: [PATCH 58/84] blk-mq-debugfs: use debugfs_get_aux() instead of manually stashing the data pointer into parent directory inode's ->i_private, just pass it to debugfs_create_file_aux() so that it can be extracted without that insane chasing through ->d_parent. Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250702212818.GJ3406663@ZenIV Signed-off-by: Greg Kroah-Hartman --- block/blk-mq-debugfs.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index 29b3540dd180..7ed3e71f2fc0 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c @@ -521,7 +521,7 @@ CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL); static int blk_mq_debugfs_show(struct seq_file *m, void *v) { const struct blk_mq_debugfs_attr *attr = m->private; - void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; + void *data = debugfs_get_aux(m->file); return attr->show(data, m); } @@ -531,7 +531,7 @@ static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, { struct seq_file *m = file->private_data; const struct blk_mq_debugfs_attr *attr = m->private; - void *data = d_inode(file->f_path.dentry->d_parent)->i_private; + void *data = debugfs_get_aux(file); /* * Attributes that only implement .seq_ops are read-only and 'attr' is @@ -546,7 +546,7 @@ static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, static int blk_mq_debugfs_open(struct inode *inode, struct file *file) { const struct blk_mq_debugfs_attr *attr = inode->i_private; - void *data = d_inode(file->f_path.dentry->d_parent)->i_private; + void *data = debugfs_get_aux(file); struct seq_file *m; int ret; @@ -612,11 +612,9 @@ static void debugfs_create_files(struct dentry *parent, void *data, if (IS_ERR_OR_NULL(parent)) return; - d_inode(parent)->i_private = data; - for (; attr->name; attr++) - debugfs_create_file(attr->name, attr->mode, parent, - (void *)attr, &blk_mq_debugfs_fops); + debugfs_create_file_aux(attr->name, attr->mode, parent, + (void *)attr, data, &blk_mq_debugfs_fops); } void blk_mq_debugfs_register(struct request_queue *q) From 3964d07dd821efe9680e90c51c86661a98e60a0f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 8 Jul 2025 03:57:34 +0100 Subject: [PATCH 59/84] lpfc: don't use file->f_path.dentry for comparisons If you want a home-grown switch, at least use enum for selector... Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20250708025734.GT1880847@ZenIV Reviewed-by: Justin Tee Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_debugfs.c | 87 ++++++++++++++------------------ drivers/scsi/lpfc/lpfc_debugfs.h | 11 ++++ 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3fd1aa5cc78c..42d138ec11b4 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -2375,32 +2375,32 @@ static ssize_t lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - struct dentry *dent = file->f_path.dentry; struct lpfc_hba *phba = file->private_data; + int kind = debugfs_get_aux_num(file); char cbuf[32]; uint64_t tmp = 0; int cnt = 0; - if (dent == phba->debug_writeGuard) + if (kind == writeGuard) cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); - else if (dent == phba->debug_writeApp) + else if (kind == writeApp) cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); - else if (dent == phba->debug_writeRef) + else if (kind == writeRef) cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); - else if (dent == phba->debug_readGuard) + else if (kind == readGuard) cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); - else if (dent == phba->debug_readApp) + else if (kind == readApp) cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); - else if (dent == phba->debug_readRef) + else if (kind == readRef) cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); - else if (dent == phba->debug_InjErrNPortID) + else if (kind == InjErrNPortID) cnt = scnprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid); - else if (dent == phba->debug_InjErrWWPN) { + else if (kind == InjErrWWPN) { memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); tmp = cpu_to_be64(tmp); cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp); - } else if (dent == phba->debug_InjErrLBA) { + } else if (kind == InjErrLBA) { if (phba->lpfc_injerr_lba == (sector_t)(-1)) cnt = scnprintf(cbuf, 32, "off\n"); else @@ -2417,8 +2417,8 @@ static ssize_t lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { - struct dentry *dent = file->f_path.dentry; struct lpfc_hba *phba = file->private_data; + int kind = debugfs_get_aux_num(file); char dstbuf[33]; uint64_t tmp = 0; int size; @@ -2428,7 +2428,7 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, if (copy_from_user(dstbuf, buf, size)) return -EFAULT; - if (dent == phba->debug_InjErrLBA) { + if (kind == InjErrLBA) { if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') && (dstbuf[2] == 'f')) tmp = (uint64_t)(-1); @@ -2437,23 +2437,23 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) return -EINVAL; - if (dent == phba->debug_writeGuard) + if (kind == writeGuard) phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; - else if (dent == phba->debug_writeApp) + else if (kind == writeApp) phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp; - else if (dent == phba->debug_writeRef) + else if (kind == writeRef) phba->lpfc_injerr_wref_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readGuard) + else if (kind == readGuard) phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readApp) + else if (kind == readApp) phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readRef) + else if (kind == readRef) phba->lpfc_injerr_rref_cnt = (uint32_t)tmp; - else if (dent == phba->debug_InjErrLBA) + else if (kind == InjErrLBA) phba->lpfc_injerr_lba = (sector_t)tmp; - else if (dent == phba->debug_InjErrNPortID) + else if (kind == InjErrNPortID) phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID); - else if (dent == phba->debug_InjErrWWPN) { + else if (kind == InjErrWWPN) { tmp = cpu_to_be64(tmp); memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name)); } else @@ -6160,60 +6160,51 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) phba->debug_dumpHostSlim = NULL; /* Setup DIF Error Injections */ - snprintf(name, sizeof(name), "InjErrLBA"); phba->debug_InjErrLBA = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("InjErrLBA", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, InjErrLBA, &lpfc_debugfs_op_dif_err); phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - snprintf(name, sizeof(name), "InjErrNPortID"); phba->debug_InjErrNPortID = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("InjErrNPortID", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, InjErrNPortID, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "InjErrWWPN"); phba->debug_InjErrWWPN = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("InjErrWWPN", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, InjErrWWPN, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "writeGuardInjErr"); phba->debug_writeGuard = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("writeGuardInjErr", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, writeGuard, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "writeAppInjErr"); phba->debug_writeApp = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("writeAppInjErr", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, writeApp, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "writeRefInjErr"); phba->debug_writeRef = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("writeRefInjErr", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, writeRef, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "readGuardInjErr"); phba->debug_readGuard = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("readGuardInjErr", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, readGuard, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "readAppInjErr"); phba->debug_readApp = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("readAppInjErr", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, readApp, &lpfc_debugfs_op_dif_err); - snprintf(name, sizeof(name), "readRefInjErr"); phba->debug_readRef = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + debugfs_create_file_aux_num("readRefInjErr", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); + phba, readRef, &lpfc_debugfs_op_dif_err); /* Setup slow ring trace */ if (lpfc_debugfs_max_slow_ring_trc) { diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 8d2e8d05bbc0..f319f3af0400 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -322,6 +322,17 @@ enum { * discovery */ #endif /* H_LPFC_DEBUG_FS */ +enum { + writeGuard = 1, + writeApp, + writeRef, + readGuard, + readApp, + readRef, + InjErrLBA, + InjErrNPortID, + InjErrWWPN, +}; /* * Driver debug utility routines outside of debugfs. The debug utility From 91ae26b06aab476bdd8b56cd99e127f029490330 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 14 Jul 2025 13:32:35 +0200 Subject: [PATCH 60/84] rust: devres: initialize Devres::inner::data last Users may want to access the Devres object from callbacks registered through the initialization of Devres::inner::data. For those accesses to be valid, Devres::inner::data must be initialized last [1]. Credit to Boqun for spotting this [2]. Link: https://lore.kernel.org/lkml/DBBPHO26CPBS.2OVI1OERCB2J5@kernel.org/ [1] Link: https://lore.kernel.org/lkml/aHSmxWeIy3L-AKIV@Mac.home/ [2] Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250714113712.22158-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index f43de3d77d61..ac5e5d94ee96 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -137,14 +137,10 @@ pub fn new<'a, E>( let callback = Self::devres_callback; try_pin_init!(&this in Self { - // INVARIANT: `inner` is properly initialized. - inner <- Opaque::pin_init(try_pin_init!(Inner { - data <- Revocable::new(data), - devm <- Completion::new(), - revoke <- Completion::new(), - })), + dev: dev.into(), callback, - dev: { + // INVARIANT: `inner` is properly initialized. + inner <- { // SAFETY: `this` is a valid pointer to uninitialized memory. let inner = unsafe { &raw mut (*this.as_ptr()).inner }; @@ -158,7 +154,11 @@ pub fn new<'a, E>( bindings::devm_add_action(dev.as_raw(), Some(callback), inner.cast()) })?; - dev.into() + Opaque::pin_init(try_pin_init!(Inner { + devm <- Completion::new(), + revoke <- Completion::new(), + data <- Revocable::new(data), + })) }, }) } From 85aa5b16fef7040213581df9ff093dae27bf8675 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sun, 13 Jul 2025 20:26:53 +0200 Subject: [PATCH 61/84] rust: devres: provide an accessor for the device Provide an accessor for the Device a Devres instance has been created with. For instance, this is useful when registrations want to provide a &Device for a scope that is protected by Devres. Suggested-by: Benno Lossin Acked-by: Greg Kroah-Hartman Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250713182737.64448-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index ac5e5d94ee96..152a89b78943 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -204,6 +204,11 @@ fn remove_action(&self) -> bool { } == 0) } + /// Return a reference of the [`Device`] this [`Devres`] instance has been created with. + pub fn device(&self) -> &Device { + &self.dev + } + /// Obtain `&'a T`, bypassing the [`Revocable`]. /// /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting From 47e6715bb7ea388a9a3a13d31918827ba3aa3f4a Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sun, 13 Jul 2025 20:26:54 +0200 Subject: [PATCH 62/84] rust: device: implement Device::as_bound() Provide an unsafe functions for abstractions to convert a regular &Device to a &Device. This is useful for registrations that provide certain guarantees for the scope of their callbacks, such as IRQs or certain class device registrations (e.g. PWM, miscdevice). Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250713182737.64448-2-dakr@kernel.org [ Remove unnecessary cast(). - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index d527ceef829e..b6b81546a0da 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -60,6 +60,25 @@ pub unsafe fn get_device(ptr: *mut bindings::device) -> ARef { // SAFETY: By the safety requirements ptr is valid unsafe { Self::as_ref(ptr) }.into() } + + /// Convert a [`&Device`](Device) into a [`&Device`](Device). + /// + /// # Safety + /// + /// The caller is responsible to ensure that the returned [`&Device`](Device) + /// only lives as long as it can be guaranteed that the [`Device`] is actually bound. + pub unsafe fn as_bound(&self) -> &Device { + let ptr = core::ptr::from_ref(self); + + // CAST: By the safety requirements the caller is responsible to guarantee that the + // returned reference only lives as long as the device is actually bound. + let ptr = ptr.cast(); + + // SAFETY: + // - `ptr` comes from `from_ref(self)` above, hence it's guaranteed to be valid. + // - Any valid `Device` pointer is also a valid pointer for `Device`. + unsafe { &*ptr } + } } impl Device { From 42573e4df8e2318fce6a711e0f9cafc9e3dc1483 Mon Sep 17 00:00:00 2001 From: Meng Shao Liu Date: Wed, 16 Jul 2025 14:46:28 +0800 Subject: [PATCH 63/84] samples/kobject: fix path comment The introductory comment still says the example creates /sys/kernel/kobject-example, but the code actually creates /sys/kernel/kobject_example. Update both comments to reflect the actual sysfs paths. Also, fix "tree"->"three" typo in kset-example.c. Signed-off-by: Meng Shao Liu Link: https://lore.kernel.org/r/5be61d284a1850f573658f1c105f0b6062e41332.1752646650.git.sau525@gmail.com Signed-off-by: Greg Kroah-Hartman --- samples/kobject/kobject-example.c | 2 +- samples/kobject/kset-example.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/kobject/kobject-example.c b/samples/kobject/kobject-example.c index c9c3db19799a..e6d7fc18e433 100644 --- a/samples/kobject/kobject-example.c +++ b/samples/kobject/kobject-example.c @@ -13,7 +13,7 @@ /* * This module shows how to create a simple subdirectory in sysfs called - * /sys/kernel/kobject-example In that directory, 3 files are created: + * /sys/kernel/kobject_example In that directory, 3 files are created: * "foo", "baz", and "bar". If an integer is written to these files, it can be * later read out of it. */ diff --git a/samples/kobject/kset-example.c b/samples/kobject/kset-example.c index 552d7e363539..579ce150217c 100644 --- a/samples/kobject/kset-example.c +++ b/samples/kobject/kset-example.c @@ -14,8 +14,8 @@ /* * This module shows how to create a kset in sysfs called - * /sys/kernel/kset-example - * Then tree kobjects are created and assigned to this kset, "foo", "baz", + * /sys/kernel/kset_example + * Then three kobjects are created and assigned to this kset, "foo", "baz", * and "bar". In those kobjects, attributes of the same name are also * created and if an integer is written to these files, it can be later * read out of it. From f751fe2a2acbe8cc20da35f118f589ac3b316b78 Mon Sep 17 00:00:00 2001 From: Meng Shao Liu Date: Wed, 16 Jul 2025 14:46:29 +0800 Subject: [PATCH 64/84] samples/kobject: make attribute_group const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The attr_group structures are allocated once and never modified at runtime. Also to match the const‑qualified parameter of sysfs_create_group(). Signed-off-by: Meng Shao Liu Link: https://lore.kernel.org/r/dc94227eaf337a2b92ab77dffa0da9f7f1f84c4e.1752646650.git.sau525@gmail.com Signed-off-by: Greg Kroah-Hartman --- samples/kobject/kobject-example.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/kobject/kobject-example.c b/samples/kobject/kobject-example.c index e6d7fc18e433..36d87ca0bee2 100644 --- a/samples/kobject/kobject-example.c +++ b/samples/kobject/kobject-example.c @@ -102,7 +102,7 @@ static struct attribute *attrs[] = { * created for the attributes with the directory being the name of the * attribute group. */ -static struct attribute_group attr_group = { +static const struct attribute_group attr_group = { .attrs = attrs, }; From 6beb4ec0f9fdff4c4c6eb8ed8654fe8396c2b6e0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 8 Jul 2025 10:46:54 +0200 Subject: [PATCH 65/84] driver core: auxiliary bus: fix OF node leak Make sure to drop the OF node reference taken when creating an auxiliary device using auxiliary_device_create() when the device is later released. Fixes: eaa0d30216c1 ("driver core: auxiliary bus: add device creation helpers") Cc: Jerome Brunet Signed-off-by: Johan Hovold Reviewed-by: Danilo Krummrich Reviewed-by: Jerome Brunet Link: https://lore.kernel.org/r/20250708084654.15145-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/auxiliary.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index dba7c8e13a53..6bdefebf3609 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -399,6 +399,7 @@ static void auxiliary_device_release(struct device *dev) { struct auxiliary_device *auxdev = to_auxiliary_dev(dev); + of_node_put(dev->of_node); kfree(auxdev); } @@ -435,6 +436,7 @@ struct auxiliary_device *auxiliary_device_create(struct device *dev, ret = auxiliary_device_init(auxdev); if (ret) { + of_node_put(auxdev->dev.of_node); kfree(auxdev); return NULL; } From 35cff7af7598b9eb143cc0556e5532e2ded3b61a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 20 May 2025 13:34:37 +0300 Subject: [PATCH 66/84] container_of: Document container_of() is not to be used in new code There is a warning in the kerneldoc documentation of container_of() that constness of its ptr argument is lost. While this is a valid suggestion container_of_const() should be used instead, the vast majority of new code still uses container_of(): $ git diff v6.13 v6.14|grep container_of\(|wc -l 646 $ git diff v6.13 v6.14|grep container_of_const|wc -l 9 Make an explicit recommendation to use container_of_const(). Signed-off-by: Sakari Ailus Link: https://lore.kernel.org/r/20250520103437.468691-1-sakari.ailus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/container_of.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/container_of.h b/include/linux/container_of.h index 713890c867be..1f6ebf27d962 100644 --- a/include/linux/container_of.h +++ b/include/linux/container_of.h @@ -14,6 +14,7 @@ * @member: the name of the member within the struct. * * WARNING: any const qualifier of @ptr is lost. + * Do not use container_of() in new code. */ #define container_of(ptr, type, member) ({ \ void *__mptr = (void *)(ptr); \ @@ -28,6 +29,8 @@ * @ptr: the pointer to the member * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. + * + * Always prefer container_of_const() instead of container_of() in new code. */ #define container_of_const(ptr, type, member) \ _Generic(ptr, \ From 6b585f4ce6e4cde967bffae4f6cd9066094967ac Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 11 Jul 2025 18:27:41 +0000 Subject: [PATCH 67/84] cacheinfo: Set cache 'id' based on DT data Use the minimum CPU h/w id of the CPUs associated with the cache for the cache 'id'. This will provide a stable id value for a given system. As we need to check all possible CPUs, we can't use the shared_cpu_map which is just online CPUs. As there's not a cache to CPUs mapping in DT, we have to walk all CPU nodes and then walk cache levels. The cache_id exposed to user-space has historically been 32 bits, and is too late to change. This value is parsed into a u32 by user-space libraries such as libvirt: https://github.com/libvirt/libvirt/blob/master/src/util/virresctrl.c#L1588 Give up on assigning cache-id's if a CPU h/w id greater than 32 bits is found. match_cache_node() does not make use of the __free() cleanup helpers because of_find_next_cache_node(prev) does not drop a reference to prev, and its too easy to accidentally drop the reference on cpu, which belongs to for_each_of_cpu_node(). Cc: "Rafael J. Wysocki" Signed-off-by: Rob Herring [ ben: converted to use the __free cleanup idiom ] Signed-off-by: Ben Horgan [ morse: Add checks to give up if a value larger than 32 bits is seen. ] Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Link: https://lore.kernel.org/r/20250711182743.30141-2-james.morse@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/cacheinfo.c | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index cf0d455209d7..4e2f60c85e74 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -183,6 +184,49 @@ static bool cache_node_is_unified(struct cacheinfo *this_leaf, return of_property_read_bool(np, "cache-unified"); } +static bool match_cache_node(struct device_node *cpu, + const struct device_node *cache_node) +{ + struct device_node *prev, *cache = of_find_next_cache_node(cpu); + + while (cache) { + if (cache == cache_node) { + of_node_put(cache); + return true; + } + + prev = cache; + cache = of_find_next_cache_node(cache); + of_node_put(prev); + } + + return false; +} + +static void cache_of_set_id(struct cacheinfo *this_leaf, + struct device_node *cache_node) +{ + struct device_node *cpu; + u32 min_id = ~0; + + for_each_of_cpu_node(cpu) { + u64 id = of_get_cpu_hwid(cpu, 0); + + if (FIELD_GET(GENMASK_ULL(63, 32), id)) { + of_node_put(cpu); + return; + } + + if (match_cache_node(cpu, cache_node)) + min_id = min(min_id, id); + } + + if (min_id != ~0) { + this_leaf->id = min_id; + this_leaf->attributes |= CACHE_ID; + } +} + static void cache_of_set_props(struct cacheinfo *this_leaf, struct device_node *np) { @@ -198,6 +242,7 @@ static void cache_of_set_props(struct cacheinfo *this_leaf, cache_get_line_size(this_leaf, np); cache_nr_sets(this_leaf, np); cache_associativity(this_leaf); + cache_of_set_id(this_leaf, np); } static int cache_setup_of_node(unsigned int cpu) From 9a697eff25c97dd11877de04fd1be60af32d6d2d Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 11 Jul 2025 18:27:42 +0000 Subject: [PATCH 68/84] cacheinfo: Add arch hook to compress CPU h/w id into 32 bits for cache-id Filesystems like resctrl use the cache-id exposed via sysfs to identify groups of CPUs. The value is also used for PCIe cache steering tags. On DT platforms cache-id is not something that is described in the device-tree, but instead generated from the smallest CPU h/w id of the CPUs associated with that cache. CPU h/w ids may be larger than 32 bits. Add a hook to allow architectures to compress the value from the devicetree into 32 bits. Returning the same value is always safe as cache_of_set_id() will stop if a value larger than 32 bits is seen. For example, on arm64 the value is the MPIDR affinity register, which only has 32 bits of affinity data, but spread accross the 64 bit field. An arch-specific bit swizzle gives a 32 bit value. Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Link: https://lore.kernel.org/r/20250711182743.30141-3-james.morse@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/cacheinfo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 4e2f60c85e74..613410705a47 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -203,6 +203,10 @@ static bool match_cache_node(struct device_node *cpu, return false; } +#ifndef arch_compact_of_hwid +#define arch_compact_of_hwid(_x) (_x) +#endif + static void cache_of_set_id(struct cacheinfo *this_leaf, struct device_node *cache_node) { @@ -212,6 +216,7 @@ static void cache_of_set_id(struct cacheinfo *this_leaf, for_each_of_cpu_node(cpu) { u64 id = of_get_cpu_hwid(cpu, 0); + id = arch_compact_of_hwid(id); if (FIELD_GET(GENMASK_ULL(63, 32), id)) { of_node_put(cpu); return; From cbf218627d6a5092e653942baa261a10d1444798 Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 11 Jul 2025 18:27:43 +0000 Subject: [PATCH 69/84] arm64: cacheinfo: Provide helper to compress MPIDR value into u32 Filesystems like resctrl use the cache-id exposed via sysfs to identify groups of CPUs. The value is also used for PCIe cache steering tags. On DT platforms cache-id is not something that is described in the device-tree, but instead generated from the smallest MPIDR of the CPUs associated with that cache. The cache-id exposed to user-space has historically been 32 bits. MPIDR values may be larger than 32 bits. MPIDR only has 32 bits worth of affinity data, but the aff3 field lives above 32bits. The corresponding lower bits are masked out by MPIDR_HWID_BITMASK and contain an SMT flag and Uni-Processor flag. Swizzzle the aff3 field into the bottom 32 bits and using that. In case more affinity fields are added in the future, the upper RES0 area should be checked. Returning a value greater than 32 bits from this helper will cause the caller to give up on allocating cache-ids. Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Link: https://lore.kernel.org/r/20250711182743.30141-4-james.morse@arm.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cache.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index 99cd6546e72e..09963004ceea 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -87,6 +87,23 @@ int cache_line_size(void); #define dma_get_cache_alignment cache_line_size +/* Compress a u64 MPIDR value into 32 bits. */ +static inline u64 arch_compact_of_hwid(u64 id) +{ + u64 aff3 = MPIDR_AFFINITY_LEVEL(id, 3); + + /* + * These bits are expected to be RES0. If not, return a value with + * the upper 32 bits set to force the caller to give up on 32 bit + * cache ids. + */ + if (FIELD_GET(GENMASK_ULL(63, 40), id)) + return id; + + return (aff3 << 24) | FIELD_GET(GENMASK_ULL(23, 0), id); +} +#define arch_compact_of_hwid arch_compact_of_hwid + /* * Read the effective value of CTR_EL0. * From 2f5606afa4c2bcabd45cb34c92faf93ca5ffe75e Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 11 Jul 2025 08:04:37 +0000 Subject: [PATCH 70/84] device: rust: rename Device::as_ref() to Device::from_raw() The prefix as_* should not be used for a constructor. Constructors usually use the prefix from_* instead. Some prior art in the stdlib: Box::from_raw, CString::from_raw, Rc::from_raw, Arc::from_raw, Waker::from_raw, File::from_raw_fd. There is also prior art in the kernel crate: cpufreq::Policy::from_raw, fs::File::from_raw_file, Kuid::from_raw, ARef::from_raw, SeqFile::from_raw, VmaNew::from_raw, Io::from_raw. Link: https://lore.kernel.org/r/aCd8D5IA0RXZvtcv@pollux Signed-off-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250711-device-as-ref-v2-1-1b16ab6402d7@google.com Signed-off-by: Danilo Krummrich --- rust/kernel/auxiliary.rs | 2 +- rust/kernel/cpu.rs | 2 +- rust/kernel/device.rs | 6 +++--- rust/kernel/drm/device.rs | 2 +- rust/kernel/faux.rs | 2 +- rust/kernel/miscdevice.rs | 2 +- rust/kernel/net/phy.rs | 2 +- rust/kernel/pci.rs | 2 +- rust/kernel/platform.rs | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 2985673181b7..e1f2a2e6b607 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -270,7 +270,7 @@ fn as_ref(&self) -> &device::Device { let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; // SAFETY: `dev` points to a valid `struct device`. - unsafe { device::Device::as_ref(dev) } + unsafe { device::Device::from_raw(dev) } } } diff --git a/rust/kernel/cpu.rs b/rust/kernel/cpu.rs index b75403b0eb56..5de730c8d817 100644 --- a/rust/kernel/cpu.rs +++ b/rust/kernel/cpu.rs @@ -147,5 +147,5 @@ pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> { // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to // a `struct device` and is never freed by the C code. - Ok(unsafe { Device::as_ref(ptr) }) + Ok(unsafe { Device::from_raw(ptr) }) } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index b6b81546a0da..ca82926fd67f 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -58,7 +58,7 @@ impl Device { /// While not officially documented, this should be the case for any `struct device`. pub unsafe fn get_device(ptr: *mut bindings::device) -> ARef { // SAFETY: By the safety requirements ptr is valid - unsafe { Self::as_ref(ptr) }.into() + unsafe { Self::from_raw(ptr) }.into() } /// Convert a [`&Device`](Device) into a [`&Device`](Device). @@ -149,7 +149,7 @@ pub(crate) fn parent(&self) -> Option<&Self> { // - Since `parent` is not NULL, it must be a valid pointer to a `struct device`. // - `parent` is valid for the lifetime of `self`, since a `struct device` holds a // reference count of its parent. - Some(unsafe { Self::as_ref(parent) }) + Some(unsafe { Self::from_raw(parent) }) } } @@ -161,7 +161,7 @@ pub(crate) fn parent(&self) -> Option<&Self> { /// i.e. it must be ensured that the reference count of the C `struct device` `ptr` points to /// can't drop to zero, for the duration of this function call and the entire duration when the /// returned reference exists. - pub unsafe fn as_ref<'a>(ptr: *mut bindings::device) -> &'a Self { + pub unsafe fn from_raw<'a>(ptr: *mut bindings::device) -> &'a Self { // SAFETY: Guaranteed by the safety requirements of the function. unsafe { &*ptr.cast() } } diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index 624d7a4c83ea..11ce1e7f2d52 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -190,7 +190,7 @@ impl AsRef for Device { fn as_ref(&self) -> &device::Device { // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid, // which is guaranteed by the type invariant. - unsafe { device::Device::as_ref((*self.as_raw()).dev) } + unsafe { device::Device::from_raw((*self.as_raw()).dev) } } } diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs index 8a50fcd4c9bb..7a906099993f 100644 --- a/rust/kernel/faux.rs +++ b/rust/kernel/faux.rs @@ -54,7 +54,7 @@ impl AsRef for Registration { fn as_ref(&self) -> &device::Device { // SAFETY: The underlying `device` in `faux_device` is guaranteed by the C API to be // a valid initialized `device`. - unsafe { device::Device::as_ref(addr_of_mut!((*self.as_raw()).dev)) } + unsafe { device::Device::from_raw(addr_of_mut!((*self.as_raw()).dev)) } } } diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 4f7a8714ad36..443e5a3c3fe0 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -98,7 +98,7 @@ pub fn device(&self) -> &Device { // function tells the borrow-checker that the `&Device` reference must not outlive the // `&MiscDeviceRegistration` used to obtain it, so the last use of the reference must be // before the underlying `struct miscdevice` is destroyed. - unsafe { Device::as_ref((*self.as_raw()).this_device) } + unsafe { Device::from_raw((*self.as_raw()).this_device) } } } diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 32ea43ece646..bd43a726f7d3 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -285,7 +285,7 @@ impl AsRef for Device { fn as_ref(&self) -> &kernel::device::Device { let phydev = self.0.get(); // SAFETY: The struct invariant ensures that `mdio.dev` is valid. - unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) } + unsafe { kernel::device::Device::from_raw(addr_of_mut!((*phydev).mdio.dev)) } } } diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 8b884e324dcf..c9f7cb04d2e5 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -468,7 +468,7 @@ fn as_ref(&self) -> &device::Device { let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; // SAFETY: `dev` points to a valid `struct device`. - unsafe { device::Device::as_ref(dev) } + unsafe { device::Device::from_raw(dev) } } } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index ced43367d900..3d7a532550c8 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -251,7 +251,7 @@ fn as_ref(&self) -> &device::Device { let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; // SAFETY: `dev` points to a valid `struct device`. - unsafe { device::Device::as_ref(dev) } + unsafe { device::Device::from_raw(dev) } } } From 8d84b32075fb2d9bd95c7e47b165942411d74bba Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 11 Jul 2025 13:09:45 +0900 Subject: [PATCH 71/84] rust: device_id: split out index support into a separate trait Introduce a new trait `RawDeviceIdIndex`, which extends `RawDeviceId` to provide support for device ID types that include an index or context field (e.g., `driver_data`). This separates the concerns of layout compatibility and index-based data embedding, and allows `RawDeviceId` to be implemented for types that do not contain a `driver_data` field. Several such structures are defined in include/linux/mod_devicetable.h. Refactor `IdArray::new()` into a generic `build()` function, which takes an optional offset. Based on the presence of `RawDeviceIdIndex`, index writing is conditionally enabled. A new `new_without_index()` constructor is also provided for use cases where no index should be written. This refactoring is a preparation for enabling the PHY abstractions to use the RawDeviceId trait. The changes to acpi.rs and driver.rs were made by Danilo. Reviewed-by: Trevor Gross Signed-off-by: FUJITA Tomonori Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250711040947.1252162-2-fujita.tomonori@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/acpi.rs | 15 ++++--- rust/kernel/auxiliary.rs | 11 ++--- rust/kernel/device_id.rs | 91 +++++++++++++++++++++++++++++----------- rust/kernel/driver.rs | 8 +++- rust/kernel/of.rs | 15 ++++--- rust/kernel/pci.rs | 11 ++--- 6 files changed, 104 insertions(+), 47 deletions(-) diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs index 2af4d4f92924..7ae317368b00 100644 --- a/rust/kernel/acpi.rs +++ b/rust/kernel/acpi.rs @@ -2,7 +2,11 @@ //! Advanced Configuration and Power Interface abstractions. -use crate::{bindings, device_id::RawDeviceId, prelude::*}; +use crate::{ + bindings, + device_id::{RawDeviceId, RawDeviceIdIndex}, + prelude::*, +}; /// IdTable type for ACPI drivers. pub type IdTable = &'static dyn kernel::device_id::IdTable; @@ -12,13 +16,14 @@ #[derive(Clone, Copy)] pub struct DeviceId(bindings::acpi_device_id); -// SAFETY: -// * `DeviceId` is a `#[repr(transparent)` wrapper of `struct acpi_device_id` and does not add -// additional invariants, so it's safe to transmute to `RawType`. -// * `DRIVER_DATA_OFFSET` is the offset to the `data` field. +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `acpi_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. unsafe impl RawDeviceId for DeviceId { type RawType = bindings::acpi_device_id; +} +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +unsafe impl RawDeviceIdIndex for DeviceId { const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::acpi_device_id, driver_data); fn index(&self) -> usize { diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index e1f2a2e6b607..4749fb6bffef 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -6,7 +6,7 @@ use crate::{ bindings, container_of, device, - device_id::RawDeviceId, + device_id::{RawDeviceId, RawDeviceIdIndex}, driver, error::{from_result, to_result, Result}, prelude::*, @@ -134,13 +134,14 @@ pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self { } } -// SAFETY: -// * `DeviceId` is a `#[repr(transparent)`] wrapper of `auxiliary_device_id` and does not add -// additional invariants, so it's safe to transmute to `RawType`. -// * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `auxiliary_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. unsafe impl RawDeviceId for DeviceId { type RawType = bindings::auxiliary_device_id; +} +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +unsafe impl RawDeviceIdIndex for DeviceId { const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::auxiliary_device_id, driver_data); diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs index 0a4eb56d98f2..8ed2c946144c 100644 --- a/rust/kernel/device_id.rs +++ b/rust/kernel/device_id.rs @@ -14,32 +14,41 @@ /// /// # Safety /// -/// Implementers must ensure that: -/// - `Self` is layout-compatible with [`RawDeviceId::RawType`]; i.e. it's safe to transmute to -/// `RawDeviceId`. +/// Implementers must ensure that `Self` is layout-compatible with [`RawDeviceId::RawType`]; +/// i.e. it's safe to transmute to `RawDeviceId`. /// -/// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building -/// the ID table. +/// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building +/// the ID table. /// -/// Ideally, this should be achieved using a const function that does conversion instead of -/// transmute; however, const trait functions relies on `const_trait_impl` unstable feature, -/// which is broken/gone in Rust 1.73. -/// -/// - `DRIVER_DATA_OFFSET` is the offset of context/data field of the device ID (usually named -/// `driver_data`) of the device ID, the field is suitable sized to write a `usize` value. -/// -/// Similar to the previous requirement, the data should ideally be added during `Self` to -/// `RawType` conversion, but there's currently no way to do it when using traits in const. +/// Ideally, this should be achieved using a const function that does conversion instead of +/// transmute; however, const trait functions relies on `const_trait_impl` unstable feature, +/// which is broken/gone in Rust 1.73. pub unsafe trait RawDeviceId { /// The raw type that holds the device id. /// /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array. type RawType: Copy; +} - /// The offset to the context/data field. +/// Extension trait for [`RawDeviceId`] for devices that embed an index or context value. +/// +/// This is typically used when the device ID struct includes a field like `driver_data` +/// that is used to store a pointer-sized value (e.g., an index or context pointer). +/// +/// # Safety +/// +/// Implementers must ensure that `DRIVER_DATA_OFFSET` is the correct offset (in bytes) to +/// the context/data field (e.g., the `driver_data` field) within the raw device ID structure. +/// This field must be correctly sized to hold a `usize`. +/// +/// Ideally, the data should be added during `Self` to `RawType` conversion, +/// but there's currently no way to do it when using traits in const. +pub unsafe trait RawDeviceIdIndex: RawDeviceId { + /// The offset (in bytes) to the context/data field in the raw device ID. const DRIVER_DATA_OFFSET: usize; - /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceId`] trait. + /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceIdIndex`] + /// trait. fn index(&self) -> usize; } @@ -68,7 +77,15 @@ impl IdArray { /// Creates a new instance of the array. /// /// The contents are derived from the given identifiers and context information. - pub const fn new(ids: [(T, U); N]) -> Self { + /// + /// # Safety + /// + /// `data_offset` as `None` is always safe. + /// If `data_offset` is `Some(data_offset)`, then: + /// - `data_offset` must be the correct offset (in bytes) to the context/data field + /// (e.g., the `driver_data` field) within the raw device ID structure. + /// - The field at `data_offset` must be correctly sized to hold a `usize`. + const unsafe fn build(ids: [(T, U); N], data_offset: Option) -> Self { let mut raw_ids = [const { MaybeUninit::::uninit() }; N]; let mut infos = [const { MaybeUninit::uninit() }; N]; @@ -77,14 +94,16 @@ impl IdArray { // SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is // layout-wise compatible with `RawType`. raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) }; - // SAFETY: by the safety requirement of `RawDeviceId`, this would be effectively - // `raw_ids[i].driver_data = i;`. - unsafe { - raw_ids[i] - .as_mut_ptr() - .byte_offset(T::DRIVER_DATA_OFFSET as _) - .cast::() - .write(i); + if let Some(data_offset) = data_offset { + // SAFETY: by the safety requirement of this function, this would be effectively + // `raw_ids[i].driver_data = i;`. + unsafe { + raw_ids[i] + .as_mut_ptr() + .byte_offset(data_offset as _) + .cast::() + .write(i); + } } // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but @@ -109,12 +128,34 @@ impl IdArray { } } + /// Creates a new instance of the array without writing index values. + /// + /// The contents are derived from the given identifiers and context information. + /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead. + pub const fn new_without_index(ids: [(T, U); N]) -> Self { + // SAFETY: Calling `Self::build` with `offset = None` is always safe, + // because no raw memory writes are performed in this case. + unsafe { Self::build(ids, None) } + } + /// Reference to the contained [`RawIdArray`]. pub const fn raw_ids(&self) -> &RawIdArray { &self.raw_ids } } +impl IdArray { + /// Creates a new instance of the array. + /// + /// The contents are derived from the given identifiers and context information. + pub const fn new(ids: [(T, U); N]) -> Self { + // SAFETY: by the safety requirement of `RawDeviceIdIndex`, + // `T::DRIVER_DATA_OFFSET` is guaranteed to be the correct offset (in bytes) to + // a field within `T::RawType`. + unsafe { Self::build(ids, Some(T::DRIVER_DATA_OFFSET)) } + } +} + /// A device id table. /// /// This trait is only implemented by `IdArray`. diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index f8dd7593e8dc..a8f2675ba7a7 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -170,7 +170,7 @@ fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { // and does not add additional invariants, so it's safe to transmute. let id = unsafe { &*raw_id.cast::() }; - Some(table.info(::index(id))) + Some(table.info(::index(id))) } } } @@ -204,7 +204,11 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { // and does not add additional invariants, so it's safe to transmute. let id = unsafe { &*raw_id.cast::() }; - Some(table.info(::index(id))) + Some( + table.info(::index( + id, + )), + ) } } } diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs index 52fe0c77b9a1..0888469bddb7 100644 --- a/rust/kernel/of.rs +++ b/rust/kernel/of.rs @@ -2,7 +2,11 @@ //! Device Tree / Open Firmware abstractions. -use crate::{bindings, device_id::RawDeviceId, prelude::*}; +use crate::{ + bindings, + device_id::{RawDeviceId, RawDeviceIdIndex}, + prelude::*, +}; /// IdTable type for OF drivers. pub type IdTable = &'static dyn kernel::device_id::IdTable; @@ -12,13 +16,14 @@ #[derive(Clone, Copy)] pub struct DeviceId(bindings::of_device_id); -// SAFETY: -// * `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` and does not add -// additional invariants, so it's safe to transmute to `RawType`. -// * `DRIVER_DATA_OFFSET` is the offset to the `data` field. +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` and +// does not add additional invariants, so it's safe to transmute to `RawType`. unsafe impl RawDeviceId for DeviceId { type RawType = bindings::of_device_id; +} +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `data` field. +unsafe impl RawDeviceIdIndex for DeviceId { const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data); fn index(&self) -> usize { diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index c9f7cb04d2e5..6a4854cf4bf9 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -6,7 +6,7 @@ use crate::{ bindings, container_of, device, - device_id::RawDeviceId, + device_id::{RawDeviceId, RawDeviceIdIndex}, devres::Devres, driver, error::{from_result, to_result, Result}, @@ -159,13 +159,14 @@ pub const fn from_class(class: u32, class_mask: u32) -> Self { } } -// SAFETY: -// * `DeviceId` is a `#[repr(transparent)]` wrapper of `pci_device_id` and does not add -// additional invariants, so it's safe to transmute to `RawType`. -// * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `pci_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. unsafe impl RawDeviceId for DeviceId { type RawType = bindings::pci_device_id; +} +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +unsafe impl RawDeviceIdIndex for DeviceId { const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data); fn index(&self) -> usize { From f65a3218fd92cbe3e00f25427e1c9255b8973b31 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 11 Jul 2025 13:09:46 +0900 Subject: [PATCH 72/84] rust: net::phy represent DeviceId as transparent wrapper over mdio_device_id Refactor the DeviceId struct to be a #[repr(transparent)] wrapper around the C struct bindings::mdio_device_id. This refactoring is a preparation for enabling the PHY abstractions to use the RawDeviceId trait. Acked-by: Jakub Kicinski Reviewed-by: Trevor Gross Signed-off-by: FUJITA Tomonori Link: https://lore.kernel.org/r/20250711040947.1252162-3-fujita.tomonori@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/net/phy.rs | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index bd43a726f7d3..11a6809f3bea 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -507,7 +507,7 @@ pub const fn create_phy_driver() -> DriverVTable { DriverVTable(Opaque::new(bindings::phy_driver { name: T::NAME.as_char_ptr().cast_mut(), flags: T::FLAGS, - phy_id: T::PHY_DEVICE_ID.id, + phy_id: T::PHY_DEVICE_ID.id(), phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(), soft_reset: if T::HAS_SOFT_RESET { Some(Adapter::::soft_reset_callback) @@ -691,42 +691,41 @@ fn drop(&mut self) { /// /// Represents the kernel's `struct mdio_device_id`. This is used to find an appropriate /// PHY driver. -pub struct DeviceId { - id: u32, - mask: DeviceMask, -} +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::mdio_device_id); impl DeviceId { /// Creates a new instance with the exact match mask. pub const fn new_with_exact_mask(id: u32) -> Self { - DeviceId { - id, - mask: DeviceMask::Exact, - } + Self(bindings::mdio_device_id { + phy_id: id, + phy_id_mask: DeviceMask::Exact.as_int(), + }) } /// Creates a new instance with the model match mask. pub const fn new_with_model_mask(id: u32) -> Self { - DeviceId { - id, - mask: DeviceMask::Model, - } + Self(bindings::mdio_device_id { + phy_id: id, + phy_id_mask: DeviceMask::Model.as_int(), + }) } /// Creates a new instance with the vendor match mask. pub const fn new_with_vendor_mask(id: u32) -> Self { - DeviceId { - id, - mask: DeviceMask::Vendor, - } + Self(bindings::mdio_device_id { + phy_id: id, + phy_id_mask: DeviceMask::Vendor.as_int(), + }) } /// Creates a new instance with a custom match mask. pub const fn new_with_custom_mask(id: u32, mask: u32) -> Self { - DeviceId { - id, - mask: DeviceMask::Custom(mask), - } + Self(bindings::mdio_device_id { + phy_id: id, + phy_id_mask: DeviceMask::Custom(mask).as_int(), + }) } /// Creates a new instance from [`Driver`]. @@ -734,18 +733,20 @@ pub const fn new_with_driver() -> Self { T::PHY_DEVICE_ID } - /// Get a `mask` as u32. + /// Get the MDIO device's PHY ID. + pub const fn id(&self) -> u32 { + self.0.phy_id + } + + /// Get the MDIO device's match mask. pub const fn mask_as_int(&self) -> u32 { - self.mask.as_int() + self.0.phy_id_mask } // macro use only #[doc(hidden)] pub const fn mdio_device_id(&self) -> bindings::mdio_device_id { - bindings::mdio_device_id { - phy_id: self.id, - phy_id_mask: self.mask.as_int(), - } + self.0 } } From 9a8682f0875b8cedad42bdfe601e6ab204fad06d Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 11 Jul 2025 13:09:47 +0900 Subject: [PATCH 73/84] rust: net::phy Change module_phy_driver macro to use module_device_table macro Change module_phy_driver macro to build device tables which are exported to userspace by using module_device_table macro. Acked-by: Jakub Kicinski Reviewed-by: Trevor Gross Signed-off-by: FUJITA Tomonori Link: https://lore.kernel.org/r/20250711040947.1252162-4-fujita.tomonori@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/net/phy.rs | 51 ++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 11a6809f3bea..95bd17d3e927 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -6,7 +6,7 @@ //! //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h). -use crate::{error::*, prelude::*, types::Opaque}; +use crate::{device_id::RawDeviceId, error::*, prelude::*, types::Opaque}; use core::{marker::PhantomData, ptr::addr_of_mut}; pub mod reg; @@ -750,6 +750,12 @@ pub const fn mdio_device_id(&self) -> bindings::mdio_device_id { } } +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct mdio_device_id` +// and does not add additional invariants, so it's safe to transmute to `RawType`. +unsafe impl RawDeviceId for DeviceId { + type RawType = bindings::mdio_device_id; +} + enum DeviceMask { Exact, Model, @@ -850,19 +856,18 @@ const fn as_int(&self) -> u32 { /// } /// }; /// -/// const _DEVICE_TABLE: [::kernel::bindings::mdio_device_id; 2] = [ -/// ::kernel::bindings::mdio_device_id { -/// phy_id: 0x00000001, -/// phy_id_mask: 0xffffffff, -/// }, -/// ::kernel::bindings::mdio_device_id { -/// phy_id: 0, -/// phy_id_mask: 0, -/// }, -/// ]; -/// #[cfg(MODULE)] -/// #[no_mangle] -/// static __mod_device_table__mdio__phydev: [::kernel::bindings::mdio_device_id; 2] = _DEVICE_TABLE; +/// const N: usize = 1; +/// +/// const TABLE: ::kernel::device_id::IdArray<::kernel::net::phy::DeviceId, (), N> = +/// ::kernel::device_id::IdArray::new_without_index([ +/// ::kernel::net::phy::DeviceId( +/// ::kernel::bindings::mdio_device_id { +/// phy_id: 0x00000001, +/// phy_id_mask: 0xffffffff, +/// }), +/// ]); +/// +/// ::kernel::module_device_table!("mdio", phydev, TABLE); /// ``` #[macro_export] macro_rules! module_phy_driver { @@ -873,20 +878,12 @@ macro_rules! module_phy_driver { }; (@device_table [$($dev:expr),+]) => { - // SAFETY: C will not read off the end of this constant since the last element is zero. - const _DEVICE_TABLE: [$crate::bindings::mdio_device_id; - $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [ - $($dev.mdio_device_id()),+, - $crate::bindings::mdio_device_id { - phy_id: 0, - phy_id_mask: 0 - } - ]; + const N: usize = $crate::module_phy_driver!(@count_devices $($dev),+); - #[cfg(MODULE)] - #[no_mangle] - static __mod_device_table__mdio__phydev: [$crate::bindings::mdio_device_id; - $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = _DEVICE_TABLE; + const TABLE: $crate::device_id::IdArray<$crate::net::phy::DeviceId, (), N> = + $crate::device_id::IdArray::new_without_index([ $(($dev,())),+, ]); + + $crate::module_device_table!("mdio", phydev, TABLE); }; (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => { From d06d5f66f5494e29c1520583eac8382f0ab5f8a7 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 16 Jul 2025 17:02:46 +0200 Subject: [PATCH 74/84] rust: dma: implement `dma::Device` trait Add a trait that defines the DMA specific methods of devices. The `dma::Device` trait is to be implemented by bus device representations, where the underlying bus is capable of DMA, such as `pci::Device` or `platform::Device`. Reviewed-by: Abdiel Janulgue Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250716150354.51081-2-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/dma.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index a33261c62e0c..586524488e5d 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -5,14 +5,21 @@ //! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-mapping.h) use crate::{ - bindings, build_assert, - device::{Bound, Device}, + bindings, build_assert, device, + device::Bound, error::code::*, error::Result, transmute::{AsBytes, FromBytes}, types::ARef, }; +/// Trait to be implemented by DMA capable bus devices. +/// +/// The [`dma::Device`](Device) trait should be implemented by bus specific device representations, +/// where the underlying bus is DMA capable, such as [`pci::Device`](::kernel::pci::Device) or +/// [`platform::Device`](::kernel::platform::Device). +pub trait Device: AsRef> {} + /// Possible attributes associated with a DMA mapping. /// /// They can be combined with the operators `|`, `&`, and `!`. @@ -130,7 +137,7 @@ pub mod attrs { // Hence, find a way to revoke the device resources of a `CoherentAllocation`, but not the // entire `CoherentAllocation` including the allocated memory itself. pub struct CoherentAllocation { - dev: ARef, + dev: ARef, dma_handle: bindings::dma_addr_t, count: usize, cpu_addr: *mut T, @@ -152,7 +159,7 @@ impl CoherentAllocation { /// # Ok::<(), Error>(()) } /// ``` pub fn alloc_attrs( - dev: &Device, + dev: &device::Device, count: usize, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, @@ -194,7 +201,7 @@ pub fn alloc_attrs( /// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the /// `dma_attrs` is 0 by default. pub fn alloc_coherent( - dev: &Device, + dev: &device::Device, count: usize, gfp_flags: kernel::alloc::Flags, ) -> Result> { From 101d66828a4eefb89b72256155feb6ec9abc144a Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 16 Jul 2025 17:02:47 +0200 Subject: [PATCH 75/84] rust: dma: add DMA addressing capabilities Implement `dma_set_mask()`, `dma_set_coherent_mask()` and `dma_set_mask_and_coherent()` in the `dma::Device` trait. Those methods are used to set up the device's DMA addressing capabilities. Reviewed-by: Abdiel Janulgue Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250716150354.51081-3-dakr@kernel.org [ Add DmaMask::try_new(). - Danilo ] Signed-off-by: Danilo Krummrich --- rust/helpers/dma.c | 5 ++ rust/kernel/dma.rs | 143 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/rust/helpers/dma.c b/rust/helpers/dma.c index df8b8a77355a..6e741c197242 100644 --- a/rust/helpers/dma.c +++ b/rust/helpers/dma.c @@ -14,3 +14,8 @@ void rust_helper_dma_free_attrs(struct device *dev, size_t size, void *cpu_addr, { dma_free_attrs(dev, size, cpu_addr, dma_handle, attrs); } + +int rust_helper_dma_set_mask_and_coherent(struct device *dev, u64 mask) +{ + return dma_set_mask_and_coherent(dev, mask); +} diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 586524488e5d..99dcf79f0897 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -6,9 +6,9 @@ use crate::{ bindings, build_assert, device, - device::Bound, - error::code::*, - error::Result, + device::{Bound, Core}, + error::{to_result, Result}, + prelude::*, transmute::{AsBytes, FromBytes}, types::ARef, }; @@ -18,7 +18,142 @@ /// The [`dma::Device`](Device) trait should be implemented by bus specific device representations, /// where the underlying bus is DMA capable, such as [`pci::Device`](::kernel::pci::Device) or /// [`platform::Device`](::kernel::platform::Device). -pub trait Device: AsRef> {} +pub trait Device: AsRef> { + /// Set up the device's DMA streaming addressing capabilities. + /// + /// This method is usually called once from `probe()` as soon as the device capabilities are + /// known. + /// + /// # Safety + /// + /// This method must not be called concurrently with any DMA allocation or mapping primitives, + /// such as [`CoherentAllocation::alloc_attrs`]. + unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result { + // SAFETY: + // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid. + // - The safety requirement of this function guarantees that there are no concurrent calls + // to DMA allocation and mapping primitives using this mask. + to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) }) + } + + /// Set up the device's DMA coherent addressing capabilities. + /// + /// This method is usually called once from `probe()` as soon as the device capabilities are + /// known. + /// + /// # Safety + /// + /// This method must not be called concurrently with any DMA allocation or mapping primitives, + /// such as [`CoherentAllocation::alloc_attrs`]. + unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> Result { + // SAFETY: + // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid. + // - The safety requirement of this function guarantees that there are no concurrent calls + // to DMA allocation and mapping primitives using this mask. + to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) }) + } + + /// Set up the device's DMA addressing capabilities. + /// + /// This is a combination of [`Device::dma_set_mask`] and [`Device::dma_set_coherent_mask`]. + /// + /// This method is usually called once from `probe()` as soon as the device capabilities are + /// known. + /// + /// # Safety + /// + /// This method must not be called concurrently with any DMA allocation or mapping primitives, + /// such as [`CoherentAllocation::alloc_attrs`]. + unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result { + // SAFETY: + // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid. + // - The safety requirement of this function guarantees that there are no concurrent calls + // to DMA allocation and mapping primitives using this mask. + to_result(unsafe { + bindings::dma_set_mask_and_coherent(self.as_ref().as_raw(), mask.value()) + }) + } +} + +/// A DMA mask that holds a bitmask with the lowest `n` bits set. +/// +/// Use [`DmaMask::new`] or [`DmaMask::try_new`] to construct a value. Values +/// are guaranteed to never exceed the bit width of `u64`. +/// +/// This is the Rust equivalent of the C macro `DMA_BIT_MASK()`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DmaMask(u64); + +impl DmaMask { + /// Constructs a `DmaMask` with the lowest `n` bits set to `1`. + /// + /// For `n <= 64`, sets exactly the lowest `n` bits. + /// For `n > 64`, results in a build error. + /// + /// # Examples + /// + /// ``` + /// use kernel::dma::DmaMask; + /// + /// let mask0 = DmaMask::new::<0>(); + /// assert_eq!(mask0.value(), 0); + /// + /// let mask1 = DmaMask::new::<1>(); + /// assert_eq!(mask1.value(), 0b1); + /// + /// let mask64 = DmaMask::new::<64>(); + /// assert_eq!(mask64.value(), u64::MAX); + /// + /// // Build failure. + /// // let mask_overflow = DmaMask::new::<100>(); + /// ``` + #[inline] + pub const fn new() -> Self { + let Ok(mask) = Self::try_new(N) else { + build_error!("Invalid DMA Mask."); + }; + + mask + } + + /// Constructs a `DmaMask` with the lowest `n` bits set to `1`. + /// + /// For `n <= 64`, sets exactly the lowest `n` bits. + /// For `n > 64`, returns [`EINVAL`]. + /// + /// # Examples + /// + /// ``` + /// use kernel::dma::DmaMask; + /// + /// let mask0 = DmaMask::try_new(0)?; + /// assert_eq!(mask0.value(), 0); + /// + /// let mask1 = DmaMask::try_new(1)?; + /// assert_eq!(mask1.value(), 0b1); + /// + /// let mask64 = DmaMask::try_new(64)?; + /// assert_eq!(mask64.value(), u64::MAX); + /// + /// let mask_overflow = DmaMask::try_new(100); + /// assert!(mask_overflow.is_err()); + /// # Ok::<(), Error>(()) + /// ``` + #[inline] + pub const fn try_new(n: u32) -> Result { + Ok(Self(match n { + 0 => 0, + 1..=64 => u64::MAX >> (64 - n), + _ => return Err(EINVAL), + })) + } + + /// Returns the underlying `u64` bitmask value. + #[inline] + pub const fn value(&self) -> u64 { + self.0 + } +} /// Possible attributes associated with a DMA mapping. /// From 8eb698f54736b44a398ca883d0a33f661c12da9d Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 16 Jul 2025 17:02:48 +0200 Subject: [PATCH 76/84] rust: pci: implement the `dma::Device` trait The PCI bus is potentially capable of performing DMA, hence implement the `dma:Device` trait for `pci::Device`. Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250716150354.51081-4-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 6a4854cf4bf9..44a2f3d2884a 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -449,6 +449,8 @@ pub fn set_master(&self) { kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); +impl crate::dma::Device for Device {} + // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::types::AlwaysRefCounted for Device { fn inc_ref(&self) { From 256de48f2cad85153b271b66320a9355773db64e Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 16 Jul 2025 17:02:49 +0200 Subject: [PATCH 77/84] rust: platform: implement the `dma::Device` trait The platform bus is potentially capable of performing DMA, hence implement the `dma:Device` trait for `platform::Device`. Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250716150354.51081-5-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 3d7a532550c8..3c0c507c2432 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -231,6 +231,8 @@ fn as_raw(&self) -> *mut bindings::platform_device { kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); +impl crate::dma::Device for Device {} + // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::types::AlwaysRefCounted for Device { fn inc_ref(&self) { From 931d9251e4855f79394357eb0071b5c4a189a8bd Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 16 Jul 2025 17:02:50 +0200 Subject: [PATCH 78/84] rust: samples: dma: set DMA mask Set a DMA mask for the `pci::Device` in the Rust DMA sample driver. Reviewed-by: Abdiel Janulgue Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250716150354.51081-6-dakr@kernel.org Signed-off-by: Danilo Krummrich --- samples/rust/rust_dma.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 874c2c964afa..12370bca97bc 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -4,7 +4,14 @@ //! //! To make this driver probe, QEMU must be run with `-device pci-testdev`. -use kernel::{bindings, device::Core, dma::CoherentAllocation, pci, prelude::*, types::ARef}; +use kernel::{ + bindings, + device::Core, + dma::{CoherentAllocation, Device, DmaMask}, + pci, + prelude::*, + types::ARef, +}; struct DmaSampleDriver { pdev: ARef, @@ -51,6 +58,11 @@ impl pci::Driver for DmaSampleDriver { fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> Result>> { dev_info!(pdev.as_ref(), "Probe DMA test driver.\n"); + let mask = DmaMask::new::<64>(); + + // SAFETY: There are no concurrent calls to DMA allocation and mapping primitives. + unsafe { pdev.dma_set_mask_and_coherent(mask)? }; + let ca: CoherentAllocation = CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?; From 493fc33ec25294cb2e444dfa77c105aa774c83f2 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 17 Jul 2025 12:55:22 -0300 Subject: [PATCH 79/84] rust: io: add resource abstraction In preparation for ioremap support, add a Rust abstraction for struct resource. A future commit will introduce the Rust API to ioremap a resource from a platform device. The current abstraction, therefore, adds only the minimum API needed to get that done. Acked-by: Miguel Ojeda Reviewed-by: Alice Ryhl Co-developed-by: Fiona Behrens Signed-off-by: Fiona Behrens Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250717-topics-tyr-platform_iomem-v15-1-beca780b77e3@collabora.com [ Capitalize safety comments and end it with a period. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/bindings/bindings_helper.h | 1 + rust/helpers/io.c | 36 +++++ rust/kernel/io.rs | 4 + rust/kernel/io/resource.rs | 229 ++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 rust/kernel/io/resource.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 7e8f22850647..5f795e60e889 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/io.c b/rust/helpers/io.c index 15ea187c5466..404776cf6717 100644 --- a/rust/helpers/io.c +++ b/rust/helpers/io.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size) { @@ -99,3 +100,38 @@ void rust_helper_writeq_relaxed(u64 value, void __iomem *addr) writeq_relaxed(value, addr); } #endif + +resource_size_t rust_helper_resource_size(struct resource *res) +{ + return resource_size(res); +} + +struct resource *rust_helper_request_mem_region(resource_size_t start, + resource_size_t n, + const char *name) +{ + return request_mem_region(start, n, name); +} + +void rust_helper_release_mem_region(resource_size_t start, resource_size_t n) +{ + release_mem_region(start, n); +} + +struct resource *rust_helper_request_region(resource_size_t start, + resource_size_t n, const char *name) +{ + return request_region(start, n, name); +} + +struct resource *rust_helper_request_muxed_region(resource_size_t start, + resource_size_t n, + const char *name) +{ + return request_muxed_region(start, n, name); +} + +void rust_helper_release_region(resource_size_t start, resource_size_t n) +{ + release_region(start, n); +} diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 72d80a6f131e..7b70d5b5477e 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -7,6 +7,10 @@ use crate::error::{code::EINVAL, Result}; use crate::{bindings, build_assert}; +pub mod resource; + +pub use resource::Resource; + /// Raw representation of an MMIO region. /// /// By itself, the existence of an instance of this structure does not provide any guarantees that diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs new file mode 100644 index 000000000000..1d5f367a6e8a --- /dev/null +++ b/rust/kernel/io/resource.rs @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Abstractions for [system +//! resources](https://docs.kernel.org/core-api/kernel-api.html#resources-management). +//! +//! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h) + +use core::ops::Deref; +use core::ptr::NonNull; + +use crate::prelude::*; +use crate::str::{CStr, CString}; +use crate::types::Opaque; + +/// Resource Size type. +/// +/// This is a type alias to either `u32` or `u64` depending on the config option +/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. +pub type ResourceSize = bindings::phys_addr_t; + +/// A region allocated from a parent [`Resource`]. +/// +/// # Invariants +/// +/// - `self.0` points to a valid `bindings::resource` that was obtained through +/// `bindings::__request_region`. +pub struct Region { + /// The resource returned when the region was requested. + resource: NonNull, + /// The name that was passed in when the region was requested. We need to + /// store it for ownership reasons. + _name: CString, +} + +impl Deref for Region { + type Target = Resource; + + fn deref(&self) -> &Self::Target { + // SAFETY: Safe as per the invariant of `Region`. + unsafe { Resource::from_raw(self.resource.as_ptr()) } + } +} + +impl Drop for Region { + fn drop(&mut self) { + let (flags, start, size) = { + let res = &**self; + (res.flags(), res.start(), res.size()) + }; + + let release_fn = if flags.contains(Flags::IORESOURCE_MEM) { + bindings::release_mem_region + } else { + bindings::release_region + }; + + // SAFETY: Safe as per the invariant of `Region`. + unsafe { release_fn(start, size) }; + } +} + +// SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from +// any thread. +unsafe impl Send for Region {} + +// SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are +// safe to be used from any thread. +unsafe impl Sync for Region {} + +/// A resource abstraction. +/// +/// # Invariants +/// +/// [`Resource`] is a transparent wrapper around a valid `bindings::resource`. +#[repr(transparent)] +pub struct Resource(Opaque); + +impl Resource { + /// Creates a reference to a [`Resource`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that for the duration of 'a, the pointer will + /// point at a valid `bindings::resource`. + /// + /// The caller must also ensure that the [`Resource`] is only accessed via the + /// returned reference for the duration of 'a. + pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self { + // SAFETY: Self is a transparent wrapper around `Opaque`. + unsafe { &*ptr.cast() } + } + + /// Requests a resource region. + /// + /// Exclusive access will be given and the region will be marked as busy. + /// Further calls to [`Self::request_region`] will return [`None`] if + /// the region, or a part of it, is already in use. + pub fn request_region( + &self, + start: ResourceSize, + size: ResourceSize, + name: CString, + flags: Flags, + ) -> Option { + // SAFETY: + // - Safe as per the invariant of `Resource`. + // - `__request_region` will store a reference to the name, but that is + // safe as we own it and it will not be dropped until the `Region` is + // dropped. + let region = unsafe { + bindings::__request_region( + self.0.get(), + start, + size, + name.as_char_ptr(), + flags.0 as c_int, + ) + }; + + Some(Region { + resource: NonNull::new(region)?, + _name: name, + }) + } + + /// Returns the size of the resource. + pub fn size(&self) -> ResourceSize { + let inner = self.0.get(); + // SAFETY: Safe as per the invariants of `Resource`. + unsafe { bindings::resource_size(inner) } + } + + /// Returns the start address of the resource. + pub fn start(&self) -> ResourceSize { + let inner = self.0.get(); + // SAFETY: Safe as per the invariants of `Resource`. + unsafe { (*inner).start } + } + + /// Returns the name of the resource. + pub fn name(&self) -> Option<&CStr> { + let inner = self.0.get(); + + // SAFETY: Safe as per the invariants of `Resource`. + let name = unsafe { (*inner).name }; + + if name.is_null() { + return None; + } + + // SAFETY: In the C code, `resource::name` either contains a null + // pointer or points to a valid NUL-terminated C string, and at this + // point we know it is not null, so we can safely convert it to a + // `CStr`. + Some(unsafe { CStr::from_char_ptr(name) }) + } + + /// Returns the flags associated with the resource. + pub fn flags(&self) -> Flags { + let inner = self.0.get(); + // SAFETY: Safe as per the invariants of `Resource`. + let flags = unsafe { (*inner).flags }; + + Flags(flags) + } +} + +// SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is +// safe to be used from any thread. +unsafe impl Send for Resource {} + +// SAFETY: `Resource` only holds a pointer to a C `struct resource`, references +// to which are safe to be used from any thread. +unsafe impl Sync for Resource {} + +/// Resource flags as stored in the C `struct resource::flags` field. +/// +/// They can be combined with the operators `|`, `&`, and `!`. +/// +/// Values can be used from the [`flags`] module. +#[derive(Clone, Copy, PartialEq)] +pub struct Flags(c_ulong); + +impl Flags { + /// Check whether `flags` is contained in `self`. + pub fn contains(self, flags: Flags) -> bool { + (self & flags) == flags + } +} + +impl core::ops::BitOr for Flags { + type Output = Self; + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + +impl core::ops::BitAnd for Flags { + type Output = Self; + fn bitand(self, rhs: Self) -> Self::Output { + Self(self.0 & rhs.0) + } +} + +impl core::ops::Not for Flags { + type Output = Self; + fn not(self) -> Self::Output { + Self(!self.0) + } +} + +impl Flags { + /// PCI/ISA I/O ports. + pub const IORESOURCE_IO: Flags = Flags::new(bindings::IORESOURCE_IO); + + /// Resource is software muxed. + pub const IORESOURCE_MUXED: Flags = Flags::new(bindings::IORESOURCE_MUXED); + + /// Resource represents a memory region. + pub const IORESOURCE_MEM: Flags = Flags::new(bindings::IORESOURCE_MEM); + + /// Resource represents a memory region that must be ioremaped using `ioremap_np`. + pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED); + + const fn new(value: u32) -> Self { + crate::build_assert!(value as u64 <= c_ulong::MAX as u64); + Flags(value as c_ulong) + } +} From 1d0d4b28513b5e0e9e87e09c8da289e1b8d88f84 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 17 Jul 2025 12:55:23 -0300 Subject: [PATCH 80/84] rust: io: mem: add a generic iomem abstraction Add a generic iomem abstraction to safely read and write ioremapped regions. This abstraction requires a previously acquired IoRequest instance. This makes it so that both the resource and the device match, or, in other words, that the resource is indeed a valid resource for a given bound device. A subsequent patch will add the ability to retrieve IoRequest instances from platform devices. The reads and writes are done through IoRaw, and are thus checked either at compile-time, if the size of the region is known at that point, or at runtime otherwise. Non-exclusive access to the underlying memory region is made possible to cater to cases where overlapped regions are unavoidable. Acked-by: Miguel Ojeda Reviewed-by: Alice Ryhl Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250717-topics-tyr-platform_iomem-v15-2-beca780b77e3@collabora.com [ Add #[expect(dead_code)] to avoid a temporary warning, remove unnecessary OF_ID_TABLE constants in doc-tests and ignore doc-tests for now to avoid a temporary build failure. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/helpers/io.c | 5 + rust/kernel/io.rs | 1 + rust/kernel/io/mem.rs | 280 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 rust/kernel/io/mem.rs diff --git a/rust/helpers/io.c b/rust/helpers/io.c index 404776cf6717..c475913c69e6 100644 --- a/rust/helpers/io.c +++ b/rust/helpers/io.c @@ -8,6 +8,11 @@ void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size) return ioremap(offset, size); } +void __iomem *rust_helper_ioremap_np(phys_addr_t offset, size_t size) +{ + return ioremap_np(offset, size); +} + void rust_helper_iounmap(void __iomem *addr) { iounmap(addr); diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 7b70d5b5477e..b7fc759f8b5d 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -7,6 +7,7 @@ use crate::error::{code::EINVAL, Result}; use crate::{bindings, build_assert}; +pub mod mem; pub mod resource; pub use resource::Resource; diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs new file mode 100644 index 000000000000..8e4dfd79079e --- /dev/null +++ b/rust/kernel/io/mem.rs @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Generic memory-mapped IO. + +use core::ops::Deref; + +use crate::c_str; +use crate::device::Bound; +use crate::device::Device; +use crate::devres::Devres; +use crate::io; +use crate::io::resource::Region; +use crate::io::resource::Resource; +use crate::io::Io; +use crate::io::IoRaw; +use crate::prelude::*; + +/// An IO request for a specific device and resource. +pub struct IoRequest<'a> { + device: &'a Device, + resource: &'a Resource, +} + +impl<'a> IoRequest<'a> { + /// Creates a new [`IoRequest`] instance. + /// + /// # Safety + /// + /// Callers must ensure that `resource` is valid for `device` during the + /// lifetime `'a`. + #[expect(dead_code)] + pub(crate) unsafe fn new(device: &'a Device, resource: &'a Resource) -> Self { + IoRequest { device, resource } + } + + /// Maps an [`IoRequest`] where the size is known at compile time. + /// + /// This uses the [`ioremap()`] C API. + /// + /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device + /// + /// # Examples + /// + /// The following example uses a [`platform::Device`] for illustration + /// purposes. + /// + /// ```ignore + /// use kernel::{bindings, c_str, platform, of, device::Core}; + /// struct SampleDriver; + /// + /// impl platform::Driver for SampleDriver { + /// # type IdInfo = (); + /// + /// fn probe( + /// pdev: &platform::Device, + /// info: Option<&Self::IdInfo>, + /// ) -> Result>> { + /// let offset = 0; // Some offset. + /// + /// // If the size is known at compile time, use [`Self::iomap_sized`]. + /// // + /// // No runtime checks will apply when reading and writing. + /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; + /// let iomem = request.iomap_sized::<42>(); + /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; + /// + /// let io = iomem.access(pdev.as_ref())?; + /// + /// // Read and write a 32-bit value at `offset`. + /// let data = io.read32_relaxed(offset); + /// + /// io.write32_relaxed(data, offset); + /// + /// # Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into()) + /// } + /// } + /// ``` + pub fn iomap_sized(self) -> impl PinInit>, Error> + 'a { + IoMem::new(self) + } + + /// Same as [`Self::iomap_sized`] but with exclusive access to the + /// underlying region. + /// + /// This uses the [`ioremap()`] C API. + /// + /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device + pub fn iomap_exclusive_sized( + self, + ) -> impl PinInit>, Error> + 'a { + ExclusiveIoMem::new(self) + } + + /// Maps an [`IoRequest`] where the size is not known at compile time, + /// + /// This uses the [`ioremap()`] C API. + /// + /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device + /// + /// # Examples + /// + /// The following example uses a [`platform::Device`] for illustration + /// purposes. + /// + /// ```ignore + /// use kernel::{bindings, c_str, platform, of, device::Core}; + /// struct SampleDriver; + /// + /// impl platform::Driver for SampleDriver { + /// # type IdInfo = (); + /// + /// fn probe( + /// pdev: &platform::Device, + /// info: Option<&Self::IdInfo>, + /// ) -> Result>> { + /// let offset = 0; // Some offset. + /// + /// // Unlike [`Self::iomap_sized`], here the size of the memory region + /// // is not known at compile time, so only the `try_read*` and `try_write*` + /// // family of functions should be used, leading to runtime checks on every + /// // access. + /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; + /// let iomem = request.iomap(); + /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; + /// + /// let io = iomem.access(pdev.as_ref())?; + /// + /// let data = io.try_read32_relaxed(offset)?; + /// + /// io.try_write32_relaxed(data, offset)?; + /// + /// # Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into()) + /// } + /// } + /// ``` + pub fn iomap(self) -> impl PinInit>, Error> + 'a { + Self::iomap_sized::<0>(self) + } + + /// Same as [`Self::iomap`] but with exclusive access to the underlying + /// region. + pub fn iomap_exclusive(self) -> impl PinInit>, Error> + 'a { + Self::iomap_exclusive_sized::<0>(self) + } +} + +/// An exclusive memory-mapped IO region. +/// +/// # Invariants +/// +/// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. +pub struct ExclusiveIoMem { + /// The underlying `IoMem` instance. + iomem: IoMem, + + /// The region abstraction. This represents exclusive access to the + /// range represented by the underlying `iomem`. + /// + /// This field is needed for ownership of the region. + _region: Region, +} + +impl ExclusiveIoMem { + /// Creates a new `ExclusiveIoMem` instance. + fn ioremap(resource: &Resource) -> Result { + let start = resource.start(); + let size = resource.size(); + let name = resource.name().unwrap_or(c_str!("")); + + let region = resource + .request_region( + start, + size, + name.to_cstring()?, + io::resource::Flags::IORESOURCE_MEM, + ) + .ok_or(EBUSY)?; + + let iomem = IoMem::ioremap(resource)?; + + let iomem = ExclusiveIoMem { + iomem, + _region: region, + }; + + Ok(iomem) + } + + /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`]. + pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit, Error> + 'a { + let dev = io_request.device; + let res = io_request.resource; + + Devres::new(dev, Self::ioremap(res)) + } +} + +impl Deref for ExclusiveIoMem { + type Target = Io; + + fn deref(&self) -> &Self::Target { + &self.iomem + } +} + +/// A generic memory-mapped IO region. +/// +/// Accesses to the underlying region is checked either at compile time, if the +/// region's size is known at that point, or at runtime otherwise. +/// +/// # Invariants +/// +/// [`IoMem`] always holds an [`IoRaw`] instance that holds a valid pointer to the +/// start of the I/O memory mapped region. +pub struct IoMem { + io: IoRaw, +} + +impl IoMem { + fn ioremap(resource: &Resource) -> Result { + // Note: Some ioremap() implementations use types that depend on the CPU + // word width rather than the bus address width. + // + // TODO: Properly address this in the C code to avoid this `try_into`. + let size = resource.size().try_into()?; + if size == 0 { + return Err(EINVAL); + } + + let res_start = resource.start(); + + let addr = if resource + .flags() + .contains(io::resource::Flags::IORESOURCE_MEM_NONPOSTED) + { + // SAFETY: + // - `res_start` and `size` are read from a presumably valid `struct resource`. + // - `size` is known not to be zero at this point. + unsafe { bindings::ioremap_np(res_start, size) } + } else { + // SAFETY: + // - `res_start` and `size` are read from a presumably valid `struct resource`. + // - `size` is known not to be zero at this point. + unsafe { bindings::ioremap(res_start, size) } + }; + + if addr.is_null() { + return Err(ENOMEM); + } + + let io = IoRaw::new(addr as usize, size)?; + let io = IoMem { io }; + + Ok(io) + } + + /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`]. + pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit, Error> + 'a { + let dev = io_request.device; + let res = io_request.resource; + + Devres::new(dev, Self::ioremap(res)) + } +} + +impl Drop for IoMem { + fn drop(&mut self) { + // SAFETY: Safe as by the invariant of `Io`. + unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } + } +} + +impl Deref for IoMem { + type Target = Io; + + fn deref(&self) -> &Self::Target { + // SAFETY: Safe as by the invariant of `IoMem`. + unsafe { Io::from_raw(&self.io) } + } +} From bc4f9045a59963abb142f6a648195ccd73ec39dd Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 17 Jul 2025 12:55:24 -0300 Subject: [PATCH 81/84] rust: platform: add resource accessors The previous patches have added the abstractions for Resources and the ability to map them and therefore read and write the underlying memory . The only thing missing to make this accessible for platform devices is to provide accessors that return instances of IoRequest<'a>. These ensure that the resource are valid only for the lifetime of the platform device, and that the platform device is in the Bound state. Therefore, add these accessors. Also make it possible to retrieve resources from platform devices in Rust using either a name or an index. Acked-by: Miguel Ojeda Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250717-topics-tyr-platform_iomem-v15-3-beca780b77e3@collabora.com [ Remove #[expect(dead_code)] from IoRequest::new() and move SAFETY comments right on top of unsafe blocks to avoid clippy warnings for some (older) clippy versions. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/io/mem.rs | 1 - rust/kernel/platform.rs | 60 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 8e4dfd79079e..50d4ec3eb623 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -28,7 +28,6 @@ impl<'a> IoRequest<'a> { /// /// Callers must ensure that `resource` is valid for `device` during the /// lifetime `'a`. - #[expect(dead_code)] pub(crate) unsafe fn new(device: &'a Device, resource: &'a Resource) -> Self { IoRequest { device, resource } } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 3c0c507c2432..b4d3087aff52 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -5,8 +5,11 @@ //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) use crate::{ - acpi, bindings, container_of, device, driver, + acpi, bindings, container_of, + device::{self, Bound}, + driver, error::{from_result, to_result, Result}, + io::{mem::IoRequest, Resource}, of, prelude::*, types::Opaque, @@ -224,6 +227,61 @@ impl Device { fn as_raw(&self) -> *mut bindings::platform_device { self.0.get() } + + /// Returns the resource at `index`, if any. + pub fn resource_by_index(&self, index: u32) -> Option<&Resource> { + // SAFETY: `self.as_raw()` returns a valid pointer to a `struct platform_device`. + let resource = unsafe { + bindings::platform_get_resource(self.as_raw(), bindings::IORESOURCE_MEM, index) + }; + + if resource.is_null() { + return None; + } + + // SAFETY: `resource` is a valid pointer to a `struct resource` as + // returned by `platform_get_resource`. + Some(unsafe { Resource::from_raw(resource) }) + } + + /// Returns the resource with a given `name`, if any. + pub fn resource_by_name(&self, name: &CStr) -> Option<&Resource> { + // SAFETY: `self.as_raw()` returns a valid pointer to a `struct + // platform_device` and `name` points to a valid C string. + let resource = unsafe { + bindings::platform_get_resource_byname( + self.as_raw(), + bindings::IORESOURCE_MEM, + name.as_char_ptr(), + ) + }; + + if resource.is_null() { + return None; + } + + // SAFETY: `resource` is a valid pointer to a `struct resource` as + // returned by `platform_get_resource`. + Some(unsafe { Resource::from_raw(resource) }) + } +} + +impl Device { + /// Returns an `IoRequest` for the resource at `index`, if any. + pub fn io_request_by_index(&self, index: u32) -> Option> { + self.resource_by_index(index) + // SAFETY: `resource` is a valid resource for `&self` during the + // lifetime of the `IoRequest`. + .map(|resource| unsafe { IoRequest::new(self.as_ref(), resource) }) + } + + /// Returns an `IoRequest` for the resource with a given `name`, if any. + pub fn io_request_by_name(&self, name: &CStr) -> Option> { + self.resource_by_name(name) + // SAFETY: `resource` is a valid resource for `&self` during the + // lifetime of the `IoRequest`. + .map(|resource| unsafe { IoRequest::new(self.as_ref(), resource) }) + } } // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic From 696b2a6ce9487ae278fd239658ca2714cd211e8e Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 19 Jul 2025 16:08:16 +0200 Subject: [PATCH 82/84] rust: io: mem: enable IoRequest doc-tests When introduced, the IoRequest doc-tests did depend on infrastructure added in subsequent patches, hence they temporarily had to be disabled. Now that we have the corresponding platform device infrastructure, enable them. Link: https://lore.kernel.org/r/DBG39YMN2TX6.1VR4PEQSI8PSG@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/io/mem.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 50d4ec3eb623..cc9feb2897d8 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -43,7 +43,7 @@ pub(crate) unsafe fn new(device: &'a Device, resource: &'a Resource) -> S /// The following example uses a [`platform::Device`] for illustration /// purposes. /// - /// ```ignore + /// ```no_run /// use kernel::{bindings, c_str, platform, of, device::Core}; /// struct SampleDriver; /// @@ -101,7 +101,7 @@ pub fn iomap_exclusive_sized( /// The following example uses a [`platform::Device`] for illustration /// purposes. /// - /// ```ignore + /// ```no_run /// use kernel::{bindings, c_str, platform, of, device::Core}; /// struct SampleDriver; /// From 83fb6160727874a588d70b727bc34f367362e6ed Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Tue, 22 Jul 2025 10:54:59 +0200 Subject: [PATCH 83/84] rust: io: fix broken intra-doc link to missing `flags` module There is no `mod flags` in this case, unlike others. Instead, they are associated constants for the `Flags` type. Thus reword the sentence to fix the broken intra-doc link, providing an example of constant and linking to it to clarify which ones we are referring to. Fixes: 493fc33ec252 ("rust: io: add resource abstraction") Signed-off-by: Miguel Ojeda Link: https://lore.kernel.org/r/20250722085500.1360401-1-ojeda@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/io/resource.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index 1d5f367a6e8a..bea3ee0ed87b 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -177,7 +177,8 @@ unsafe impl Sync for Resource {} /// /// They can be combined with the operators `|`, `&`, and `!`. /// -/// Values can be used from the [`flags`] module. +/// Values can be used from the associated constants such as +/// [`Flags::IORESOURCE_IO`]. #[derive(Clone, Copy, PartialEq)] pub struct Flags(c_ulong); From 51a486feac0ca002bee6429f03da0a6c206d0dc5 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Tue, 22 Jul 2025 10:55:00 +0200 Subject: [PATCH 84/84] rust: io: fix broken intra-doc links to `platform::Device` `platform` is not accessible from here. Thus fix the intra-doc links by qualifying the paths a bit more. Fixes: 1d0d4b28513b ("rust: io: mem: add a generic iomem abstraction") Signed-off-by: Miguel Ojeda Link: https://lore.kernel.org/r/20250722085500.1360401-2-ojeda@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/io/mem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index cc9feb2897d8..6f99510bfc3a 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -40,8 +40,8 @@ pub(crate) unsafe fn new(device: &'a Device, resource: &'a Resource) -> S /// /// # Examples /// - /// The following example uses a [`platform::Device`] for illustration - /// purposes. + /// The following example uses a [`kernel::platform::Device`] for + /// illustration purposes. /// /// ```no_run /// use kernel::{bindings, c_str, platform, of, device::Core}; @@ -98,8 +98,8 @@ pub fn iomap_exclusive_sized( /// /// # Examples /// - /// The following example uses a [`platform::Device`] for illustration - /// purposes. + /// The following example uses a [`kernel::platform::Device`] for + /// illustration purposes. /// /// ```no_run /// use kernel::{bindings, c_str, platform, of, device::Core};