C block device drivers can attach private data to a `struct blk_mq_tag_set`. Add support for this feature for Rust block device drivers via the `Operations::TagSetData` associated type. The private data is passed to `TagSet::new` and is stored in the `driver_data` field of the underlying `struct blk_mq_tag_set`. It is released when the `TagSet` is dropped. Signed-off-by: Andreas Hindborg --- drivers/block/rnull/rnull.rs | 3 ++- rust/kernel/block/mq.rs | 6 ++++-- rust/kernel/block/mq/operations.rs | 4 ++++ rust/kernel/block/mq/tag_set.rs | 25 ++++++++++++++++++++----- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs index 6691e5912c5c9..9e8d085924040 100644 --- a/drivers/block/rnull/rnull.rs +++ b/drivers/block/rnull/rnull.rs @@ -229,7 +229,7 @@ fn new(options: NullBlkOptions<'_>) -> Result> { } let tagset = Arc::pin_init( - TagSet::new(submit_queues, 256, 1, home_node, flags), + TagSet::new(submit_queues, (), 256, 1, home_node, flags), GFP_KERNEL, )?; @@ -505,6 +505,7 @@ fn align_down(value: T, to: T) -> T impl Operations for NullBlkDevice { type QueueData = Pin>; type RequestData = Pdu; + type TagSetData = (); fn new_request_data() -> impl PinInit { pin_init!(Pdu { diff --git a/rust/kernel/block/mq.rs b/rust/kernel/block/mq.rs index d3957f2fb1a66..415be31e9a777 100644 --- a/rust/kernel/block/mq.rs +++ b/rust/kernel/block/mq.rs @@ -71,6 +71,7 @@ //! impl Operations for MyBlkDevice { //! type RequestData = (); //! type QueueData = (); +//! type TagSetData = (); //! //! fn new_request_data( //! ) -> impl PinInit<()> { @@ -94,8 +95,9 @@ //! //! let tagset: Arc> = //! Arc::pin_init( -//! TagSet::new(1, 256, 1, bindings::NUMA_NO_NODE, mq::tag_set::Flags::default()), -//! GFP_KERNEL)?; +//! TagSet::new(1, (), 256, 1, bindings::NUMA_NO_NODE, mq::tag_set::Flags::default()), +//! GFP_KERNEL +//! )?; //! let mut disk = gen_disk::GenDiskBuilder::new() //! .capacity_sectors(4096) //! .build(fmt!("myblk"), tagset, ())?; diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs index cd37b939bbf30..9aab6240428cc 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -44,6 +44,10 @@ pub trait Operations: Sized { /// the `GenDisk` associated with this `Operations` implementation. type QueueData: ForeignOwnable; + /// Data associated with a `TagSet`. This is stored as a pointer in `struct + /// blk_mq_tag_set`. + type TagSetData: ForeignOwnable; + /// Called by the kernel to get an initializer for a `Pin<&mut RequestData>`. fn new_request_data() -> impl PinInit; diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index e9b36d6329b9b..f18b51e5217fe 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -10,8 +10,8 @@ bindings, block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations}, error::{self, Result}, - prelude::try_pin_init, - types::Opaque, + try_pin_init, + types::{ForeignOwnable, Opaque}, }; use core::{convert::TryInto, marker::PhantomData}; use pin_init::{pin_data, pinned_drop, PinInit}; @@ -39,6 +39,7 @@ impl TagSet { /// Try to create a new tag set pub fn new( nr_hw_queues: u32, + tagset_data: T::TagSetData, num_tags: u32, num_maps: u32, numa_node: i32, @@ -58,7 +59,7 @@ pub fn new( queue_depth: num_tags, cmd_size, flags: flags.into_inner(), - driver_data: core::ptr::null_mut::(), + driver_data: tagset_data.into_foreign(), nr_maps: num_maps, ..tag_set } @@ -71,7 +72,14 @@ pub fn new( // SAFETY: we do not move out of `tag_set`. let tag_set: &mut Opaque<_> = unsafe { Pin::get_unchecked_mut(tag_set) }; // SAFETY: `tag_set` is a reference to an initialized `blk_mq_tag_set`. - error::to_result( unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())}) + let status = error::to_result( + unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())} + ); + if status.is_err() { + // SAFETY: We created `driver_data` above with `into_foreign` + unsafe { T::TagSetData::from_foreign((*tag_set.get()).driver_data) }; + } + status }), _p: PhantomData, }) @@ -87,7 +95,14 @@ pub(crate) fn raw_tag_set(&self) -> *mut bindings::blk_mq_tag_set { impl PinnedDrop for TagSet { fn drop(self: Pin<&mut Self>) { // SAFETY: By type invariant `inner` is valid and has been properly - // initialized during construction. + // initialised during construction. + let tagset_data = unsafe { (*self.inner.get()).driver_data }; + + // SAFETY: `inner` is valid and has been properly initialised during construction. unsafe { bindings::blk_mq_free_tag_set(self.inner.get()) }; + + // SAFETY: `tagset_data` was created by a call to + // `ForeignOwnable::into_foreign` in `TagSet::try_new()` + unsafe { T::TagSetData::from_foreign(tagset_data) }; } } -- 2.51.2