Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3//! This is a Rust implementation of the C null block driver.
4
5mod configfs;
6
7use configfs::IRQMode;
8use 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};
22use pin_init::PinInit;
23
24module! {
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]
33struct NullBlkModule {
34 #[pin]
35 configfs_subsystem: kernel::configfs::Subsystem<configfs::Config>,
36}
37
38impl 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
48struct NullBlkDevice;
49
50impl 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
71struct QueueData {
72 irq_mode: IRQMode,
73}
74
75#[vtable]
76impl 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}