Files
linux-stable-mirror/drivers/block/rnull/rnull.rs
Andreas Hindborg 34585dc649 rnull: add soft-irq completion support
rnull currently only supports direct completion. Add option for completing
requests across CPU nodes via soft IRQ or IPI.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Link: https://lore.kernel.org/r/20250902-rnull-up-v6-16-v7-17-b5212cc89b98@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2025-09-02 05:23:56 -06:00

105 lines
2.8 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
//! This is a Rust implementation of the C null block driver.
mod configfs;
use configfs::IRQMode;
use kernel::{
block::{
self,
mq::{
self,
gen_disk::{self, GenDisk},
Operations, TagSet,
},
},
error::Result,
pr_info,
prelude::*,
sync::Arc,
types::ARef,
};
use pin_init::PinInit;
module! {
type: NullBlkModule,
name: "rnull_mod",
authors: ["Andreas Hindborg"],
description: "Rust implementation of the C null block driver",
license: "GPL v2",
}
#[pin_data]
struct NullBlkModule {
#[pin]
configfs_subsystem: kernel::configfs::Subsystem<configfs::Config>,
}
impl kernel::InPlaceModule for NullBlkModule {
fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
pr_info!("Rust null_blk loaded\n");
try_pin_init!(Self {
configfs_subsystem <- configfs::subsystem(),
})
}
}
struct NullBlkDevice;
impl NullBlkDevice {
fn new(
name: &CStr,
block_size: u32,
rotational: bool,
capacity_mib: u64,
irq_mode: IRQMode,
) -> Result<GenDisk<Self>> {
let tagset = Arc::pin_init(TagSet::new(1, 256, 1), GFP_KERNEL)?;
let queue_data = Box::new(QueueData { irq_mode }, GFP_KERNEL)?;
gen_disk::GenDiskBuilder::new()
.capacity_sectors(capacity_mib << (20 - block::SECTOR_SHIFT))
.logical_block_size(block_size)?
.physical_block_size(block_size)?
.rotational(rotational)
.build(fmt!("{}", name.to_str()?), tagset, queue_data)
}
}
struct QueueData {
irq_mode: IRQMode,
}
#[vtable]
impl Operations for NullBlkDevice {
type QueueData = KBox<QueueData>;
#[inline(always)]
fn queue_rq(queue_data: &QueueData, rq: ARef<mq::Request<Self>>, _is_last: bool) -> Result {
match queue_data.irq_mode {
IRQMode::None => mq::Request::end_ok(rq)
.map_err(|_e| kernel::error::code::EIO)
// We take no refcounts on the request, so we expect to be able to
// end the request. The request reference must be unique at this
// point, and so `end_ok` cannot fail.
.expect("Fatal error - expected to be able to end request"),
IRQMode::Soft => mq::Request::complete(rq),
}
Ok(())
}
fn commit_rqs(_queue_data: &QueueData) {}
fn complete(rq: ARef<mq::Request<Self>>) {
mq::Request::end_ok(rq)
.map_err(|_e| kernel::error::code::EIO)
// We take no refcounts on the request, so we expect to be able to
// end the request. The request reference must be unique at this
// point, and so `end_ok` cannot fail.
.expect("Fatal error - expected to be able to end request");
}
}