* [PATCH v7 08/10] rust: binder: use `LocalModule` for `THIS_MODULE`
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Replace the `THIS_MODULE` static reference in the binder fops with
`this_module::<LocalModule>()`, consistent with the move of
`THIS_MODULE` into the `ModuleMetadata` trait.
Assisted-by: opencode:glm-5.2
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
drivers/android/binder/rust_binder_main.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index dc1941cd2407b..d6ceebbd5f94e 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -17,6 +17,7 @@
bindings::{self, seq_file},
fs::File,
list::{ListArc, ListArcSafe, ListLinksSelfPtr, TryNewListArc},
+ module::this_module,
prelude::*,
seq_file::SeqFile,
seq_print,
@@ -318,7 +319,7 @@ unsafe impl<T> Sync for AssertSync<T> {}
let zeroed_ops = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
let ops = kernel::bindings::file_operations {
- owner: THIS_MODULE.as_ptr(),
+ owner: this_module::<LocalModule>().as_ptr(),
poll: Some(rust_binder_poll),
unlocked_ioctl: Some(rust_binder_ioctl),
compat_ioctl: bindings::compat_ptr_ioctl,
--
2.43.0
^ permalink raw reply related
* [PATCH v7 09/10] rust: macros: remove `THIS_MODULE` static from `module!`
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
All users have been migrated to `ModuleMetadata::THIS_MODULE` const or
`this_module::<LocalModule>()` helper. The `static THIS_MODULE`
generated by the `module!` macro is no longer referenced anywhere,
so remove it to avoid having two sources of the same `ThisModule`
pointer.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/macros/module.rs | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index aa9a618d5d19e..23b6a1b456b80 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -497,22 +497,6 @@ pub(crate) fn module(info: ModuleInfo) -> Result<TokenStream> {
/// Used by the printing macros, e.g. [`info!`].
const __LOG_PREFIX: &[u8] = #name_cstr.to_bytes_with_nul();
- // SAFETY: `__this_module` is constructed by the kernel at load time and will not be
- // freed until the module is unloaded.
- #[cfg(MODULE)]
- static THIS_MODULE: ::kernel::ThisModule = unsafe {
- extern "C" {
- static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
- };
-
- ::kernel::ThisModule::from_ptr(__this_module.get())
- };
-
- #[cfg(not(MODULE))]
- static THIS_MODULE: ::kernel::ThisModule = unsafe {
- ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())
- };
-
/// The `LocalModule` type is the type of the module created by `module!`,
/// `module_pci_driver!`, `module_platform_driver!`, etc.
type LocalModule = #type_;
--
2.43.0
^ permalink raw reply related
* [PATCH v7 07/10] rust: configfs: use `LocalModule` for `THIS_MODULE`
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Replace the `THIS_MODULE` static reference in the `configfs_attrs!`
macro with `this_module::<LocalModule>()`, and update
rnull to import `LocalModule` instead of `THIS_MODULE`, consistent
with the move of `THIS_MODULE` into the `ModuleMetadata` trait.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
drivers/block/rnull/configfs.rs | 6 ++----
rust/kernel/configfs.rs | 9 ++++++---
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index c10a55fc58948..b2547ad1e5ddd 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -1,9 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
-use super::{
- NullBlkDevice,
- THIS_MODULE, //
-};
+use super::NullBlkDevice;
+use crate::LocalModule;
use kernel::{
block::mq::gen_disk::{
GenDisk,
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 2339c6467325d..cd082b83e9e74 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -875,13 +875,14 @@ fn as_ptr(&self) -> *const bindings::config_item_type {
/// configfs::Subsystem<Configuration>,
/// Configuration
/// >::new_with_child_ctor::<N,Child>(
-/// &THIS_MODULE,
+/// ::kernel::module::this_module::<crate::LocalModule>(),
/// &CONFIGURATION_ATTRS
/// );
///
/// &CONFIGURATION_TPE
/// }
/// ```
+#[allow(clippy::crate_in_macro_def)]
#[macro_export]
macro_rules! configfs_attrs {
(
@@ -1021,7 +1022,8 @@ macro_rules! configfs_attrs {
static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> =
$crate::configfs::ItemType::<$container, $data>::new::<N>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
+ $crate::module::this_module::<crate::LocalModule>(),
+ &[<$ data:upper _ATTRS >]
);
)?
@@ -1030,7 +1032,8 @@ macro_rules! configfs_attrs {
$crate::configfs::ItemType<$container, $data> =
$crate::configfs::ItemType::<$container, $data>::
new_with_child_ctor::<N, $child>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
+ $crate::module::this_module::<crate::LocalModule>(),
+ &[<$ data:upper _ATTRS >]
);
)?
--
2.43.0
^ permalink raw reply related
* [PATCH v7 10/10] rust: module: update MAINTAINERS to cover module.rs
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Module types now live in `rust/kernel/module.rs` alongside
`rust/kernel/module_param.rs`. Update the MODULE SUPPORT file pattern
from `rust/kernel/module_param.rs` to `rust/kernel/module*.rs` so both
files are covered.
Assisted-by: opencode:glm-5.2
Link: https://lore.kernel.org/rust-for-linux/8ea21b29-9baf-4926-a16f-7d21c5a1a1b8@suse.com
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
MAINTAINERS | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index e035a3be797c4..74733de3e41ee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17984,7 +17984,7 @@ F: include/linux/module*.h
F: kernel/module/
F: lib/test_kmod.c
F: lib/tests/module/
-F: rust/kernel/module_param.rs
+F: rust/kernel/module*.rs
F: rust/macros/module.rs
F: scripts/module*
F: tools/testing/selftests/kmod/
--
2.43.0
^ permalink raw reply related
* [PATCH v7 05/10] rust: drm: set fops.owner from driver module pointer
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Change `create_fops()` to accept an owner module pointer instead of
hardcoding `null_mut()`, ensuring the kernel correctly tracks the
module owning the DRM device's file operations.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/drm/device.rs | 3 ++-
rust/kernel/drm/gem/mod.rs | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 403fc35353c74..d92cacb665366 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -111,7 +111,8 @@ impl<T: drm::Driver> Device<T> {
fops: &Self::GEM_FOPS,
};
- const GEM_FOPS: bindings::file_operations = drm::gem::create_fops();
+ const GEM_FOPS: bindings::file_operations =
+ drm::gem::create_fops(crate::module::this_module::<T::OwnerModule>().as_ptr());
/// Create a new `drm::Device` for a `drm::Driver`.
pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<ARef<Self>> {
diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs
index 01b5bd47a3332..9a203efc59116 100644
--- a/rust/kernel/drm/gem/mod.rs
+++ b/rust/kernel/drm/gem/mod.rs
@@ -357,10 +357,10 @@ impl<T: DriverObject> AllocImpl for Object<T> {
};
}
-pub(super) const fn create_fops() -> bindings::file_operations {
+pub(super) const fn create_fops(owner: *mut bindings::module) -> bindings::file_operations {
let mut fops: bindings::file_operations = pin_init::zeroed();
- fops.owner = core::ptr::null_mut();
+ fops.owner = owner;
fops.open = Some(bindings::drm_open);
fops.release = Some(bindings::drm_release);
fops.unlocked_ioctl = Some(bindings::drm_ioctl);
--
2.43.0
^ permalink raw reply related
* [PATCH v7 06/10] rust: miscdevice: set fops.owner from driver module pointer
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Set the miscdevice fops owner field from the driver module pointer
via the `this_module::<T::OwnerModule>()` helper, instead of
defaulting to null.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/miscdevice.rs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index 83ce50def5ac9..2a4329f98614e 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -24,12 +24,13 @@
IovIterSource, //
},
mm::virt::VmaNew,
+ module::this_module,
prelude::*,
seq_file::SeqFile,
types::{
ForeignOwnable,
Opaque, //
- },
+ }, //
};
use core::marker::PhantomData;
@@ -430,6 +431,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
} else {
None
},
+ owner: this_module::<T::OwnerModule>().as_ptr(),
..pin_init::zeroed()
};
--
2.43.0
^ permalink raw reply related
* [PATCH v7 03/10] rust: doctest: add LocalModule fallback for #[vtable] ThisModule
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Add a `LocalModule` struct with a null-pointer `ModuleMetadata` impl
in the doctest harness, so that `crate::LocalModule` (auto-inserted
by `#[vtable]`) resolves correctly when there is no `module!` macro.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
scripts/rustdoc_test_gen.rs | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
index ee76e96b41eea..198af4e446c8c 100644
--- a/scripts/rustdoc_test_gen.rs
+++ b/scripts/rustdoc_test_gen.rs
@@ -239,6 +239,22 @@ macro_rules! assert_eq {{
const __LOG_PREFIX: &[u8] = b"rust_doctests_kernel\0";
+/// Dummy module type for doctest context.
+struct LocalModule;
+
+use kernel::{{
+ str::CStr,
+ ModuleMetadata,
+ ThisModule, //
+}};
+use core::ptr::null_mut;
+
+impl ModuleMetadata for LocalModule {{
+ const NAME: &'static CStr = c"rust_doctests_kernel";
+ // SAFETY: `try_module_get`/`module_put` handle null module pointers gracefully.
+ const THIS_MODULE: ThisModule = unsafe {{ ThisModule::from_ptr(null_mut()) }};
+}}
+
{rust_tests}
"#
)
--
2.43.0
^ permalink raw reply related
* [PATCH v7 04/10] rust: macros: auto-insert OwnerModule in #[vtable]
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Auto-add `type OwnerModule: ::kernel::ModuleMetadata;` as a required
associated type on the trait side if not already defined, and
auto-insert `type OwnerModule = crate::LocalModule;` on the impl side
if not explicitly provided, eliminating the need to manually declare
and implement `OwnerModule` in every vtable trait and impl.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Suggested-by: Gary Guo <gary@garyguo.net>
Link: https://lore.kernel.org/all/DIMMWHUOLPSH.13JFRHDKDQJGO@garyguo.net
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/macros/lib.rs | 6 ++++++
rust/macros/vtable.rs | 41 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 2cfd59e0f9e7c..bc7ded353c5ca 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -176,6 +176,12 @@ pub fn module(input: TokenStream) -> TokenStream {
///
/// This macro should not be used when all functions are required.
///
+/// Additionally, this macro automatically handles the `OwnerModule`
+/// associated type: on the trait side, `type OwnerModule: ModuleMetadata;`
+/// is added as a required associated type if not already defined; on the
+/// impl side, `type OwnerModule = LocalModule;` is automatically inserted
+/// if not explicitly defined.
+///
/// # Examples
///
/// ```
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
index c6510b0c4ea1d..be9a5ed8abe5e 100644
--- a/rust/macros/vtable.rs
+++ b/rust/macros/vtable.rs
@@ -30,6 +30,22 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
const USE_VTABLE_ATTR: ();
});
+ // Add `type OwnerModule: ModuleMetadata` as a required associated type if
+ // the trait does not already define it.
+ if !item
+ .items
+ .iter()
+ .any(|i| matches!(i, TraitItem::Type(t) if t.ident == "OwnerModule"))
+ {
+ gen_items.push(parse_quote! {
+ /// The module implementing this vtable trait.
+ ///
+ /// Automatically set to `crate::LocalModule` by the `#[vtable]`
+ /// impl macro.
+ type OwnerModule: ::kernel::ModuleMetadata;
+ });
+ }
+
for item in &item.items {
if let TraitItem::Fn(fn_item) = item {
let name = &fn_item.sig.ident;
@@ -57,12 +73,18 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
let mut gen_items = Vec::new();
- let mut defined_consts = HashSet::new();
+ let mut defined_items = HashSet::new();
- // Iterate over all user-defined constants to gather any possible explicit overrides.
+ // Iterate over all user-defined items to gather any possible explicit overrides.
for item in &item.items {
- if let ImplItem::Const(const_item) = item {
- defined_consts.insert(const_item.ident.clone());
+ match item {
+ ImplItem::Const(const_item) => {
+ defined_items.insert(const_item.ident.clone());
+ }
+ ImplItem::Type(type_item) => {
+ defined_items.insert(type_item.ident.clone());
+ }
+ _ => {}
}
}
@@ -70,6 +92,15 @@ fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
const USE_VTABLE_ATTR: () = ();
});
+ // Auto-insert `type OwnerModule = crate::LocalModule` if not explicitly defined.
+ // `crate::LocalModule` resolves to the real module type (via `module!`) or a
+ // dummy fallback in non-module contexts (e.g., doctests).
+ if !defined_items.contains(&parse_quote!(OwnerModule)) {
+ gen_items.push(parse_quote! {
+ type OwnerModule = crate::LocalModule;
+ });
+ }
+
for item in &item.items {
if let ImplItem::Fn(fn_item) = item {
let name = &fn_item.sig.ident;
@@ -78,7 +109,7 @@ fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
name.span(),
);
// Skip if it's declared already -- this allows user override.
- if defined_consts.contains(&gen_const_name) {
+ if defined_items.contains(&gen_const_name) {
continue;
}
let cfg_attrs = crate::helpers::gather_cfg_attrs(&fn_item.attrs);
--
2.43.0
^ permalink raw reply related
* [PATCH v7 01/10] rust: module: move module types into `module.rs`
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Move `Module`, `InPlaceModule`, `ModuleMetadata` and `ThisModule` from
`lib.rs` into a new `rust/kernel/module.rs`. Re-export them from `lib.rs`
to avoid tree-wide changes.
Switch six bus driver registrations from `module.0` to the public
`ThisModule::as_ptr()` accessor, since the field is no longer visible
outside the new `module` submodule.
No functional change.
Assisted-by: opencode:glm-5.2
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/auxiliary.rs | 2 +-
rust/kernel/i2c.rs | 2 +-
rust/kernel/lib.rs | 75 +++++-------------------------------------------
rust/kernel/module.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/net/phy.rs | 6 +++-
rust/kernel/pci.rs | 2 +-
rust/kernel/platform.rs | 2 +-
rust/kernel/usb.rs | 2 +-
8 files changed, 88 insertions(+), 74 deletions(-)
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 93c0db1f66555..4a02f83240be3 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -63,7 +63,7 @@ unsafe fn register(
// SAFETY: `adrv` is guaranteed to be a valid `DriverType`.
to_result(unsafe {
- bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr())
+ bindings::__auxiliary_driver_register(adrv.get(), module.as_ptr(), name.as_char_ptr())
})
}
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 7b908f0c5a58d..24eff08f47123 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -142,7 +142,7 @@ unsafe fn register(
}
// SAFETY: `idrv` is guaranteed to be a valid `DriverType`.
- to_result(unsafe { bindings::i2c_register_driver(module.0, idrv.get()) })
+ to_result(unsafe { bindings::i2c_register_driver(module.as_ptr(), idrv.get()) })
}
unsafe fn unregister(idrv: &Opaque<Self::DriverType>) {
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index b72b2fbe046d6..040ae85056509 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -93,6 +93,7 @@
pub mod maple_tree;
pub mod miscdevice;
pub mod mm;
+pub mod module;
pub mod module_param;
#[cfg(CONFIG_NET)]
pub mod net;
@@ -139,79 +140,17 @@
#[doc(hidden)]
pub use bindings;
pub use macros;
+pub use module::{
+ InPlaceModule,
+ Module,
+ ModuleMetadata,
+ ThisModule, //
+};
pub use uapi;
/// Prefix to appear before log messages printed from within the `kernel` crate.
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
-/// The top level entrypoint to implementing a kernel module.
-///
-/// For any teardown or cleanup operations, your type may implement [`Drop`].
-pub trait Module: Sized + Sync + Send {
- /// Called at module initialization time.
- ///
- /// Use this method to perform whatever setup or registration your module
- /// should do.
- ///
- /// Equivalent to the `module_init` macro in the C API.
- fn init(module: &'static ThisModule) -> error::Result<Self>;
-}
-
-/// A module that is pinned and initialised in-place.
-pub trait InPlaceModule: Sync + Send {
- /// Creates an initialiser for the module.
- ///
- /// It is called when the module is loaded.
- fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, error::Error>;
-}
-
-impl<T: Module> InPlaceModule for T {
- fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, error::Error> {
- let initer = move |slot: *mut Self| {
- let m = <Self as Module>::init(module)?;
-
- // SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`.
- unsafe { slot.write(m) };
- Ok(())
- };
-
- // SAFETY: On success, `initer` always fully initialises an instance of `Self`.
- unsafe { pin_init::pin_init_from_closure(initer) }
- }
-}
-
-/// Metadata attached to a [`Module`] or [`InPlaceModule`].
-pub trait ModuleMetadata {
- /// The name of the module as specified in the `module!` macro.
- const NAME: &'static crate::str::CStr;
-}
-
-/// Equivalent to `THIS_MODULE` in the C API.
-///
-/// C header: [`include/linux/init.h`](srctree/include/linux/init.h)
-pub struct ThisModule(*mut bindings::module);
-
-// SAFETY: `THIS_MODULE` may be used from all threads within a module.
-unsafe impl Sync for ThisModule {}
-
-impl ThisModule {
- /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
- ///
- /// # Safety
- ///
- /// The pointer must be equal to the right `THIS_MODULE`.
- pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
- ThisModule(ptr)
- }
-
- /// Access the raw pointer for this module.
- ///
- /// It is up to the user to use it correctly.
- pub const fn as_ptr(&self) -> *mut bindings::module {
- self.0
- }
-}
-
#[cfg(not(testlib))]
#[panic_handler]
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
diff --git a/rust/kernel/module.rs b/rust/kernel/module.rs
new file mode 100644
index 0000000000000..be242a82e86d2
--- /dev/null
+++ b/rust/kernel/module.rs
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Module-related types and helpers.
+
+/// The entrypoint to implementing a kernel module.
+///
+/// For any teardown or cleanup operations, your type may implement [`Drop`].
+pub trait Module: Sized + Sync + Send {
+ /// Called at module initialization time.
+ ///
+ /// Use this method to perform whatever setup or registration your module
+ /// should do.
+ ///
+ /// Equivalent to the `module_init` macro in the C API.
+ fn init(module: &'static ThisModule) -> crate::error::Result<Self>;
+}
+
+/// A module that is pinned and initialised in-place.
+pub trait InPlaceModule: Sync + Send {
+ /// Creates an initialiser for the module.
+ ///
+ /// It is called when the module is loaded.
+ fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, crate::error::Error>;
+}
+
+impl<T: Module> InPlaceModule for T {
+ fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, crate::error::Error> {
+ let initer = move |slot: *mut Self| {
+ let m = <Self as Module>::init(module)?;
+
+ // SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`.
+ unsafe { slot.write(m) };
+ Ok(())
+ };
+
+ // SAFETY: On success, `initer` always fully initialises an instance of `Self`.
+ unsafe { pin_init::pin_init_from_closure(initer) }
+ }
+}
+
+/// Metadata attached to a [`Module`] or [`InPlaceModule`].
+pub trait ModuleMetadata {
+ /// The name of the module as specified in the `module!` macro.
+ const NAME: &'static crate::str::CStr;
+}
+
+/// Equivalent to `THIS_MODULE` in the C API.
+///
+/// C header: [`include/linux/init.h`](srctree/include/linux/init.h)
+pub struct ThisModule(*mut crate::bindings::module);
+
+// SAFETY: `THIS_MODULE` may be used from all threads within a module.
+unsafe impl Sync for ThisModule {}
+
+impl ThisModule {
+ /// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
+ ///
+ /// # Safety
+ ///
+ /// The pointer must be equal to the right `THIS_MODULE`.
+ pub const unsafe fn from_ptr(ptr: *mut crate::bindings::module) -> ThisModule {
+ ThisModule(ptr)
+ }
+
+ /// Access the raw pointer for this module.
+ ///
+ /// It is up to the user to use it correctly.
+ pub const fn as_ptr(&self) -> *mut crate::bindings::module {
+ self.0
+ }
+}
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 3ca99db5cccf2..8b7036b8fe480 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -659,7 +659,11 @@ pub fn register(
// the `drivers` slice are initialized properly. `drivers` will not be moved.
// So it's just an FFI call.
to_result(unsafe {
- bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0)
+ bindings::phy_drivers_register(
+ drivers[0].0.get(),
+ drivers.len().try_into()?,
+ module.as_ptr(),
+ )
})?;
// INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`.
Ok(Registration { drivers })
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index af74ddff6114d..916ed2cb6b70b 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -86,7 +86,7 @@ unsafe fn register(
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
to_result(unsafe {
- bindings::__pci_register_driver(pdrv.get(), module.0, name.as_char_ptr())
+ bindings::__pci_register_driver(pdrv.get(), module.as_ptr(), name.as_char_ptr())
})
}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 8917d4ee499fb..9fdbafd53bc21 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -82,7 +82,7 @@ unsafe fn register(
}
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
- to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) })
+ to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.as_ptr()) })
}
unsafe fn unregister(pdrv: &Opaque<Self::DriverType>) {
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 9c17a672cd275..213db32727c17 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -63,7 +63,7 @@ unsafe fn register(
// SAFETY: `udrv` is guaranteed to be a valid `DriverType`.
to_result(unsafe {
- bindings::usb_register_driver(udrv.get(), module.0, name.as_char_ptr())
+ bindings::usb_register_driver(udrv.get(), module.as_ptr(), name.as_char_ptr())
})
}
--
2.43.0
^ permalink raw reply related
* [PATCH v7 00/10] Fix missing fops.owner in Rust DRM/misc abstractions
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
During tyr debugfs development, a kernel NULL pointer dereference was
encountered after `rmmod tyr` while gnome-shell still held /dev/card1 open:
```
[158827.868132] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[158827.868918] Mem abort info:
[158827.869177] ESR = 0x0000000086000004
[158827.869519] EC = 0x21: IABT (current EL), IL = 32 bits
[158827.870000] SET = 0, FnV = 0
[158827.870281] EA = 0, S1PTW = 0
[158827.870571] FSC = 0x04: level 0 translation fault
[158827.871043] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000108dec000
[158827.871623] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000
[158827.872242] Internal error: Oops: 0000000086000004 [#1] SMP
[158827.872246] Modules linked in: tyr sunrpc snd_soc_simple_card rk805_pwrkey snd_soc_simple_card_utils rtw88_8822bu display_connector rtw88_usb rtw88_8822b snd_soc_rockchip_i2s_tdm snd_soc_hdmi_codec
rtw88_core]
[158827.872337] CPU: 4 UID: 1000 PID: 11276 Comm: gnome-s:disk$0 Tainted: G N 7.1.0-rc1+ #331 PREEMPT
[158827.880534] Tainted: [N]=TEST
[158827.880535] Hardware name: FriendlyElec NanoPi R6C/NanoPi R6C, BIOS v1.1 04/09/2025
[158827.880538] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[158827.880542] pc : 0x0
[158827.880547] lr : _RNvNtCs257m05FHVbX_3tyr2vm8pt_unmap+0x8c/0x12c [tyr]
[158827.880578] sp : ffff800083c236b0
[158827.880579] x29: ffff800083c236d0 x28: ffff00013f8a0000 x27: 0000000000000000
[158827.880585] x26: 000000000000007c x25: ffff000108e6ed80 x24: 0000000000401000
[158827.880590] x23: 0000000000000000 x22: 0000000040000000 x21: 0000000000001000
[158827.880595] x20: ffff00010f778138 x19: 0000000000400000 x18: 00000000ffffffff
[158827.880600] x17: 000000040044ffff x16: 045000f2b5503510 x15: 0720072007200720
[158827.880606] x14: 0720072007200720 x13: 0000000000401000 x12: 0000000000400000
[158827.880611] x11: ffff800083c239d0 x10: ffff000141e4fd88 x9 : 0000000000000000
[158827.880615] x8 : 0000000000000000 x7 : 0000000000000000 x6 : 0000000000400000
[158827.880620] x5 : ffff00013f8a0000 x4 : 0000000000000000 x3 : 0000000000000001
[158827.880625] x2 : 0000000000001000 x1 : 0000000000400000 x0 : ffff00010f778138
[158827.880630] Call trace:
[158827.880632] 0x0 (P)
[158827.880635] _RNvXs6_NtCs257m05FHVbX_3tyr2vmNtB5_9GpuVmDataNtNtNtCsgmSOfgXi5CZ_6kernel3drm5gpuvm11DriverGpuVm13sm_step_unmap+0x3c/0x120 [tyr]
[158827.891166] _RNvMs4_NtNtNtCsgmSOfgXi5CZ_6kernel3drm5gpuvm6sm_opsINtB7_5GpuVmNtNtCs257m05FHVbX_3tyr2vm9GpuVmDataE13sm_step_unmapB13_+0x18/0x34 [tyr]
[158827.891187] op_unmap_cb+0x78/0xb0
[158827.891196] __drm_gpuvm_sm_unmap+0x18c/0x1b4
[158827.891204] drm_gpuvm_sm_unmap+0x38/0x4c
[158827.891209] _RNvMs5_NtCs257m05FHVbX_3tyr2vmNtB5_2Vm7exec_op+0x1cc/0x254 [tyr]
[158827.894085] _RNvMs5_NtCs257m05FHVbX_3tyr2vmNtB5_2Vm11unmap_range+0x124/0x188 [tyr]
[158827.894105] _RINvNtCs5hGKnPbRUFW_4core3ptr13drop_in_placeNtNtCs257m05FHVbX_3tyr3gem8KernelBoEBK_+0x44/0xd8 [tyr]
[158827.894125] _RINvNtCs5hGKnPbRUFW_4core3ptr13drop_in_placeINtNtNtCsgmSOfgXi5CZ_6kernel5alloc4kvec3VecNtNtCs257m05FHVbX_3tyr2fw7SectionNtNtBL_9allocator7KmallocEEB1r_+0x3c/0x100 [tyr]
[158827.894147] _RINvNtCs5hGKnPbRUFW_4core3ptr13drop_in_placeINtNtNtCsgmSOfgXi5CZ_6kernel4sync3arc3ArcNtNtCs257m05FHVbX_3tyr2fw8FirmwareEEB1p_+0x94/0x190 [tyr]
[158827.894167] _RNvMs4_NtNtCsgmSOfgXi5CZ_6kernel3drm6deviceINtB5_6DeviceNtNtCs257m05FHVbX_3tyr6driver12TyrDrmDriverE7releaseBW_+0x30/0x98 [tyr]
[158827.899550] drm_dev_put.part.0+0x88/0xc0
[158827.899557] drm_minor_release+0x18/0x28
[158827.899562] drm_release+0x144/0x170
[158827.899567] __fput+0xe4/0x30c
[158827.899573] ____fput+0x14/0x20
[158827.899579] task_work_run+0x7c/0xe8
[158827.899586] do_exit+0x2a8/0xac4
[158827.899590] do_group_exit+0x34/0x90
[158827.899594] get_signal+0xaac/0xabc
[158827.899599] arch_do_signal_or_restart+0x90/0x3e8
[158827.899606] exit_to_user_mode_loop+0x140/0x1d0
[158827.899613] el0_svc+0x2f4/0x2f8
[158827.899620] el0t_64_sync_handler+0xa0/0xe4
[158827.899627] el0t_64_sync+0x198/0x19c
[158827.899632] ---[ end trace 0000000000000000 ]---
```
The root cause: `fops.owner` was `NULL` in Rust DRM drivers, so the kernel
never blocked module unloading while file descriptors were open. This leads to
use-after-free when drm_release (or other fops) is called on freed module code.
The series moves `THIS_MODULE` into the `ModuleMetadata` as a const, threads it
through `#[vtable]` to set `fops.owner` in DRM/miscdevice, and updates configfs
and rnull to use `this_module::<LocalModule>()`.
Assisted-by: opencode:glm-5.2
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
Changes in v7:
- Use `crate::LocalModule` in `configfs_attrs!` and silence `clippy::crate_in_macro_def`, per Gary's review.
- Link to v6: https://lore.kernel.org/r/20260624-fix-fops-owner-v6-0-5295e333cb3e@linux.dev
Changes in v6:
- Update MAINTAINERS to cover the new `rust/kernel/module.rs`.
- Link to v5: https://lore.kernel.org/r/20260624-fix-fops-owner-v5-0-aa1cba242f05@linux.dev
Changes in v5:
- Add `#[inline]` to the `this_module()` helper.
- Fix configfs doc comment to reference `crate::LocalModule` instead of
bare `LocalModule`.
- Link to v4: https://lore.kernel.org/r/20260623-fix-fops-owner-v4-0-0daf5f077d5c@linux.dev
Changes in v4:
- Move module-related types into a new `rust/kernel/module.rs`.
- Migrate binder from the `module!`-generated `THIS_MODULE` static to
`this_module::<LocalModule>()`.
- Reorganise the series so that every commit builds independently, and
drop the legacy `THIS_MODULE` static once all users are migrated.
- Link to v3: https://lore.kernel.org/r/20260622-fix-fops-owner-v3-0-49d45cb37032@linux.dev
Changes in v3:
- Renamed vtable associated type `ThisModule` to `OwnerModule`
- Added `this_module()` helper for ergonomic `THIS_MODULE` access
- Refined vtable macro implementation: one-liner detection and single `defined_items` set
- Reordered commits to place doctest fallback before vtable auto-insert
- Link to v2: https://lore.kernel.org/r/20260521-fix-fops-owner-v2-0-fd99079c5a04@linux.dev
Changes in v2:
- Merged old `static THIS_MODULE` and v1's `MODULE_PTR` into a single
`ModuleMetadata::THIS_MODULE` const
- `#[vtable]` macro now auto-inserts `type ThisModule`, removing all per-driver
manual patches from v1
- Added configfs & rnull usage site updates and doctest `LocalModule` fallback
- Link to v1: https://lore.kernel.org/r/20260519-fix-fops-owner-v1-0-2ded9830da14@linux.dev
---
Alvin Sun (10):
rust: module: move module types into `module.rs`
rust: module: add `THIS_MODULE` const to `ModuleMetadata` trait
rust: doctest: add LocalModule fallback for #[vtable] ThisModule
rust: macros: auto-insert OwnerModule in #[vtable]
rust: drm: set fops.owner from driver module pointer
rust: miscdevice: set fops.owner from driver module pointer
rust: configfs: use `LocalModule` for `THIS_MODULE`
rust: binder: use `LocalModule` for `THIS_MODULE`
rust: macros: remove `THIS_MODULE` static from `module!`
rust: module: update MAINTAINERS to cover module.rs
MAINTAINERS | 2 +-
drivers/android/binder/rust_binder_main.rs | 3 +-
drivers/block/rnull/configfs.rs | 6 +--
rust/kernel/auxiliary.rs | 2 +-
rust/kernel/configfs.rs | 9 ++--
rust/kernel/drm/device.rs | 3 +-
rust/kernel/drm/gem/mod.rs | 4 +-
rust/kernel/i2c.rs | 2 +-
rust/kernel/lib.rs | 75 +++-------------------------
rust/kernel/miscdevice.rs | 4 +-
rust/kernel/module.rs | 80 ++++++++++++++++++++++++++++++
rust/kernel/net/phy.rs | 6 ++-
rust/kernel/pci.rs | 2 +-
rust/kernel/platform.rs | 2 +-
rust/kernel/usb.rs | 2 +-
rust/macros/lib.rs | 6 +++
rust/macros/module.rs | 34 ++++++-------
rust/macros/vtable.rs | 41 +++++++++++++--
scripts/rustdoc_test_gen.rs | 16 ++++++
19 files changed, 190 insertions(+), 109 deletions(-)
---
base-commit: b7e5ac83cb16f7ffd11dc23736f84276602100ed
change-id: 20260519-fix-fops-owner-e3a77bb27c6c
prerequisite-change-id: 20260519-miscdev-use-format-9ab7e83b1c11:v3
prerequisite-patch-id: 405b334ff0d48ad350014f05a2321bdbaa025400
prerequisite-patch-id: 604b631c81d5423f4ebb2e12ba2d22e9ce371bfc
prerequisite-patch-id: cb550d94cefe01920e0d3ced2b2bcbecd76f3907
prerequisite-patch-id: 3bc830839742591460cb86d9472c04f4686dc600
prerequisite-patch-id: 571058244bc8c7088638d2e3225713011246c7e9
prerequisite-patch-id: 347c5a3c6dbef9832bfce8419fc23e6e08ba477f
prerequisite-patch-id: 3e202d988b56b88446f7535e90d3f00cf5f15701
Best regards,
--
Alvin Sun <alvin.sun@linux.dev>
^ permalink raw reply
* [PATCH v7 02/10] rust: module: add `THIS_MODULE` const to `ModuleMetadata` trait
From: Alvin Sun @ 2026-06-27 9:28 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci, Alvin Sun
In-Reply-To: <20260627-fix-fops-owner-v7-0-33cd3990edf0@linux.dev>
Since `const_refs_to_static` has been stable as of the MSRV bump, a
`ThisModule` pointer can now be used in const contexts.
Add a `THIS_MODULE` const to the `ModuleMetadata` trait so that modules
can provide their `ThisModule` pointer in const contexts such as static
`file_operations`.
Add a `this_module()` helper to retrieve the `THIS_MODULE` pointer of a
given module type, and update `__init` to use it instead of the
`THIS_MODULE` static generated by the `module!` macro.
The `static THIS_MODULE` generated by the `module!` macro is retained
for backwards compatibility with existing users and removed in a later
patch once all references have been migrated.
Assisted-by: opencode:glm-5.2
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
rust/kernel/module.rs | 9 +++++++++
rust/macros/module.rs | 18 +++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/module.rs b/rust/kernel/module.rs
index be242a82e86d2..d713705984477 100644
--- a/rust/kernel/module.rs
+++ b/rust/kernel/module.rs
@@ -42,6 +42,15 @@ fn init(module: &'static ThisModule) -> impl pin_init::PinInit<Self, crate::erro
pub trait ModuleMetadata {
/// The name of the module as specified in the `module!` macro.
const NAME: &'static crate::str::CStr;
+
+ /// The module's `THIS_MODULE` pointer.
+ const THIS_MODULE: ThisModule;
+}
+
+/// Returns a reference to the `THIS_MODULE` of the given module type.
+#[inline]
+pub const fn this_module<M: ModuleMetadata>() -> &'static ThisModule {
+ &M::THIS_MODULE
}
/// Equivalent to `THIS_MODULE` in the C API.
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 06c18e2075083..aa9a618d5d19e 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -519,6 +519,22 @@ pub(crate) fn module(info: ModuleInfo) -> Result<TokenStream> {
impl ::kernel::ModuleMetadata for #type_ {
const NAME: &'static ::kernel::str::CStr = #name_cstr;
+
+ #[cfg(MODULE)]
+ const THIS_MODULE: ::kernel::ThisModule = {
+ extern "C" {
+ static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
+ }
+
+ // SAFETY: `__this_module` is constructed by the kernel at load time
+ // and lives until the module is unloaded.
+ unsafe { ::kernel::ThisModule::from_ptr(__this_module.get()) }
+ };
+
+ #[cfg(not(MODULE))]
+ const THIS_MODULE: ::kernel::ThisModule = unsafe {
+ ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())
+ };
}
// Double nested modules, since then nobody can access the public items inside.
@@ -616,7 +632,7 @@ pub extern "C" fn #ident_exit() {
/// This function must only be called once.
unsafe fn __init() -> ::kernel::ffi::c_int {
let initer = <super::super::LocalModule as ::kernel::InPlaceModule>::init(
- &super::super::THIS_MODULE
+ ::kernel::module::this_module::<super::super::LocalModule>()
);
// SAFETY: No data race, since `__MOD` can only be accessed by this module
// and there only `__init` and `__exit` access it. These functions are only
--
2.43.0
^ permalink raw reply related
* Re: block: partitions: Use seq_buf_putc() in cmdline_partition()
From: Markus Elfring @ 2026-06-27 7:28 UTC (permalink / raw)
To: Christophe Jaillet, linux-block, Andy Shevchenko, Jens Axboe,
Josh Law, Kees Cook
Cc: LKML, kernel-janitors, Woradorn Laodhanadhaworn, Steven Rostedt
In-Reply-To: <630e1d4c-3302-4d2c-a90c-5b3aedfe8f6b@wanadoo.fr>
…
>>> block/partitions/cmdline.c | 4 +---
>>
>> Will development interests grow for remaining update candidates?
>
> These changes are pointless and already performed by the compiler.
I got other impressions.
> See [1].
> So from my PoV, they only trash git blame output and make future backport harder.
>
> Just my 2c.
…
> [1]: https://elixir.bootlin.com/linux/v7.1-rc6/source/include/linux/seq_file.h#L127
Why do you refer to the sequence file programming interface
when I propose refinements for the application of sequence buffers?
https://elixir.bootlin.com/linux/v7.1.1/source/include/linux/seq_buf.h#L176-L177
Regards,
Markus
^ permalink raw reply
* [PATCH 3/3] zram: reset per-priority params when changing algorithm before init
From: Haoqin Huang @ 2026-06-27 7:02 UTC (permalink / raw)
To: minchan, senozhatsky, axboe, terrelln, dsterba, akpm
Cc: linux-kernel, linux-block, haoqinhuang7, rongwei.wrw,
Haoqin Huang, Rongwei Wang
In-Reply-To: <20260627070216.13511-1-haoqinhuang7@gmail.com>
From: Haoqin Huang <haoqinhuang@tencent.com>
Parameters validated against one algorithm may be invalid for another
(e.g. lz4 accepts level=65535 but zstd does not). Although algorithm
changes are blocked after disksize is set, they are allowed before
device initialization. Reset per-priority params on algorithm change
so that stale parameters do not silently carry over.
Signed-off-by: Haoqin Huang <haoqinhuang@tencent.com>
Reviewed-by: Rongwei Wang <zigiwang@tencent.com>
---
drivers/block/zram/zram_drv.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index a667d0672720..6b47586e8718 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -57,6 +57,7 @@ static size_t huge_class_size;
static const struct block_device_operations zram_devops;
static void slot_free(struct zram *zram, u32 index);
+static void comp_params_reset(struct zram *zram, u32 prio);
#define slot_dep_map(zram, index) (&(zram)->table[(index)].dep_map)
static void slot_lock_init(struct zram *zram, u32 index)
@@ -1681,6 +1682,7 @@ static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf)
}
comp_algorithm_set(zram, prio, alg);
+ comp_params_reset(zram, prio);
return 0;
}
--
2.43.7
^ permalink raw reply related
* [PATCH 2/3] zram: add per-backend capability flags and validate parameters early
From: Haoqin Huang @ 2026-06-27 7:02 UTC (permalink / raw)
To: minchan, senozhatsky, axboe, terrelln, dsterba, akpm
Cc: linux-kernel, linux-block, haoqinhuang7, rongwei.wrw,
Haoqin Huang, Rongwei Wang
In-Reply-To: <20260627070216.13511-1-haoqinhuang7@gmail.com>
From: Haoqin Huang <haoqinhuang@tencent.com>
Writing dict or level parameters for algorithms that don't support
them was silently accepted but had no effect. Out-of-range levels
were silently clamped by the underlying library. Dict read failures
always lost the real error from kernel_read_file_from_path().
Add caps, level_min and level_max to zcomp_ops and validate
user-supplied parameters in algorithm_params_store() before storing,
giving immediate error feedback. Also fix comp_params_store() to
read the new dict into a temporary buffer before resetting old
parameters, making the update atomic.
Signed-off-by: Haoqin Huang <haoqinhuang@tencent.com>
Reviewed-by: Rongwei Wang <zigiwang@tencent.com>
---
drivers/block/zram/backend_842.c | 1 +
drivers/block/zram/backend_deflate.c | 3 +++
drivers/block/zram/backend_lz4.c | 3 +++
drivers/block/zram/backend_lz4hc.c | 3 +++
drivers/block/zram/backend_lzo.c | 1 +
drivers/block/zram/backend_lzorle.c | 1 +
drivers/block/zram/backend_zstd.c | 3 +++
drivers/block/zram/zcomp.c | 23 ++++++++++++++++++++
drivers/block/zram/zcomp.h | 8 +++++++
drivers/block/zram/zram_drv.c | 32 +++++++++++++++++++++-------
include/linux/zstd_lib.h | 1 +
lib/zstd/compress/clevels.h | 1 -
12 files changed, 71 insertions(+), 9 deletions(-)
diff --git a/drivers/block/zram/backend_842.c b/drivers/block/zram/backend_842.c
index 10d9d5c60f53..d796ebda1fa0 100644
--- a/drivers/block/zram/backend_842.c
+++ b/drivers/block/zram/backend_842.c
@@ -57,5 +57,6 @@ const struct zcomp_ops backend_842 = {
.destroy_ctx = destroy_842,
.setup_params = setup_params_842,
.release_params = release_params_842,
+ .caps = 0,
.name = "842",
};
diff --git a/drivers/block/zram/backend_deflate.c b/drivers/block/zram/backend_deflate.c
index f92a52a720d1..cedc3daad33a 100644
--- a/drivers/block/zram/backend_deflate.c
+++ b/drivers/block/zram/backend_deflate.c
@@ -144,5 +144,8 @@ const struct zcomp_ops backend_deflate = {
.destroy_ctx = deflate_destroy,
.setup_params = deflate_setup_params,
.release_params = deflate_release_params,
+ .caps = ZCOMP_CAP_LEVEL,
+ .level_min = Z_DEFAULT_COMPRESSION,
+ .level_max = Z_BEST_COMPRESSION,
.name = "deflate",
};
diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c
index c449d511ba86..bd1e5ca4d134 100644
--- a/drivers/block/zram/backend_lz4.c
+++ b/drivers/block/zram/backend_lz4.c
@@ -146,5 +146,8 @@ const struct zcomp_ops backend_lz4 = {
.destroy_ctx = lz4_destroy,
.setup_params = lz4_setup_params,
.release_params = lz4_release_params,
+ .caps = ZCOMP_CAP_DICT | ZCOMP_CAP_LEVEL,
+ .level_min = LZ4_ACCELERATION_DEFAULT,
+ .level_max = 65535,
.name = "lz4",
};
diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c
index f6a336acfe20..0e0d7c68a7d4 100644
--- a/drivers/block/zram/backend_lz4hc.c
+++ b/drivers/block/zram/backend_lz4hc.c
@@ -124,5 +124,8 @@ const struct zcomp_ops backend_lz4hc = {
.destroy_ctx = lz4hc_destroy,
.setup_params = lz4hc_setup_params,
.release_params = lz4hc_release_params,
+ .caps = ZCOMP_CAP_DICT | ZCOMP_CAP_LEVEL,
+ .level_min = LZ4HC_MIN_CLEVEL,
+ .level_max = LZ4HC_MAX_CLEVEL,
.name = "lz4hc",
};
diff --git a/drivers/block/zram/backend_lzo.c b/drivers/block/zram/backend_lzo.c
index 4c906beaae6b..965f007e2ca8 100644
--- a/drivers/block/zram/backend_lzo.c
+++ b/drivers/block/zram/backend_lzo.c
@@ -55,5 +55,6 @@ const struct zcomp_ops backend_lzo = {
.destroy_ctx = lzo_destroy,
.setup_params = lzo_setup_params,
.release_params = lzo_release_params,
+ .caps = 0,
.name = "lzo",
};
diff --git a/drivers/block/zram/backend_lzorle.c b/drivers/block/zram/backend_lzorle.c
index 10640c96cbfc..757b4598be03 100644
--- a/drivers/block/zram/backend_lzorle.c
+++ b/drivers/block/zram/backend_lzorle.c
@@ -55,5 +55,6 @@ const struct zcomp_ops backend_lzorle = {
.destroy_ctx = lzorle_destroy,
.setup_params = lzorle_setup_params,
.release_params = lzorle_release_params,
+ .caps = 0,
.name = "lzo-rle",
};
diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index 2584f47c9b3c..0fbd2460883a 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -212,5 +212,8 @@ const struct zcomp_ops backend_zstd = {
.destroy_ctx = zstd_destroy,
.setup_params = zstd_setup_params,
.release_params = zstd_release_params,
+ .caps = ZCOMP_CAP_DICT | ZCOMP_CAP_LEVEL,
+ .level_min = (int)-ZSTD_TARGETLENGTH_MAX,
+ .level_max = ZSTD_MAX_CLEVEL,
.name = "zstd",
};
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 974c4691887e..15de28b50d42 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -9,6 +9,9 @@
#include <linux/cpuhotplug.h>
#include <linux/vmalloc.h>
#include <linux/sysfs.h>
+#include <linux/lz4.h>
+#include <linux/zlib.h>
+#include <linux/zstd.h>
#include "zcomp.h"
@@ -94,6 +97,26 @@ const char *zcomp_lookup_backend_name(const char *comp)
return NULL;
}
+unsigned int zcomp_get_caps(const char *comp)
+{
+ const struct zcomp_ops *backend = lookup_backend_ops(comp);
+
+ return backend ? backend->caps : 0;
+}
+
+int zcomp_validate_level(const char *comp, s32 level)
+{
+ const struct zcomp_ops *backend = lookup_backend_ops(comp);
+
+ if (!backend)
+ return -EINVAL;
+ if (!(backend->caps & ZCOMP_CAP_LEVEL))
+ return -EOPNOTSUPP;
+ if (level < backend->level_min || level > backend->level_max)
+ return -EINVAL;
+ return 0;
+}
+
/* show available compressors */
ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at)
{
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 81a0f3f6ff48..16f812a94c67 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -7,6 +7,9 @@
#define ZCOMP_PARAM_NOT_SET INT_MIN
+#define ZCOMP_CAP_DICT BIT(0) /* dictionary support */
+#define ZCOMP_CAP_LEVEL BIT(1) /* adjustable compression level */
+
struct deflate_params {
s32 winbits;
};
@@ -66,6 +69,9 @@ struct zcomp_ops {
int (*setup_params)(struct zcomp_params *params);
void (*release_params)(struct zcomp_params *params);
+ unsigned int caps;
+ s32 level_min;
+ s32 level_max;
const char *name;
};
@@ -81,6 +87,8 @@ int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node);
int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node);
ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at);
const char *zcomp_lookup_backend_name(const char *comp);
+unsigned int zcomp_get_caps(const char *comp);
+int zcomp_validate_level(const char *comp, s32 level);
struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params);
void zcomp_destroy(struct zcomp *comp);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index ace65c586072..a667d0672720 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1699,21 +1699,24 @@ static int comp_params_store(struct zram *zram, u32 prio, s32 level,
const char *dict_path,
struct deflate_params *deflate_params)
{
+ void *new_dict = NULL;
ssize_t sz = 0;
- comp_params_reset(zram, prio);
-
if (dict_path) {
- sz = kernel_read_file_from_path(dict_path, 0,
- &zram->params[prio].dict,
- INT_MAX,
- NULL,
- READING_POLICY);
- if (sz < 0)
+ sz = kernel_read_file_from_path(dict_path, 0, &new_dict,
+ INT_MAX, NULL, READING_POLICY);
+ if (sz < 0) {
+ vfree(new_dict);
+ return sz;
+ } else if (sz == 0) {
+ vfree(new_dict);
return -EINVAL;
+ }
}
+ comp_params_reset(zram, prio);
zram->params[prio].dict_sz = sz;
+ zram->params[prio].dict = new_dict;
zram->params[prio].level = level;
zram->params[prio].deflate.winbits = deflate_params->winbits;
return 0;
@@ -1794,6 +1797,19 @@ static ssize_t algorithm_params_store(struct device *dev,
return -EINVAL;
}
+ if (zram->comp_algs[prio]) {
+ unsigned int caps = zcomp_get_caps(zram->comp_algs[prio]);
+
+ if (dict_path && !(caps & ZCOMP_CAP_DICT))
+ return -EOPNOTSUPP;
+
+ if (level != ZCOMP_PARAM_NOT_SET) {
+ ret = zcomp_validate_level(zram->comp_algs[prio], level);
+ if (ret)
+ return ret;
+ }
+ }
+
ret = comp_params_store(zram, prio, level, dict_path, &deflate_params);
return ret ? ret : len;
}
diff --git a/include/linux/zstd_lib.h b/include/linux/zstd_lib.h
index e295d4125dde..f4b26844e53a 100644
--- a/include/linux/zstd_lib.h
+++ b/include/linux/zstd_lib.h
@@ -1241,6 +1241,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
#define ZSTD_SEARCHLOG_MIN 1
#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */
#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */
+#define ZSTD_MAX_CLEVEL 22
#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX
#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */
#define ZSTD_STRATEGY_MIN ZSTD_fast
diff --git a/lib/zstd/compress/clevels.h b/lib/zstd/compress/clevels.h
index 6ab8be6532ef..db3b275b502e 100644
--- a/lib/zstd/compress/clevels.h
+++ b/lib/zstd/compress/clevels.h
@@ -17,7 +17,6 @@
/*-===== Pre-defined compression levels =====-*/
-#define ZSTD_MAX_CLEVEL 22
__attribute__((__unused__))
--
2.43.7
^ permalink raw reply related
* [PATCH 1/3] zram: fix zstd dict use-after-free on per-CPU error path
From: Haoqin Huang @ 2026-06-27 7:02 UTC (permalink / raw)
To: minchan, senozhatsky, axboe, terrelln, dsterba, akpm
Cc: linux-kernel, linux-block, haoqinhuang7, rongwei.wrw,
Haoqin Huang, Rongwei Wang
From: Haoqin Huang <haoqinhuang@tencent.com>
zstd_setup_params() creates global cdict and ddict stored in
params->drv_data, shared across all per-CPU contexts. When a
per-CPU zstd_create() failed, its error path called
zstd_release_params() which freed those shared objects while
other per-CPU contexts might already hold references to them.
Remove the premature zstd_release_params() from the per-CPU
error path, the global cdict/ddict are properly released later
by zstd_release_params(), called from zcomp_init()'s cleanup
or from zcomp_destroy().
Fixes: 6a559ecd6e7e ("zram: add dictionary support to zstd backend")
Signed-off-by: Haoqin Huang <haoqinhuang@tencent.com>
Reviewed-by: Rongwei Wang <zigiwang@tencent.com>
---
drivers/block/zram/backend_zstd.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index d00b548056dc..2584f47c9b3c 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -161,7 +161,6 @@ static int zstd_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
return 0;
error:
- zstd_release_params(params);
zstd_destroy(ctx);
return -EINVAL;
}
--
2.43.7
^ permalink raw reply related
* [RFC PATCH 0/2] Avoid software ref tag remapping for NVMe devices
From: Caleb Sander Mateos @ 2026-06-27 6:19 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
Martin K. Petersen
Cc: linux-block, linux-nvme, linux-kernel, Caleb Sander Mateos
Currently, each bio has a reference tag seed which is used to generate
the sequential ref tags in its protection information. In principle, the
ref tag seed can be any value as long as the same value is used when
blocks are written as when they are read back. However, some devices
(e.g. T10 DIF) require the ref tags to match the low bits of the
absolute integrity interval numbers. So the block integrity layer always
"remaps" ref tags to absolute integrity intervals using
blk_integrity_prepare() on writes and blk_integrity_complete() on reads.
On devices which do support an explicit "expected initial reference tag"
field in addition to the logical block address on each I/O, the software
ref tag remapping could be skipped by just passing the ref tag seed as
the expected initial ref tag.
Introduce a BLK_EXPECTED_REF_TAG_CAPABLE flag for devices to advertise
support for an expected initial ref tag. On devices that set this flag,
skip the block integrity layer ref tag remapping. Also take care not to
merge bios with non-contiguous ref tags, as the merged bio's ref tags
would no longer come from a single ref tag seed.
Set BLK_EXPECTED_REF_TAG_CAPABLE for NVMe devices and plumb the ref tag
seed (if provided) to the NVMe Read/Write (E)ILBRT field.
One potential concern would be NVMe devices which already have ref tags
written by an old kernel, which did perform the remapping (persisting
ref tags set to the low bits of the LBAs). When a new kernel that skips
the remapping reads back the ref tags, it would expect them to match the
ref tag seed, which would fail the ref tag verification.
Caleb Sander Mateos (2):
blk-integrity: add BLK_EXPECTED_REF_TAG_CAPABLE
nvme/core: advertise BLK_EXPECTED_REF_TAG_CAPABLE
block/blk-integrity.c | 18 ++++++++++++++++++
block/t10-pi.c | 3 ++-
drivers/nvme/host/core.c | 20 ++++++++++----------
include/linux/blk-integrity.h | 2 ++
include/linux/t10-pi.h | 5 -----
5 files changed, 32 insertions(+), 16 deletions(-)
--
2.54.0
^ permalink raw reply
* [RFC PATCH 2/2] nvme/core: advertise BLK_EXPECTED_REF_TAG_CAPABLE
From: Caleb Sander Mateos @ 2026-06-27 6:19 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
Martin K. Petersen
Cc: linux-block, linux-nvme, linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627061933.2187447-1-csander@purestorage.com>
NVMe Read, Write, and Write Zeroes commands include an (E)ILBRT field to
specify the expected initial reference tag for the controller to check
against the ref tags in the protection information buffer. However, the
NVMe driver currently always sets (E)ILBRT to the lower bits of the LBA.
The block integrity layer generates/verifies the PI ref tags according
to the bio's ref tag seed, so it must "remap" the ref tags, adjusting
for the difference between the ref tag seed and the absolute integrity
interval number (= LBA).
If a request has an integrity payload, set (E)ILBRT to its ref tag seed
so no ref tag remapping is required. Set BLK_EXPECTED_REF_TAG_CAPABLE in
NVMe devices' enum blk_integrity_flags to skip the block integrity layer
ref tag remapping.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
drivers/nvme/host/core.c | 20 ++++++++++----------
include/linux/t10-pi.h | 5 -----
2 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 453c1f0b2dd0..8202ca706c97 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -914,34 +914,34 @@ static void nvme_set_app_tag(struct request *req, struct nvme_command *cmnd)
}
static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd,
struct request *req)
{
- u32 upper, lower;
- u64 ref48;
+ u64 ref_tag;
/* only type1 and type 2 PI formats have a reftag */
switch (ns->head->pi_type) {
case NVME_NS_DPS_PI_TYPE1:
case NVME_NS_DPS_PI_TYPE2:
break;
default:
return;
}
+ ref_tag = full_pi_ref_tag(req);
+ if (blk_integrity_rq(req))
+ ref_tag = bio_integrity(req->bio)->bip_iter.bi_sector;
+
/* both rw and write zeroes share the same reftag format */
switch (ns->head->guard_type) {
case NVME_NVM_NS_16B_GUARD:
- cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req));
+ cmnd->rw.reftag = cpu_to_le32(lower_32_bits(ref_tag));
break;
case NVME_NVM_NS_64B_GUARD:
- ref48 = ext_pi_ref_tag(req);
- lower = lower_32_bits(ref48);
- upper = upper_32_bits(ref48);
-
- cmnd->rw.reftag = cpu_to_le32(lower);
- cmnd->rw.cdw3 = cpu_to_le32(upper);
+ ref_tag = lower_48_bits(ref_tag);
+ cmnd->rw.reftag = cpu_to_le32(lower_32_bits(ref_tag));
+ cmnd->rw.cdw3 = cpu_to_le32(upper_32_bits(ref_tag));
break;
default:
break;
}
}
@@ -1889,11 +1889,11 @@ static bool nvme_init_integrity(struct nvme_ns_head *head,
break;
default:
break;
}
- bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE;
+ bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE | BLK_EXPECTED_REF_TAG_CAPABLE;
bi->metadata_size = head->ms;
if (bi->csum_type) {
bi->pi_tuple_size = head->pi_size;
bi->pi_offset = info->pi_offset;
}
diff --git a/include/linux/t10-pi.h b/include/linux/t10-pi.h
index b6c2496866ea..5cf4859877f5 100644
--- a/include/linux/t10-pi.h
+++ b/include/linux/t10-pi.h
@@ -66,11 +66,6 @@ struct crc64_pi_tuple {
static inline u64 lower_48_bits(u64 n)
{
return n & ((1ull << 48) - 1);
}
-static inline u64 ext_pi_ref_tag(struct request *rq)
-{
- return lower_48_bits(full_pi_ref_tag(rq));
-}
-
#endif
--
2.54.0
^ permalink raw reply related
* [RFC PATCH 1/2] blk-integrity: add BLK_EXPECTED_REF_TAG_CAPABLE
From: Caleb Sander Mateos @ 2026-06-27 6:19 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
Martin K. Petersen
Cc: linux-block, linux-nvme, linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627061933.2187447-1-csander@purestorage.com>
Add BLK_EXPECTED_REF_TAG_CAPABLE to enum blk_integrity_flags to allow a
device to report support for specifying an expected initial ref tag in
I/O. Make blk_integrity_remap() a no-op if the flag is set, as the ref
tag seed used to generate/verify ref tags in the protection information
can be passed as the expected initial ref tag.
Ref tag remapping is necessary to merge bios with non-contiguous ref tag
seeds, as it converts both bios' ref tags to/from absolute integrity
interval numbers, which are contiguous. So don't merge bios to a
BLK_EXPECTED_REF_TAG_CAPABLE device if the next bio's ref tag seed
doesn't match the ref tag that would follow the end of the first bio.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
block/blk-integrity.c | 18 ++++++++++++++++++
block/t10-pi.c | 3 ++-
include/linux/blk-integrity.h | 2 ++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 964eebbee14d..85ebe13f0912 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -139,10 +139,12 @@ EXPORT_SYMBOL_GPL(blk_rq_integrity_map_user);
bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
struct request *next)
{
struct bio_integrity_payload *bip, *bip_next;
+ struct blk_integrity *bi;
+ u64 intervals;
if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0)
return true;
if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0)
@@ -155,10 +157,17 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
if (bip->bip_flags & BIP_CHECK_APPTAG &&
bip->app_tag != bip_next->app_tag)
return false;
+ bi = blk_get_integrity(req->bio->bi_bdev->bd_disk);
+ intervals = blk_rq_bytes(req) >> bi->interval_exp;
+ if (bip->bip_flags & BIP_CHECK_REFTAG &&
+ bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE &&
+ bip->bip_iter.bi_sector + intervals != bip_next->bip_iter.bi_sector)
+ return false;
+
if (req->nr_integrity_segments + next->nr_integrity_segments >
q->limits.max_integrity_segments)
return false;
if (integrity_req_gap_back_merge(req, next->bio))
@@ -169,11 +178,13 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
struct bio *bio)
{
struct bio_integrity_payload *bip, *bip_bio = bio_integrity(bio);
+ struct blk_integrity *bi;
int nr_integrity_segs;
+ u64 intervals;
if (blk_integrity_rq(req) == 0 && bip_bio == NULL)
return true;
if (blk_integrity_rq(req) == 0 || bip_bio == NULL)
@@ -185,10 +196,17 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
if (bip->bip_flags & BIP_CHECK_APPTAG &&
bip->app_tag != bip_bio->app_tag)
return false;
+ bi = blk_get_integrity(req->bio->bi_bdev->bd_disk);
+ intervals = blk_rq_bytes(req) >> bi->interval_exp;
+ if (bip->bip_flags & BIP_CHECK_REFTAG &&
+ bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE &&
+ bip->bip_iter.bi_sector + intervals != bip_bio->bip_iter.bi_sector)
+ return false;
+
nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
if (req->nr_integrity_segments + nr_integrity_segs >
q->limits.max_integrity_segments)
return false;
diff --git a/block/t10-pi.c b/block/t10-pi.c
index 71367fd082bd..becf3e316b06 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -545,11 +545,12 @@ static void blk_integrity_remap(struct request *rq, unsigned int nr_bytes,
struct blk_integrity *bi = &rq->q->limits.integrity;
u64 ref = bio_integrity_intervals(bi, blk_rq_pos(rq));
unsigned intervals = nr_bytes >> bi->interval_exp;
struct bio *bio;
- if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
+ if (!(bi->flags & BLK_INTEGRITY_REF_TAG) ||
+ bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE)
return;
__rq_for_each_bio(bio, rq) {
__blk_reftag_remap(bio, bi, &intervals, &ref, prep);
if (!intervals)
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index c82b2f6fe194..e314d22d9922 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -13,10 +13,12 @@ enum blk_integrity_flags {
BLK_INTEGRITY_NOGENERATE = 1 << 1,
BLK_INTEGRITY_DEVICE_CAPABLE = 1 << 2,
BLK_INTEGRITY_REF_TAG = 1 << 3,
BLK_INTEGRITY_STACKED = 1 << 4,
BLK_SPLIT_INTERVAL_CAPABLE = 1 << 5,
+ /* Device I/O specifies expected initial ref tag independent of LBA */
+ BLK_EXPECTED_REF_TAG_CAPABLE = 1 << 6,
};
const char *blk_integrity_profile_name(struct blk_integrity *bi);
bool queue_limits_stack_integrity(struct queue_limits *t,
struct queue_limits *b);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] block: assert blk_iou_cmd fits in the io_uring_cmd PDU
From: Caleb Sander Mateos @ 2026-06-27 5:52 UTC (permalink / raw)
To: dayou5941; +Cc: Jens Axboe, linux-block, liyouhong
In-Reply-To: <20260627032731.2878510-1-dayou5941@163.com>
On Fri, Jun 26, 2026 at 8:28 PM <dayou5941@163.com> wrote:
>
> From: liyouhong <liyouhong@kylinos.cn>
>
> blk_iou_cmd is stored in io_uring_cmd->pdu via io_uring_cmd_to_pdu() for
> block device io_uring commands (e.g. discard). The PDU is only 32 bytes
> inline storage; add a static_assert matching scsi_bsg.c so that future
> struct growth cannot silently overflow it.
>
> Signed-off-by: liyouhong <liyouhong@kylinos.cn>
> ---
> block/ioctl.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/block/ioctl.c b/block/ioctl.c
> index ab2c9ed79946..3c8fd365aa9f 100644
> --- a/block/ioctl.c
> +++ b/block/ioctl.c
> @@ -856,12 +856,17 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
> }
> #endif
>
> +/*
> + * Per-command block io_uring PDU stored in io_uring_cmd.pdu[32].
> + * Holds discard state between submission, completion and task work.
> + */
> struct blk_iou_cmd {
> u64 start;
> u64 len;
> int res;
> bool nowait;
> };
> +static_assert(sizeof(struct blk_iou_cmd) <= sizeof_field(struct io_uring_cmd, pdu));
Doesn't io_uring_cmd_to_pdu() already have this assertion?
static inline void io_uring_cmd_private_sz_check(size_t cmd_sz)
{
BUILD_BUG_ON(cmd_sz > sizeof_field(struct io_uring_cmd, pdu));
}
#define io_uring_cmd_to_pdu(cmd, pdu_type) ( \
io_uring_cmd_private_sz_check(sizeof(pdu_type)), \
((pdu_type *)&(cmd)->pdu) \
)
Best,
Caleb
^ permalink raw reply
* [PATCH v4 2/5] blk-integrity: take u64 in bio_integrity_intervals()
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>
To allow bio_integrity_intervals() to convert an absolute sector to an
absolute integrity interval, use u64 for its argument and return types.
Also use SECTOR_SHIFT instead of the magic constant 9.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
include/linux/blk-integrity.h | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index b1b530613c34..825d777c078b 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -64,23 +64,23 @@ queue_max_integrity_segments(const struct request_queue *q)
{
return q->limits.max_integrity_segments;
}
/**
- * bio_integrity_intervals - Return number of integrity intervals for a bio
+ * bio_integrity_intervals - Convert sectors to integrity intervals
* @bi: blk_integrity profile for device
- * @sectors: Size of the bio in 512-byte sectors
+ * @sectors: Number of 512-byte sectors
*
* Description: The block layer calculates everything in 512 byte
* sectors but integrity metadata is done in terms of the data integrity
* interval size of the storage device. Convert the block layer sectors
* to the appropriate number of integrity intervals.
*/
-static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi,
- unsigned int sectors)
+static inline u64 bio_integrity_intervals(const struct blk_integrity *bi,
+ u64 sectors)
{
- return sectors >> (bi->interval_exp - 9);
+ return sectors >> (bi->interval_exp - SECTOR_SHIFT);
}
static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
unsigned int sectors)
{
@@ -151,12 +151,12 @@ static inline unsigned short
queue_max_integrity_segments(const struct request_queue *q)
{
return 0;
}
-static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi,
- unsigned int sectors)
+static inline u64 bio_integrity_intervals(const struct blk_integrity *bi,
+ u64 sectors)
{
return 0;
}
static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
--
2.54.0
^ permalink raw reply related
* [PATCH v4 3/5] bio-integrity-fs: use integrity interval instead of sector as seed
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>
bip_iter.bi_sector is meant to be in units of integrity intervals rather
than 512-byte sectors. bio_integrity_verify() doesn't actually use it
currently (it uses the passed in struct bvec_iter's bi_sector instead).
But let's set it to the expected value for consistency.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
block/bio-integrity-fs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/bio-integrity-fs.c b/block/bio-integrity-fs.c
index 9c5fe5fa8f0d..770eacb2220f 100644
--- a/block/bio-integrity-fs.c
+++ b/block/bio-integrity-fs.c
@@ -65,11 +65,11 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
*
* This is for use in the submitter after the driver is done with the
* bio. Requires the submitter to remember the sector and the size.
*/
memset(&bip->bip_iter, 0, sizeof(bip->bip_iter));
- bip->bip_iter.bi_sector = sector;
+ bip->bip_iter.bi_sector = bio_integrity_intervals(bi, sector);
bip->bip_iter.bi_size = bio_integrity_bytes(bi, size >> SECTOR_SHIFT);
return blk_status_to_errno(bio_integrity_verify(bio, &data_iter));
}
static int __init fs_bio_integrity_init(void)
--
2.54.0
^ permalink raw reply related
* [PATCH v4 5/5] blk-integrity: avoid sector_t in bip_{get,set}_seed()
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos, Christoph Hellwig
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>
bip_set_seed() and bip_get_seed() take/return a sector_t value that's
actually an integrity interval number. This is confusing, so pass
struct bio instead to bip_set_seed() and convert the bio's device
address to integrity intervals.
Open-code the access to bip->bip_iter.bi_sector in the one caller of
bip_set_seed() that doesn't use the bio device address for the seed.
Open-code bip_get_seed() in its one caller.
Add a comment to struct bvec_iter's bi_sector field explaining its
alternate use for bip_iter.
Suggested-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
block/bio-integrity.c | 5 ++---
block/t10-pi.c | 2 +-
drivers/nvme/target/io-cmd-bdev.c | 3 +--
drivers/target/target_core_iblock.c | 3 +--
include/linux/bio-integrity.h | 11 -----------
include/linux/blk-integrity.h | 13 +++++++++++++
include/linux/bvec.h | 1 +
7 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index d20f9002c7c9..7e5fb9b44848 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -102,13 +102,12 @@ void bio_integrity_free_buf(struct bio_integrity_payload *bip)
void bio_integrity_setup_default(struct bio *bio)
{
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
struct bio_integrity_payload *bip = bio_integrity(bio);
- u64 seed = bio->bi_iter.bi_sector >> (bi->interval_exp - SECTOR_SHIFT);
- bip_set_seed(bip, seed);
+ bip_set_seed(bio);
if (bi->csum_type) {
bip->bip_flags |= BIP_CHECK_GUARD;
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
bip->bip_flags |= BIP_IP_CHECKSUM;
@@ -488,11 +487,11 @@ int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
it.count = integrity_bytes;
ret = bio_integrity_map_user(bio, &it);
if (!ret) {
bio_uio_meta_to_bip(bio, meta);
- bip_set_seed(bio_integrity(bio), meta->seed);
+ bio_integrity(bio)->bip_iter.bi_sector = meta->seed;
iov_iter_advance(&meta->iter, integrity_bytes);
meta->seed += bio_integrity_intervals(bi, bio_sectors(bio));
}
return ret;
}
diff --git a/block/t10-pi.c b/block/t10-pi.c
index 787950dec50a..71367fd082bd 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -510,11 +510,11 @@ static void blk_reftag_remap_prepare(struct blk_integrity *bi,
static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi,
unsigned *intervals, u64 *ref, bool prep)
{
struct bio_integrity_payload *bip = bio_integrity(bio);
struct bvec_iter iter = bip->bip_iter;
- u64 virt = bip_get_seed(bip);
+ u64 virt = bip->bip_iter.bi_sector;
union pi_tuple *ptuple;
union pi_tuple tuple;
if (prep && bip->bip_flags & BIP_MAPPED_INTEGRITY) {
*ref += bio->bi_iter.bi_size >> bi->interval_exp;
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index f2d9e8901df4..65fce51b024a 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -218,12 +218,11 @@ static int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
pr_err("Unable to allocate bio_integrity_payload\n");
return PTR_ERR(bip);
}
/* virtual start sector must be in integrity interval units */
- bip_set_seed(bip, bio->bi_iter.bi_sector >>
- (bi->interval_exp - SECTOR_SHIFT));
+ bip_set_seed(bio);
resid = bio_integrity_bytes(bi, bio_sectors(bio));
while (resid > 0 && sg_miter_next(miter)) {
len = min_t(size_t, miter->length, resid);
rc = bio_integrity_add_page(bio, miter->page, len,
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 1087d1d17c36..1aeb5be529a8 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -706,12 +706,11 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio,
pr_err("Unable to allocate bio_integrity_payload\n");
return PTR_ERR(bip);
}
/* virtual start sector must be in integrity interval units */
- bip_set_seed(bip, bio->bi_iter.bi_sector >>
- (bi->interval_exp - SECTOR_SHIFT));
+ bip_set_seed(bio);
pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size,
(unsigned long long)bip->bip_iter.bi_sector);
resid = bio_integrity_bytes(bi, bio_sectors(bio));
diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
index c3dda32fd803..992cb1622c2c 100644
--- a/include/linux/bio-integrity.h
+++ b/include/linux/bio-integrity.h
@@ -56,21 +56,10 @@ static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
return bip->bip_flags & flag;
return false;
}
-static inline sector_t bip_get_seed(struct bio_integrity_payload *bip)
-{
- return bip->bip_iter.bi_sector;
-}
-
-static inline void bip_set_seed(struct bio_integrity_payload *bip,
- sector_t seed)
-{
- bip->bip_iter.bi_sector = seed;
-}
-
void bio_integrity_init(struct bio *bio, struct bio_integrity_payload *bip,
struct bio_vec *bvecs, unsigned int nr_vecs);
struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp,
unsigned int nr);
int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len,
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index 825d777c078b..c82b2f6fe194 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -85,10 +85,23 @@ static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
unsigned int sectors)
{
return bio_integrity_intervals(bi, sectors) * bi->metadata_size;
}
+/**
+ * bip_set_seed - Set bip reference tag seed from bio device address
+ * @bio: struct bio whose integrity payload's ref tag seed to initialize
+ */
+static inline void bip_set_seed(struct bio *bio)
+{
+ struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+ struct bio_integrity_payload *bip = bio_integrity(bio);
+
+ bip->bip_iter.bi_sector =
+ bio_integrity_intervals(bi, bio->bi_iter.bi_sector);
+}
+
static inline bool blk_integrity_rq(const struct request *rq)
{
return rq->cmd_flags & REQ_INTEGRITY;
}
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index 92837e2743f1..22bded380bbf 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -91,10 +91,11 @@ static inline struct folio *bvec_folio(const struct bio_vec *bv)
struct bvec_iter {
/*
* Current device address in 512 byte sectors. Only updated by the bio
* iter wrappers and not the bvec iterator helpers themselves.
+ * For bip_iter, this is overloaded to represent the integrity interval.
*/
sector_t bi_sector;
/*
* Remaining size in bytes.
--
2.54.0
^ permalink raw reply related
* [PATCH v4 4/5] t10-pi: use bio_integrity_intervals() helper
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>
Use bio_integrity_intervals() to convert blk_rq_pos(rq) to integrity
intervals to reduce code duplication.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
block/t10-pi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/t10-pi.c b/block/t10-pi.c
index e58d5eb6cefb..787950dec50a 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -541,11 +541,11 @@ static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi,
static void blk_integrity_remap(struct request *rq, unsigned int nr_bytes,
bool prep)
{
struct blk_integrity *bi = &rq->q->limits.integrity;
- u64 ref = blk_rq_pos(rq) >> (bi->interval_exp - SECTOR_SHIFT);
+ u64 ref = bio_integrity_intervals(bi, blk_rq_pos(rq));
unsigned intervals = nr_bytes >> bi->interval_exp;
struct bio *bio;
if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
return;
--
2.54.0
^ permalink raw reply related
* [PATCH v4 1/5] block: use integrity interval instead of sector as seed
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>
bio_integrity_setup_default() and blk_integrity_iterate() set the
integrity seed (initial reference tag) to the absolute address in the
block device in units of 512-byte sectors. However, Type 1 and Type 2
ref tags are actually the least significant bits of the integrity
interval number. On devices with integrity interval size > 512 bytes,
the ref tag seed thus isn't the correct initial ref tag. The ref tag
seed is correctly incremented/decremented in units of integrity
intervals in bio_integrity_map_iter(), bio_integrity_advance(), and
blk_integrity_interval().
For REQ_OP_{WRITE,READ}, blk_integrity_{prepare,complete}() covers up
this ref tag seed discrepancy by adding/subtracting the difference
between the initial integrity interval and ref tag values to/from each
ref tag in the protection information. However, REQ_OP_ZONE_APPEND can
also carry PI but doesn't go through blk_integrity_prepare() because the
final data location on the zoned block device isn't known until the
operation completes. As a result, the REQ_OP_ZONE_APPEND PI ref tags
start from the ref tag seed, which isn't in integrity interval units.
Subsequent reads of the appended blocks will fail to remap the ref tags
from the expected integrity interval numbers to sector numbers.
Additionally, NVMe and many SCSI transports support offloading ref tag
remapping to the device by specifying the expected initial ref tag in
the command. The kernel doesn't currently take advantage of this, always
remapping ref tags in software for reads and writes and setting the
expected initial ref tag to the integrity interval. Setting the ref tag
seed in units of integrity intervals would be a prerequisite to allowing
the kernel to skip the software remapping and pass the ref tag seed as
the expected initial ref tag in the command.
So compute the ref tag seed in units of integrity intervals instead of
sectors to avoid relying on ref tag remapping for the conversion.
Fixes: 0512a75b98f8 ("block: Introduce REQ_OP_ZONE_APPEND")
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
block/bio-integrity.c | 3 ++-
block/t10-pi.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index b23e2434d80c..d20f9002c7c9 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -102,12 +102,13 @@ void bio_integrity_free_buf(struct bio_integrity_payload *bip)
void bio_integrity_setup_default(struct bio *bio)
{
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
struct bio_integrity_payload *bip = bio_integrity(bio);
+ u64 seed = bio->bi_iter.bi_sector >> (bi->interval_exp - SECTOR_SHIFT);
- bip_set_seed(bip, bio->bi_iter.bi_sector);
+ bip_set_seed(bip, seed);
if (bi->csum_type) {
bip->bip_flags |= BIP_CHECK_GUARD;
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
bip->bip_flags |= BIP_IP_CHECKSUM;
diff --git a/block/t10-pi.c b/block/t10-pi.c
index a19b4e102a83..e58d5eb6cefb 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -308,18 +308,19 @@ static blk_status_t blk_integrity_iterate(struct bio *bio,
struct bvec_iter *data_iter,
bool verify)
{
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
struct bio_integrity_payload *bip = bio_integrity(bio);
+ u64 seed = data_iter->bi_sector >> (bi->interval_exp - SECTOR_SHIFT);
struct blk_integrity_iter iter = {
.bio = bio,
.bip = bip,
.bi = bi,
.data_iter = *data_iter,
.prot_iter = bip->bip_iter,
.interval_remaining = 1 << bi->interval_exp,
- .seed = data_iter->bi_sector,
+ .seed = seed,
.csum = 0,
};
blk_status_t ret = BLK_STS_OK;
while (iter.data_iter.bi_size && ret == BLK_STS_OK) {
--
2.54.0
^ permalink raw reply related
* [PATCH v4 0/5] block: use integrity interval instead of sector as seed
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
The block integrity layer currently sets the integrity seed (initial
reference tag) in units of 512-byte sectors. However, Type 1 and Type 2
ref tags are actually in units of integrity intervals. On devices with
integrity interval size > 512 bytes, ref tags are seeded incorrectly.
Ref tag "remapping" in blk_integrity_{prepare,complete}() covers up this
ref tag seed discrepancy by offsetting all ref tags in each bio to
convert to/from the absolute integrity interval numbers. But
REQ_OP_ZONE_APPEND operations don't have their ref tags remapped, so the
ref tags using units of sectors will be stored to the device. As future
optimizations, the ref tag remapping could be avoided entirely on NVMe
and some SCSI devices by passing the ref tag seed instead of the
absolute integrity interval as the expected initial ref tag.
So avoid relying on remapping to convert between the ref tag seed in
units of sectors and stored ref tags in units of integrity intervals.
Initialize the ref tag seed as the integrity interval, not sector.
The subsequent commits clean up the integrity ref tag seed code a bit.
v4:
- Drop patch already applied
v3: https://lore.kernel.org/linux-block/20260417015732.2692434-1-csander@purestorage.com/T/
- Drop bi and bip arguments to bip_set_seed() (Christoph)
v2:
- Reorder fixes before refactoring commits
- Use u64, SECTOR_SHIFT (Christoph)
- Don't take sector_t in bip_set_seed() (Christoph)
Caleb Sander Mateos (5):
block: use integrity interval instead of sector as seed
blk-integrity: take u64 in bio_integrity_intervals()
bio-integrity-fs: use integrity interval instead of sector as seed
t10-pi: use bio_integrity_intervals() helper
blk-integrity: avoid sector_t in bip_{get,set}_seed()
block/bio-integrity-fs.c | 2 +-
block/bio-integrity.c | 4 ++--
block/t10-pi.c | 7 ++++---
drivers/nvme/target/io-cmd-bdev.c | 3 +--
drivers/target/target_core_iblock.c | 3 +--
include/linux/bio-integrity.h | 11 -----------
include/linux/blk-integrity.h | 27 ++++++++++++++++++++-------
include/linux/bvec.h | 1 +
8 files changed, 30 insertions(+), 28 deletions(-)
--
2.54.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox