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