Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/block/mq.rs
29266 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
//! This module provides types for implementing block drivers that interface the
4
//! blk-mq subsystem.
5
//!
6
//! To implement a block device driver, a Rust module must do the following:
7
//!
8
//! - Implement [`Operations`] for a type `T`.
9
//! - Create a [`TagSet<T>`].
10
//! - Create a [`GenDisk<T>`], via the [`GenDiskBuilder`].
11
//! - Add the disk to the system by calling [`GenDiskBuilder::build`] passing in
12
//! the `TagSet` reference.
13
//!
14
//! The types available in this module that have direct C counterparts are:
15
//!
16
//! - The [`TagSet`] type that abstracts the C type `struct tag_set`.
17
//! - The [`GenDisk`] type that abstracts the C type `struct gendisk`.
18
//! - The [`Request`] type that abstracts the C type `struct request`.
19
//!
20
//! The kernel will interface with the block device driver by calling the method
21
//! implementations of the `Operations` trait.
22
//!
23
//! IO requests are passed to the driver as [`kernel::types::ARef<Request>`]
24
//! instances. The `Request` type is a wrapper around the C `struct request`.
25
//! The driver must mark end of processing by calling one of the
26
//! `Request::end`, methods. Failure to do so can lead to deadlock or timeout
27
//! errors. Please note that the C function `blk_mq_start_request` is implicitly
28
//! called when the request is queued with the driver.
29
//!
30
//! The `TagSet` is responsible for creating and maintaining a mapping between
31
//! `Request`s and integer ids as well as carrying a pointer to the vtable
32
//! generated by `Operations`. This mapping is useful for associating
33
//! completions from hardware with the correct `Request` instance. The `TagSet`
34
//! determines the maximum queue depth by setting the number of `Request`
35
//! instances available to the driver, and it determines the number of queues to
36
//! instantiate for the driver. If possible, a driver should allocate one queue
37
//! per core, to keep queue data local to a core.
38
//!
39
//! One `TagSet` instance can be shared between multiple `GenDisk` instances.
40
//! This can be useful when implementing drivers where one piece of hardware
41
//! with one set of IO resources are represented to the user as multiple disks.
42
//!
43
//! One significant difference between block device drivers implemented with
44
//! these Rust abstractions and drivers implemented in C, is that the Rust
45
//! drivers have to own a reference count on the `Request` type when the IO is
46
//! in flight. This is to ensure that the C `struct request` instances backing
47
//! the Rust `Request` instances are live while the Rust driver holds a
48
//! reference to the `Request`. In addition, the conversion of an integer tag to
49
//! a `Request` via the `TagSet` would not be sound without this bookkeeping.
50
//!
51
//! [`GenDisk`]: gen_disk::GenDisk
52
//! [`GenDisk<T>`]: gen_disk::GenDisk
53
//! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder
54
//! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build
55
//!
56
//! # Examples
57
//!
58
//! ```rust
59
//! use kernel::{
60
//! alloc::flags,
61
//! block::mq::*,
62
//! new_mutex,
63
//! prelude::*,
64
//! sync::{Arc, Mutex},
65
//! types::{ARef, ForeignOwnable},
66
//! };
67
//!
68
//! struct MyBlkDevice;
69
//!
70
//! #[vtable]
71
//! impl Operations for MyBlkDevice {
72
//! type QueueData = ();
73
//!
74
//! fn queue_rq(_queue_data: (), rq: ARef<Request<Self>>, _is_last: bool) -> Result {
75
//! Request::end_ok(rq);
76
//! Ok(())
77
//! }
78
//!
79
//! fn commit_rqs(_queue_data: ()) {}
80
//!
81
//! fn complete(rq: ARef<Request<Self>>) {
82
//! Request::end_ok(rq)
83
//! .map_err(|_e| kernel::error::code::EIO)
84
//! .expect("Fatal error - expected to be able to end request");
85
//! }
86
//! }
87
//!
88
//! let tagset: Arc<TagSet<MyBlkDevice>> =
89
//! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
90
//! let mut disk = gen_disk::GenDiskBuilder::new()
91
//! .capacity_sectors(4096)
92
//! .build(fmt!("myblk"), tagset, ())?;
93
//!
94
//! # Ok::<(), kernel::error::Error>(())
95
//! ```
96
97
pub mod gen_disk;
98
mod operations;
99
mod request;
100
mod tag_set;
101
102
pub use operations::Operations;
103
pub use request::Request;
104
pub use tag_set::TagSet;
105
106