brintos

brintos / linux-shallow public Read only

0
0
Text · 3.7 KiB · fb0f393 Raw
99 lines · rust
1// SPDX-License-Identifier: GPL-2.02 3//! This module provides types for implementing block drivers that interface the4//! 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 in12//!   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 method21//! 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 the26//! `Request::end`, methods. Failure to do so can lead to deadlock or timeout27//! errors. Please note that the C function `blk_mq_start_request` is implicitly28//! called when the request is queued with the driver.29//!30//! The `TagSet` is responsible for creating and maintaining a mapping between31//! `Request`s and integer ids as well as carrying a pointer to the vtable32//! generated by `Operations`. This mapping is useful for associating33//! 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 to36//! instantiate for the driver. If possible, a driver should allocate one queue37//! 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 hardware41//! with one set of IO resources are represented to the user as multiple disks.42//!43//! One significant difference between block device drivers implemented with44//! these Rust abstractions and drivers implemented in C, is that the Rust45//! drivers have to own a reference count on the `Request` type when the IO is46//! in flight. This is to ensure that the C `struct request` instances backing47//! the Rust `Request` instances are live while the Rust driver holds a48//! reference to the `Request`. In addition, the conversion of an integer tag to49//! a `Request` via the `TagSet` would not be sound without this bookkeeping.50//!51//! [`GenDisk`]: gen_disk::GenDisk52//! [`GenDisk<T>`]: gen_disk::GenDisk53//! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder54//! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build55//!56//! # Example57//!58//! ```rust59//! 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;99