// SPDX-License-Identifier: GPL-2.0 //! This is a Rust implementation of the C null block driver. //! //! Supported features: //! //! - blk-mq interface //! - direct completion //! - block size 4k //! //! The driver is not configurable. use kernel::{ alloc::flags, block::mq::{ self, gen_disk::{self, GenDisk}, Operations, TagSet, }, error::Result, new_mutex, pr_info, prelude::*, sync::{Arc, Mutex}, types::ARef, }; module! { type: NullBlkModule, name: "rnull_mod", author: "Andreas Hindborg", license: "GPL v2", } struct NullBlkModule { _disk: Pin<Box<Mutex<GenDisk<NullBlkDevice>>>>, } impl kernel::Module for NullBlkModule { fn init(_module: &'static ThisModule) -> Result<Self> { pr_info!("Rust null_blk loaded\n"); let tagset = Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?; let disk = gen_disk::GenDiskBuilder::new() .capacity_sectors(4096 << 11) .logical_block_size(4096)? .physical_block_size(4096)? .rotational(false) .build(format_args!("rnullb{}", 0), tagset)?; let disk = Box::pin_init(new_mutex!(disk, "nullb:disk"), flags::GFP_KERNEL)?; Ok(Self { _disk: disk }) } } struct NullBlkDevice; #[vtable] impl Operations for NullBlkDevice { #[inline(always)] fn queue_rq(rq: ARef<mq::Request<Self>>, _is_last: bool) -> Result { 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"); Ok(()) } fn commit_rqs() {} }