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)
.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)
.expect("Fatal error - expected to be able to end request");
}
}