| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- // 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::types::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
- //!
- //! # Example
- //!
- //! ```rust
- //! use kernel::{
- //! alloc::flags,
- //! block::mq::*,
- //! new_mutex,
- //! prelude::*,
- //! sync::{Arc, Mutex},
- //! types::{ARef, ForeignOwnable},
- //! };
- //!
- //! struct MyBlkDevice;
- //!
- //! #[vtable]
- //! impl Operations for MyBlkDevice {
- //!
- //! fn queue_rq(rq: ARef<Request<Self>>, _is_last: bool) -> Result {
- //! Request::end_ok(rq);
- //! Ok(())
- //! }
- //!
- //! fn commit_rqs() {}
- //! }
- //!
- //! 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(format_args!("myblk"), tagset)?;
- //!
- //! # Ok::<(), kernel::error::Error>(())
- //! ```
- pub mod gen_disk;
- mod operations;
- mod raw_writer;
- mod request;
- mod tag_set;
- pub use operations::Operations;
- pub use request::Request;
- pub use tag_set::TagSet;
|