mq.rs 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // SPDX-License-Identifier: GPL-2.0
  2. //! This module provides types for implementing block drivers that interface the
  3. //! 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 in
  11. //! 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 method
  20. //! 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 the
  25. //! `Request::end`, methods. Failure to do so can lead to deadlock or timeout
  26. //! errors. Please note that the C function `blk_mq_start_request` is implicitly
  27. //! called when the request is queued with the driver.
  28. //!
  29. //! The `TagSet` is responsible for creating and maintaining a mapping between
  30. //! `Request`s and integer ids as well as carrying a pointer to the vtable
  31. //! generated by `Operations`. This mapping is useful for associating
  32. //! 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 to
  35. //! instantiate for the driver. If possible, a driver should allocate one queue
  36. //! 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 hardware
  40. //! with one set of IO resources are represented to the user as multiple disks.
  41. //!
  42. //! One significant difference between block device drivers implemented with
  43. //! these Rust abstractions and drivers implemented in C, is that the Rust
  44. //! drivers have to own a reference count on the `Request` type when the IO is
  45. //! in flight. This is to ensure that the C `struct request` instances backing
  46. //! the Rust `Request` instances are live while the Rust driver holds a
  47. //! reference to the `Request`. In addition, the conversion of an integer tag to
  48. //! a `Request` via the `TagSet` would not be sound without this bookkeeping.
  49. //!
  50. //! [`GenDisk`]: gen_disk::GenDisk
  51. //! [`GenDisk<T>`]: gen_disk::GenDisk
  52. //! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder
  53. //! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build
  54. //!
  55. //! # Example
  56. //!
  57. //! ```rust
  58. //! 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. //!
  72. //! fn queue_rq(rq: ARef<Request<Self>>, _is_last: bool) -> Result {
  73. //! Request::end_ok(rq);
  74. //! Ok(())
  75. //! }
  76. //!
  77. //! fn commit_rqs() {}
  78. //! }
  79. //!
  80. //! let tagset: Arc<TagSet<MyBlkDevice>> =
  81. //! Arc::pin_init(TagSet::new(1, 256, 1), flags::GFP_KERNEL)?;
  82. //! let mut disk = gen_disk::GenDiskBuilder::new()
  83. //! .capacity_sectors(4096)
  84. //! .build(format_args!("myblk"), tagset)?;
  85. //!
  86. //! # Ok::<(), kernel::error::Error>(())
  87. //! ```
  88. pub mod gen_disk;
  89. mod operations;
  90. mod raw_writer;
  91. mod request;
  92. mod tag_set;
  93. pub use operations::Operations;
  94. pub use request::Request;
  95. pub use tag_set::TagSet;