File Index
Files and directories
Sign in
FILE

mq.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/block/mq.rs RUST
  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::sync::aref::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::{aref::ARef, Arc, Mutex},
 65//! };
 66//!
 67//! struct MyBlkDevice;
 68//!
 69//! #[vtable]
 70//! impl Operations for MyBlkDevice {
 71//!     type QueueData = ();
 72//!
 73//!     fn queue_rq(_queue_data: (), rq: ARef<Request<Self>>, _is_last: bool) -> Result {
 74//!         Request::end_ok(rq);
 75//!         Ok(())
 76//!     }
 77//!
 78//!     fn commit_rqs(_queue_data: ()) {}
 79//!
 80//!     fn complete(rq: ARef<Request<Self>>) {
 81//!         Request::end_ok(rq)
 82//!             .map_err(|_e| kernel::error::code::EIO)
 83//!             .expect("Fatal error - expected to be able to end request");
 84//!     }
 85//! }
 86//!
 87//! let tagset: Arc<TagSet<MyBlkDevice>> =
 88//!     Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
 89//! let mut disk = gen_disk::GenDiskBuilder::new()
 90//!     .capacity_sectors(4096)
 91//!     .build(fmt!("myblk"), tagset, ())?;
 92//!
 93//! # Ok::<(), kernel::error::Error>(())
 94//! ```
 95
 96pub mod gen_disk;
 97mod operations;
 98mod request;
 99mod tag_set;
100
101pub use operations::Operations;
102pub use request::Request;
103pub use tag_set::TagSet;
~/ Read-only file preview.