// 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, } impl kernel::InPlaceModule for NullBlkModule { fn init(_module: &'static ThisModule) -> impl PinInit { 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> { 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; #[inline(always)] fn queue_rq(queue_data: &QueueData, rq: ARef>, _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::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"); } }