xref: /linux/rust/kernel/block/mq.rs (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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 //! # Example
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 //!
73 //!     fn queue_rq(rq: ARef<Request<Self>>, _is_last: bool) -> Result {
74 //!         Request::end_ok(rq);
75 //!         Ok(())
76 //!     }
77 //!
78 //!     fn commit_rqs() {}
79 //! }
80 //!
81 //! let tagset: Arc<TagSet<MyBlkDevice>> =
82 //!     Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
83 //! let mut disk = gen_disk::GenDiskBuilder::new()
84 //!     .capacity_sectors(4096)
85 //!     .build(format_args!("myblk"), tagset)?;
86 //!
87 //! # Ok::<(), kernel::error::Error>(())
88 //! ```
89 
90 pub mod gen_disk;
91 mod operations;
92 mod raw_writer;
93 mod request;
94 mod tag_set;
95 
96 pub use operations::Operations;
97 pub use request::Request;
98 pub use tag_set::TagSet;
99