Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
 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
90pub mod gen_disk;
91mod operations;
92mod raw_writer;
93mod request;
94mod tag_set;
95
96pub use operations::Operations;
97pub use request::Request;
98pub use tag_set::TagSet;