xref: /linux/drivers/block/rnull/rnull.rs (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
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