// SPDX-License-Identifier: GPL-2.0//! This module provides types for implementing block drivers that interface the//! blk-mq subsystem.//!//! To implement a block device driver, a Rust module must do the following://!//! - Implement [`Operations`] for a type `T`.//! - Create a [`TagSet<T>`].//! - Create a [`GenDisk<T>`], via the [`GenDiskBuilder`].//! - Add the disk to the system by calling [`GenDiskBuilder::build`] passing in//! the `TagSet` reference.//!//! The types available in this module that have direct C counterparts are://!//! - The [`TagSet`] type that abstracts the C type `struct tag_set`.//! - The [`GenDisk`] type that abstracts the C type `struct gendisk`.//! - The [`Request`] type that abstracts the C type `struct request`.//!//! The kernel will interface with the block device driver by calling the method//! implementations of the `Operations` trait.//!//! IO requests are passed to the driver as [`kernel::sync::aref::ARef<Request>`]//! instances. The `Request` type is a wrapper around the C `struct request`.//! The driver must mark end of processing by calling one of the//! `Request::end`, methods. Failure to do so can lead to deadlock or timeout//! errors. Please note that the C function `blk_mq_start_request` is implicitly//! called when the request is queued with the driver.//!//! The `TagSet` is responsible for creating and maintaining a mapping between//! `Request`s and integer ids as well as carrying a pointer to the vtable//! generated by `Operations`. This mapping is useful for associating//! completions from hardware with the correct `Request` instance. The `TagSet`//! determines the maximum queue depth by setting the number of `Request`//! instances available to the driver, and it determines the number of queues to//! instantiate for the driver. If possible, a driver should allocate one queue//! per core, to keep queue data local to a core.//!//! One `TagSet` instance can be shared between multiple `GenDisk` instances.//! This can be useful when implementing drivers where one piece of hardware//! with one set of IO resources are represented to the user as multiple disks.//!//! One significant difference between block device drivers implemented with//! these Rust abstractions and drivers implemented in C, is that the Rust//! drivers have to own a reference count on the `Request` type when the IO is//! in flight. This is to ensure that the C `struct request` instances backing//! the Rust `Request` instances are live while the Rust driver holds a//! reference to the `Request`. In addition, the conversion of an integer tag to//! a `Request` via the `TagSet` would not be sound without this bookkeeping.//!//! [`GenDisk`]: gen_disk::GenDisk//! [`GenDisk<T>`]: gen_disk::GenDisk//! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder//! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build//!//! # Examples//!//! ```rust//! use kernel::{//! alloc::flags,//! block::mq::*,//! new_mutex,//! prelude::*,//! sync::{aref::ARef, Arc, Mutex},//! };//!//! struct MyBlkDevice;//!//! #[vtable]//! impl Operations for MyBlkDevice {//! type QueueData = ();//!//! fn queue_rq(_queue_data: (), rq: ARef<Request<Self>>, _is_last: bool) -> Result {//! Request::end_ok(rq);//! Ok(())//! }//!//! fn commit_rqs(_queue_data: ()) {}//!//! fn complete(rq: ARef<Request<Self>>) {//! Request::end_ok(rq)//! .map_err(|_e| kernel::error::code::EIO)//! .expect("Fatal error - expected to be able to end request");//! }//! }//!//! let tagset: Arc<TagSet<MyBlkDevice>> =//! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;//! let mut disk = gen_disk::GenDiskBuilder::new()//! .capacity_sectors(4096)//! .build(fmt!("myblk"), tagset, ())?;//!//! # Ok::<(), kernel::error::Error>(())//! ```pub mod gen_disk;mod operations;mod request;mod tag_set;pub use operations::Operations;pub use request::Request;pub use tag_set::TagSet;
// SPDX-License-Identifier: GPL-2.0
//! This module provides types for implementing block drivers that interface the
//! blk-mq subsystem.
//!
//! To implement a block device driver, a Rust module must do the following:
//!
//! - Implement [`Operations`] for a type `T`.
//! - Create a [`TagSet<T>`].
//! - Create a [`GenDisk<T>`], via the [`GenDiskBuilder`].
//! - Add the disk to the system by calling [`GenDiskBuilder::build`] passing in
//! the `TagSet` reference.
//!
//! The types available in this module that have direct C counterparts are:
//!
//! - The [`TagSet`] type that abstracts the C type `struct tag_set`.
//! - The [`GenDisk`] type that abstracts the C type `struct gendisk`.
//! - The [`Request`] type that abstracts the C type `struct request`.
//!
//! The kernel will interface with the block device driver by calling the method
//! implementations of the `Operations` trait.
//!
//! IO requests are passed to the driver as [`kernel::sync::aref::ARef<Request>`]
//! instances. The `Request` type is a wrapper around the C `struct request`.
//! The driver must mark end of processing by calling one of the
//! `Request::end`, methods. Failure to do so can lead to deadlock or timeout
//! errors. Please note that the C function `blk_mq_start_request` is implicitly
//! called when the request is queued with the driver.
//!
//! The `TagSet` is responsible for creating and maintaining a mapping between
//! `Request`s and integer ids as well as carrying a pointer to the vtable
//! generated by `Operations`. This mapping is useful for associating
//! completions from hardware with the correct `Request` instance. The `TagSet`
//! determines the maximum queue depth by setting the number of `Request`
//! instances available to the driver, and it determines the number of queues to
//! instantiate for the driver. If possible, a driver should allocate one queue
//! per core, to keep queue data local to a core.
//!
//! One `TagSet` instance can be shared between multiple `GenDisk` instances.
//! This can be useful when implementing drivers where one piece of hardware
//! with one set of IO resources are represented to the user as multiple disks.
//!
//! One significant difference between block device drivers implemented with
//! these Rust abstractions and drivers implemented in C, is that the Rust
//! drivers have to own a reference count on the `Request` type when the IO is
//! in flight. This is to ensure that the C `struct request` instances backing
//! the Rust `Request` instances are live while the Rust driver holds a
//! reference to the `Request`. In addition, the conversion of an integer tag to
//! a `Request` via the `TagSet` would not be sound without this bookkeeping.
//!
//! [`GenDisk`]: gen_disk::GenDisk
//! [`GenDisk<T>`]: gen_disk::GenDisk
//! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder
//! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build
//!
//! # Examples
//!
//! ```rust
//! use kernel::{
//! alloc::flags,
//! block::mq::*,
//! new_mutex,
//! prelude::*,
//! sync::{aref::ARef, Arc, Mutex},
//! };
//!
//! struct MyBlkDevice;
//!
//! #[vtable]
//! impl Operations for MyBlkDevice {
//! type QueueData = ();
//!
//! fn queue_rq(_queue_data: (), rq: ARef<Request<Self>>, _is_last: bool) -> Result {
//! Request::end_ok(rq);
//! Ok(())
//! }
//!
//! fn commit_rqs(_queue_data: ()) {}
//!
//! fn complete(rq: ARef<Request<Self>>) {
//! Request::end_ok(rq)
//! .map_err(|_e| kernel::error::code::EIO)
//! .expect("Fatal error - expected to be able to end request");
//! }
//! }
//!
//! let tagset: Arc<TagSet<MyBlkDevice>> =
//! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
//! let mut disk = gen_disk::GenDiskBuilder::new()
//! .capacity_sectors(4096)
//! .build(fmt!("myblk"), tagset, ())?;
//!
//! # Ok::<(), kernel::error::Error>(())
//! ```
pub mod gen_disk;
mod operations;
mod request;
mod tag_set;
pub use operations::Operations;
pub use request::Request;
pub use tag_set::TagSet;