1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 //! This module provides types for implementin 3 //! This module provides types for implementing block drivers that interface the 4 //! blk-mq subsystem. 4 //! blk-mq subsystem. 5 //! 5 //! 6 //! To implement a block device driver, a Rust 6 //! To implement a block device driver, a Rust module must do the following: 7 //! 7 //! 8 //! - Implement [`Operations`] for a type `T`. 8 //! - Implement [`Operations`] for a type `T`. 9 //! - Create a [`TagSet<T>`]. 9 //! - Create a [`TagSet<T>`]. 10 //! - Create a [`GenDisk<T>`], via the [`GenDi 10 //! - Create a [`GenDisk<T>`], via the [`GenDiskBuilder`]. 11 //! - Add the disk to the system by calling [` 11 //! - Add the disk to the system by calling [`GenDiskBuilder::build`] passing in 12 //! the `TagSet` reference. 12 //! the `TagSet` reference. 13 //! 13 //! 14 //! The types available in this module that ha 14 //! The types available in this module that have direct C counterparts are: 15 //! 15 //! 16 //! - The [`TagSet`] type that abstracts the C 16 //! - The [`TagSet`] type that abstracts the C type `struct tag_set`. 17 //! - The [`GenDisk`] type that abstracts the 17 //! - The [`GenDisk`] type that abstracts the C type `struct gendisk`. 18 //! - The [`Request`] type that abstracts the 18 //! - The [`Request`] type that abstracts the C type `struct request`. 19 //! 19 //! 20 //! The kernel will interface with the block d 20 //! The kernel will interface with the block device driver by calling the method 21 //! implementations of the `Operations` trait. 21 //! implementations of the `Operations` trait. 22 //! 22 //! 23 //! IO requests are passed to the driver as [` 23 //! IO requests are passed to the driver as [`kernel::types::ARef<Request>`] 24 //! instances. The `Request` type is a wrapper 24 //! instances. The `Request` type is a wrapper around the C `struct request`. 25 //! The driver must mark end of processing by 25 //! The driver must mark end of processing by calling one of the 26 //! `Request::end`, methods. Failure to do so 26 //! `Request::end`, methods. Failure to do so can lead to deadlock or timeout 27 //! errors. Please note that the C function `b 27 //! errors. Please note that the C function `blk_mq_start_request` is implicitly 28 //! called when the request is queued with the 28 //! called when the request is queued with the driver. 29 //! 29 //! 30 //! The `TagSet` is responsible for creating a 30 //! The `TagSet` is responsible for creating and maintaining a mapping between 31 //! `Request`s and integer ids as well as carr 31 //! `Request`s and integer ids as well as carrying a pointer to the vtable 32 //! generated by `Operations`. This mapping is 32 //! generated by `Operations`. This mapping is useful for associating 33 //! completions from hardware with the correct 33 //! completions from hardware with the correct `Request` instance. The `TagSet` 34 //! determines the maximum queue depth by sett 34 //! determines the maximum queue depth by setting the number of `Request` 35 //! instances available to the driver, and it 35 //! instances available to the driver, and it determines the number of queues to 36 //! instantiate for the driver. If possible, a 36 //! instantiate for the driver. If possible, a driver should allocate one queue 37 //! per core, to keep queue data local to a co 37 //! per core, to keep queue data local to a core. 38 //! 38 //! 39 //! One `TagSet` instance can be shared betwee 39 //! One `TagSet` instance can be shared between multiple `GenDisk` instances. 40 //! This can be useful when implementing drive 40 //! This can be useful when implementing drivers where one piece of hardware 41 //! with one set of IO resources are represent 41 //! with one set of IO resources are represented to the user as multiple disks. 42 //! 42 //! 43 //! One significant difference between block d 43 //! One significant difference between block device drivers implemented with 44 //! these Rust abstractions and drivers implem 44 //! these Rust abstractions and drivers implemented in C, is that the Rust 45 //! drivers have to own a reference count on t 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 `s 46 //! in flight. This is to ensure that the C `struct request` instances backing 47 //! the Rust `Request` instances are live whil 47 //! the Rust `Request` instances are live while the Rust driver holds a 48 //! reference to the `Request`. In addition, t 48 //! reference to the `Request`. In addition, the conversion of an integer tag to 49 //! a `Request` via the `TagSet` would not be 49 //! a `Request` via the `TagSet` would not be sound without this bookkeeping. 50 //! 50 //! 51 //! [`GenDisk`]: gen_disk::GenDisk 51 //! [`GenDisk`]: gen_disk::GenDisk 52 //! [`GenDisk<T>`]: gen_disk::GenDisk 52 //! [`GenDisk<T>`]: gen_disk::GenDisk 53 //! [`GenDiskBuilder`]: gen_disk::GenDiskBuild 53 //! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder 54 //! [`GenDiskBuilder::build`]: gen_disk::GenDi 54 //! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build 55 //! 55 //! 56 //! # Example 56 //! # Example 57 //! 57 //! 58 //! ```rust 58 //! ```rust 59 //! use kernel::{ 59 //! use kernel::{ 60 //! alloc::flags, 60 //! alloc::flags, 61 //! block::mq::*, 61 //! block::mq::*, 62 //! new_mutex, 62 //! new_mutex, 63 //! prelude::*, 63 //! prelude::*, 64 //! sync::{Arc, Mutex}, 64 //! sync::{Arc, Mutex}, 65 //! types::{ARef, ForeignOwnable}, 65 //! types::{ARef, ForeignOwnable}, 66 //! }; 66 //! }; 67 //! 67 //! 68 //! struct MyBlkDevice; 68 //! struct MyBlkDevice; 69 //! 69 //! 70 //! #[vtable] 70 //! #[vtable] 71 //! impl Operations for MyBlkDevice { 71 //! impl Operations for MyBlkDevice { 72 //! 72 //! 73 //! fn queue_rq(rq: ARef<Request<Self>>, _ 73 //! fn queue_rq(rq: ARef<Request<Self>>, _is_last: bool) -> Result { 74 //! Request::end_ok(rq); 74 //! Request::end_ok(rq); 75 //! Ok(()) 75 //! Ok(()) 76 //! } 76 //! } 77 //! 77 //! 78 //! fn commit_rqs() {} 78 //! fn commit_rqs() {} 79 //! } 79 //! } 80 //! 80 //! 81 //! let tagset: Arc<TagSet<MyBlkDevice>> = 81 //! let tagset: Arc<TagSet<MyBlkDevice>> = 82 //! Arc::pin_init(TagSet::new(1, 256, 1), 82 //! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?; 83 //! let mut disk = gen_disk::GenDiskBuilder::n 83 //! let mut disk = gen_disk::GenDiskBuilder::new() 84 //! .capacity_sectors(4096) 84 //! .capacity_sectors(4096) 85 //! .build(format_args!("myblk"), tagset)? 85 //! .build(format_args!("myblk"), tagset)?; 86 //! 86 //! 87 //! # Ok::<(), kernel::error::Error>(()) 87 //! # Ok::<(), kernel::error::Error>(()) 88 //! ``` 88 //! ``` 89 89 90 pub mod gen_disk; 90 pub mod gen_disk; 91 mod operations; 91 mod operations; 92 mod raw_writer; 92 mod raw_writer; 93 mod request; 93 mod request; 94 mod tag_set; 94 mod tag_set; 95 95 96 pub use operations::Operations; 96 pub use operations::Operations; 97 pub use request::Request; 97 pub use request::Request; 98 pub use tag_set::TagSet; 98 pub use tag_set::TagSet;
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.