1 // SPDX-License-Identifier: GPL-2.0 2 3 //! This is a Rust implementation of the C null block driver. 4 5 mod configfs; 6 7 use configfs::IRQMode; 8 use kernel::{ 9 block::{ 10 self, 11 mq::{ 12 self, 13 gen_disk::{self, GenDisk}, 14 Operations, TagSet, 15 }, 16 }, 17 prelude::*, 18 sync::{aref::ARef, Arc}, 19 }; 20 21 module! { 22 type: NullBlkModule, 23 name: "rnull_mod", 24 authors: ["Andreas Hindborg"], 25 description: "Rust implementation of the C null block driver", 26 license: "GPL v2", 27 } 28 29 #[pin_data] 30 struct NullBlkModule { 31 #[pin] 32 configfs_subsystem: kernel::configfs::Subsystem<configfs::Config>, 33 } 34 35 impl kernel::InPlaceModule for NullBlkModule { 36 fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> { 37 pr_info!("Rust null_blk loaded\n"); 38 39 try_pin_init!(Self { 40 configfs_subsystem <- configfs::subsystem(), 41 }) 42 } 43 } 44 45 struct NullBlkDevice; 46 47 impl NullBlkDevice { 48 fn new( 49 name: &CStr, 50 block_size: u32, 51 rotational: bool, 52 capacity_mib: u64, 53 irq_mode: IRQMode, 54 ) -> Result<GenDisk<Self>> { 55 let tagset = Arc::pin_init(TagSet::new(1, 256, 1), GFP_KERNEL)?; 56 57 let queue_data = Box::new(QueueData { irq_mode }, GFP_KERNEL)?; 58 59 gen_disk::GenDiskBuilder::new() 60 .capacity_sectors(capacity_mib << (20 - block::SECTOR_SHIFT)) 61 .logical_block_size(block_size)? 62 .physical_block_size(block_size)? 63 .rotational(rotational) 64 .build(fmt!("{}", name.to_str()?), tagset, queue_data) 65 } 66 } 67 68 struct QueueData { 69 irq_mode: IRQMode, 70 } 71 72 #[vtable] 73 impl Operations for NullBlkDevice { 74 type QueueData = KBox<QueueData>; 75 76 #[inline(always)] 77 fn queue_rq(queue_data: &QueueData, rq: ARef<mq::Request<Self>>, _is_last: bool) -> Result { 78 match queue_data.irq_mode { 79 IRQMode::None => mq::Request::end_ok(rq) 80 .map_err(|_e| kernel::error::code::EIO) 81 // We take no refcounts on the request, so we expect to be able to 82 // end the request. The request reference must be unique at this 83 // point, and so `end_ok` cannot fail. 84 .expect("Fatal error - expected to be able to end request"), 85 IRQMode::Soft => mq::Request::complete(rq), 86 } 87 Ok(()) 88 } 89 90 fn commit_rqs(_queue_data: &QueueData) {} 91 92 fn complete(rq: ARef<mq::Request<Self>>) { 93 mq::Request::end_ok(rq) 94 .map_err(|_e| kernel::error::code::EIO) 95 // We take no refcounts on the request, so we expect to be able to 96 // end the request. The request reference must be unique at this 97 // point, and so `end_ok` cannot fail. 98 .expect("Fatal error - expected to be able to end request"); 99 } 100 } 101