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