// SPDX-License-Identifier: GPL-2.012//! This module provides types for implementing block drivers that interface the3//! blk-mq subsystem.4//!5//! To implement a block device driver, a Rust module must do the following:6//!7//! - Implement [`Operations`] for a type `T`.8//! - Create a [`TagSet<T>`].9//! - Create a [`GenDisk<T>`], via the [`GenDiskBuilder`].10//! - Add the disk to the system by calling [`GenDiskBuilder::build`] passing in11//! the `TagSet` reference.12//!13//! The types available in this module that have direct C counterparts are:14//!15//! - The [`TagSet`] type that abstracts the C type `struct tag_set`.16//! - The [`GenDisk`] type that abstracts the C type `struct gendisk`.17//! - The [`Request`] type that abstracts the C type `struct request`.18//!19//! The kernel will interface with the block device driver by calling the method20//! implementations of the `Operations` trait.21//!22//! IO requests are passed to the driver as [`kernel::types::ARef<Request>`]23//! instances. The `Request` type is a wrapper around the C `struct request`.24//! The driver must mark end of processing by calling one of the25//! `Request::end`, methods. Failure to do so can lead to deadlock or timeout26//! errors. Please note that the C function `blk_mq_start_request` is implicitly27//! called when the request is queued with the driver.28//!29//! The `TagSet` is responsible for creating and maintaining a mapping between30//! `Request`s and integer ids as well as carrying a pointer to the vtable31//! generated by `Operations`. This mapping is useful for associating32//! completions from hardware with the correct `Request` instance. The `TagSet`33//! determines the maximum queue depth by setting the number of `Request`34//! instances available to the driver, and it determines the number of queues to35//! instantiate for the driver. If possible, a driver should allocate one queue36//! per core, to keep queue data local to a core.37//!38//! One `TagSet` instance can be shared between multiple `GenDisk` instances.39//! This can be useful when implementing drivers where one piece of hardware40//! with one set of IO resources are represented to the user as multiple disks.41//!42//! One significant difference between block device drivers implemented with43//! these Rust abstractions and drivers implemented in C, is that the Rust44//! drivers have to own a reference count on the `Request` type when the IO is45//! in flight. This is to ensure that the C `struct request` instances backing46//! the Rust `Request` instances are live while the Rust driver holds a47//! reference to the `Request`. In addition, the conversion of an integer tag to48//! a `Request` via the `TagSet` would not be sound without this bookkeeping.49//!50//! [`GenDisk`]: gen_disk::GenDisk51//! [`GenDisk<T>`]: gen_disk::GenDisk52//! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder53//! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build54//!55//! # Examples56//!57//! ```rust58//! use kernel::{59//! alloc::flags,60//! block::mq::*,61//! new_mutex,62//! prelude::*,63//! sync::{Arc, Mutex},64//! types::{ARef, ForeignOwnable},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//! ```9596pub mod gen_disk;97mod operations;98mod request;99mod tag_set;100101pub use operations::Operations;102pub use request::Request;103pub use tag_set::TagSet;104105106