Add support for sharing tags between multiple rnull devices. When enabled via the `shared_tags` configfs attribute, all devices in the group share a single tag set, reducing memory usage. This feature requires creating a shared `TagSet` that can be referenced by multiple devices. Signed-off-by: Andreas Hindborg --- drivers/block/rnull/configfs.rs | 7 ++++++- drivers/block/rnull/rnull.rs | 25 +++++++++++++++++++++---- rust/kernel/block/mq/tag_set.rs | 6 ++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs index 640e3de230c0a..d1a70fe030cb2 100644 --- a/drivers/block/rnull/configfs.rs +++ b/drivers/block/rnull/configfs.rs @@ -70,7 +70,7 @@ impl AttributeOperations<0> for Config { let mut writer = kernel::str::Formatter::new(page); writer.write_str( "blocksize,size,rotational,irqmode,completion_nsec,memory_backed\ - submit_queues,use_per_node_hctx,discard,blocking\n", + submit_queues,use_per_node_hctx,discard,blocking,shared_tags\n", )?; Ok(writer.bytes_written()) } @@ -107,6 +107,7 @@ fn make_group( cache_size_mib: 15, mbps: 16, blocking: 17, + shared_tags: 18, ], }; @@ -140,6 +141,7 @@ fn make_group( cache_size_mib: 0, mbps: 0, blocking: false, + shared_tags: false, }), }), core::iter::empty(), @@ -206,6 +208,7 @@ struct DeviceConfigInner { disk_storage: Arc, mbps: u32, blocking: bool, + shared_tags: bool, } #[vtable] @@ -247,6 +250,7 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result { storage: guard.disk_storage.clone(), bandwidth_limit: u64::from(guard.mbps) * 2u64.pow(20), blocking: guard.blocking, + shared_tags: guard.shared_tags, })?); guard.powered = true; } else if guard.powered && !power_op { @@ -467,3 +471,4 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result { configfs_simple_field!(DeviceConfig, 16, mbps, u32); configfs_simple_bool_field!(DeviceConfig, 17, blocking); +configfs_simple_bool_field!(DeviceConfig, 18, shared_tags); diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs index cfc00c104d9ca..84e75a7042214 100644 --- a/drivers/block/rnull/rnull.rs +++ b/drivers/block/rnull/rnull.rs @@ -145,6 +145,10 @@ default: 0, description: "Register as a blocking blk-mq driver device", }, + shared_tags: u8 { + default: 0, + description: "Share tag set between devices for blk-mq", + }, }, } @@ -192,6 +196,7 @@ fn init(_module: &'static ThisModule) -> impl PinInit { storage: Arc::pin_init(DiskStorage::new(0, block_size as usize), GFP_KERNEL)?, bandwidth_limit: u64::from(*module_parameters::mbps.value()) * 2u64.pow(20), blocking: *module_parameters::blocking.value() != 0, + shared_tags: *module_parameters::shared_tags.value() != 0, })?; disks.push(disk, GFP_KERNEL)?; } @@ -224,8 +229,11 @@ struct NullBlkOptions<'a> { storage: Arc, bandwidth_limit: u64, blocking: bool, + shared_tags: bool, } +static SHARED_TAG_SET: SetOnce>> = SetOnce::new(); + #[pin_data] struct NullBlkDevice { storage: Arc, @@ -267,6 +275,7 @@ fn new(options: NullBlkOptions<'_>) -> Result>> { storage, bandwidth_limit, blocking, + shared_tags, } = options; let mut flags = mq::tag_set::Flags::default(); @@ -286,10 +295,18 @@ fn new(options: NullBlkOptions<'_>) -> Result>> { return Err(code::EINVAL); } - let tagset = Arc::pin_init( - TagSet::new(submit_queues, (), 256, 1, home_node, flags), - GFP_KERNEL, - )?; + let tagset_ctor = || -> Result> { + Arc::pin_init( + TagSet::new(submit_queues, (), 256, 1, home_node, flags), + GFP_KERNEL, + ) + }; + + let tagset = if shared_tags { + SHARED_TAG_SET.as_ref_or_populate_with(tagset_ctor)?.clone() + } else { + tagset_ctor()? + }; let queue_data = Arc::try_pin_init( try_pin_init!(Self { diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index f18b51e5217fe..600c9c6249123 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -106,3 +106,9 @@ fn drop(self: Pin<&mut Self>) { unsafe { T::TagSetData::from_foreign(tagset_data) }; } } + +// SAFETY: It is safe to transfer ownership of `TagSet` across thread boundaries. +unsafe impl Sync for TagSet {} + +// SAFETY: It is safe to share references to `TagSet` across thread boundaries. +unsafe impl Send for TagSet {} -- 2.51.2