| // 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"); | |
| } | |
| } |