Allow user space to control the number of submission queues when creating null block devices. Signed-off-by: Andreas Hindborg --- drivers/block/rnull/configfs.rs | 56 +++++++++++++++++++++++++++++++++-------- drivers/block/rnull/rnull.rs | 56 +++++++++++++++++++++++++++-------------- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs index b5dc30c5d3e20..fd3cbf7aa012e 100644 --- a/drivers/block/rnull/configfs.rs +++ b/drivers/block/rnull/configfs.rs @@ -59,7 +59,10 @@ impl AttributeOperations<0> for Config { fn show(_this: &Config, page: &mut [u8; PAGE_SIZE]) -> Result { let mut writer = kernel::str::Formatter::new(page); - writer.write_str("blocksize,size,rotational,irqmode,completion_nsec,memory_backed\n")?; + writer.write_str( + "blocksize,size,rotational,irqmode,completion_nsec,memory_backed\ + submit_queues\n", + )?; Ok(writer.bytes_written()) } } @@ -84,6 +87,7 @@ fn make_group( irqmode: 4, completion_nsec: 5, memory_backed: 6, + submit_queues: 7, ], }; @@ -102,6 +106,7 @@ fn make_group( completion_time: time::Delta::ZERO, name: name.try_into()?, memory_backed: false, + submit_queues: 1, }), }), core::iter::empty(), @@ -157,6 +162,7 @@ struct DeviceConfigInner { completion_time: time::Delta, disk: Option>, memory_backed: bool, + submit_queues: u32, } #[vtable] @@ -180,15 +186,16 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result { let mut guard = this.data.lock(); if !guard.powered && power_op { - guard.disk = Some(NullBlkDevice::new( - &guard.name, - guard.block_size, - guard.rotational, - guard.capacity_mib, - guard.irq_mode, - guard.completion_time, - guard.memory_backed, - )?); + guard.disk = Some(NullBlkDevice::new(crate::NullBlkOptions { + name: &guard.name, + block_size: guard.block_size, + rotational: guard.rotational, + capacity_mib: guard.capacity_mib, + irq_mode: guard.irq_mode, + completion_time: guard.completion_time, + memory_backed: guard.memory_backed, + submit_queues: guard.submit_queues, + })?); guard.powered = true; } else if guard.powered && !power_op { drop(guard.disk.take()); @@ -244,3 +251,32 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result { Ok(()) } } + +#[vtable] +impl configfs::AttributeOperations<7> for DeviceConfig { + type Data = DeviceConfig; + + fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result { + let mut writer = kernel::str::Formatter::new(page); + writer.write_fmt(fmt!("{}\n", this.data.lock().submit_queues))?; + Ok(writer.bytes_written()) + } + + fn store(this: &DeviceConfig, page: &[u8]) -> Result { + if this.data.lock().powered { + return Err(EBUSY); + } + + let text = core::str::from_utf8(page)?.trim(); + let value = text + .parse::() + .map_err(|_| kernel::error::code::EINVAL)?; + + if value == 0 || value > kernel::num_possible_cpus() { + return Err(kernel::error::code::EINVAL); + } + + this.data.lock().submit_queues = value; + Ok(()) + } +} diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs index a1156a368c467..55ee5165b90b3 100644 --- a/drivers/block/rnull/rnull.rs +++ b/drivers/block/rnull/rnull.rs @@ -80,6 +80,10 @@ default: 0, description: "Create a memory-backed block device. 0-false, 1-true. Default: 0", }, + submit_queues: u32 { + default: 1, + description: "Number of submission queues", + }, }, } @@ -102,15 +106,16 @@ fn init(_module: &'static ThisModule) -> impl PinInit { for i in 0..(*module_parameters::nr_devices.value()) { let name = CString::try_from_fmt(fmt!("rnullb{}", i))?; - let disk = NullBlkDevice::new( - &name, - *module_parameters::bs.value(), - *module_parameters::rotational.value() != 0, - *module_parameters::gb.value() * 1024, - (*module_parameters::irqmode.value()).try_into()?, - Delta::from_nanos(completion_time), - *module_parameters::memory_backed.value() != 0, - )?; + let disk = NullBlkDevice::new(NullBlkOptions { + name: &name, + block_size: *module_parameters::bs.value(), + rotational: *module_parameters::rotational.value() != 0, + capacity_mib: *module_parameters::gb.value() * 1024, + irq_mode: (*module_parameters::irqmode.value()).try_into()?, + completion_time: Delta::from_nanos(completion_time), + memory_backed: *module_parameters::memory_backed.value() != 0, + submit_queues: *module_parameters::submit_queues.value(), + })?; disks.push(disk, GFP_KERNEL)?; } @@ -124,25 +129,38 @@ fn init(_module: &'static ThisModule) -> impl PinInit { } } +struct NullBlkOptions<'a> { + name: &'a CStr, + block_size: u32, + rotational: bool, + capacity_mib: u64, + irq_mode: IRQMode, + completion_time: Delta, + memory_backed: bool, + submit_queues: u32, +} struct NullBlkDevice; impl NullBlkDevice { - fn new( - name: &CStr, - block_size: u32, - rotational: bool, - capacity_mib: u64, - irq_mode: IRQMode, - completion_time: Delta, - memory_backed: bool, - ) -> Result> { + fn new(options: NullBlkOptions<'_>) -> Result> { + let NullBlkOptions { + name, + block_size, + rotational, + capacity_mib, + irq_mode, + completion_time, + memory_backed, + submit_queues, + } = options; + let flags = if memory_backed { mq::tag_set::Flag::Blocking.into() } else { mq::tag_set::Flags::default() }; - let tagset = Arc::pin_init(TagSet::new(1, 256, 1, flags), GFP_KERNEL)?; + let tagset = Arc::pin_init(TagSet::new(submit_queues, 256, 1, flags), GFP_KERNEL)?; let queue_data = Box::pin_init( pin_init!(QueueData { -- 2.51.2