// 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, }, }, prelude::*, sync::{aref::ARef, Arc},};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"); }}
// 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,
},
},
prelude::*,
sync::{aref::ARef, Arc},
};
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");
}
}