xref: /linux/drivers/block/rnull.rs (revision 442bc81bd344dc52c37d8f80b854cc6da062b2d0)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! This is a Rust implementation of the C null block driver.
4 //!
5 //! Supported features:
6 //!
7 //! - blk-mq interface
8 //! - direct completion
9 //! - block size 4k
10 //!
11 //! The driver is not configurable.
12 
13 use kernel::{
14     alloc::flags,
15     block::mq::{
16         self,
17         gen_disk::{self, GenDisk},
18         Operations, TagSet,
19     },
20     error::Result,
21     new_mutex, pr_info,
22     prelude::*,
23     sync::{Arc, Mutex},
24     types::ARef,
25 };
26 
27 module! {
28     type: NullBlkModule,
29     name: "rnull_mod",
30     author: "Andreas Hindborg",
31     description: "Rust implementation of the C null block driver",
32     license: "GPL v2",
33 }
34 
35 #[pin_data]
36 struct NullBlkModule {
37     #[pin]
38     _disk: Mutex<GenDisk<NullBlkDevice>>,
39 }
40 
41 impl kernel::InPlaceModule for NullBlkModule {
init(_module: &'static ThisModule) -> impl PinInit<Self, Error>42     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
43         pr_info!("Rust null_blk loaded\n");
44 
45         // Use a immediately-called closure as a stable `try` block
46         let disk = /* try */ (|| {
47             let tagset = Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
48 
49             gen_disk::GenDiskBuilder::new()
50                 .capacity_sectors(4096 << 11)
51                 .logical_block_size(4096)?
52                 .physical_block_size(4096)?
53                 .rotational(false)
54                 .build(format_args!("rnullb{}", 0), tagset)
55         })();
56 
57         try_pin_init!(Self {
58             _disk <- new_mutex!(disk?, "nullb:disk"),
59         })
60     }
61 }
62 
63 struct NullBlkDevice;
64 
65 #[vtable]
66 impl Operations for NullBlkDevice {
67     #[inline(always)]
queue_rq(rq: ARef<mq::Request<Self>>, _is_last: bool) -> Result68     fn queue_rq(rq: ARef<mq::Request<Self>>, _is_last: bool) -> Result {
69         mq::Request::end_ok(rq)
70             .map_err(|_e| kernel::error::code::EIO)
71             // We take no refcounts on the request, so we expect to be able to
72             // end the request. The request reference must be unique at this
73             // point, and so `end_ok` cannot fail.
74             .expect("Fatal error - expected to be able to end request");
75 
76         Ok(())
77     }
78 
commit_rqs()79     fn commit_rqs() {}
80 }
81