1 // SPDX-License-Identifier: GPL-2.0 2 3 //! This module provides the `TagSet` struct to wrap the C `struct blk_mq_tag_set`. 4 //! 5 //! C header: [`include/linux/blk-mq.h`](srctree/include/linux/blk-mq.h) 6 7 use core::pin::Pin; 8 9 use crate::{ 10 bindings, 11 block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations}, 12 error::{self, Result}, 13 prelude::try_pin_init, 14 types::Opaque, 15 }; 16 use core::{convert::TryInto, marker::PhantomData}; 17 use pin_init::{pin_data, pinned_drop, PinInit}; 18 19 /// A wrapper for the C `struct blk_mq_tag_set`. 20 /// 21 /// `struct blk_mq_tag_set` contains a `struct list_head` and so must be pinned. 22 /// 23 /// # Invariants 24 /// 25 /// - `inner` is initialized and valid. 26 #[pin_data(PinnedDrop)] 27 #[repr(transparent)] 28 pub struct TagSet<T: Operations> { 29 #[pin] 30 inner: Opaque<bindings::blk_mq_tag_set>, 31 _p: PhantomData<T>, 32 } 33 34 impl<T: Operations> TagSet<T> { 35 /// Try to create a new tag set 36 pub fn new( 37 nr_hw_queues: u32, 38 num_tags: u32, 39 num_maps: u32, 40 ) -> impl PinInit<Self, error::Error> { 41 let tag_set: bindings::blk_mq_tag_set = pin_init::zeroed(); 42 let tag_set: Result<_> = core::mem::size_of::<RequestDataWrapper>() 43 .try_into() 44 .map(|cmd_size| { 45 bindings::blk_mq_tag_set { 46 ops: OperationsVTable::<T>::build(), 47 nr_hw_queues, 48 timeout: 0, // 0 means default which is 30Hz in C 49 numa_node: bindings::NUMA_NO_NODE, 50 queue_depth: num_tags, 51 cmd_size, 52 flags: 0, 53 driver_data: core::ptr::null_mut::<crate::ffi::c_void>(), 54 nr_maps: num_maps, 55 ..tag_set 56 } 57 }) 58 .map(Opaque::new) 59 .map_err(|e| e.into()); 60 61 try_pin_init!(TagSet { 62 inner <- tag_set.pin_chain(|tag_set| { 63 // SAFETY: we do not move out of `tag_set`. 64 let tag_set: &mut Opaque<_> = unsafe { Pin::get_unchecked_mut(tag_set) }; 65 // SAFETY: `tag_set` is a reference to an initialized `blk_mq_tag_set`. 66 error::to_result( unsafe { bindings::blk_mq_alloc_tag_set(tag_set.get())}) 67 }), 68 _p: PhantomData, 69 }) 70 } 71 72 /// Return the pointer to the wrapped `struct blk_mq_tag_set` 73 pub(crate) fn raw_tag_set(&self) -> *mut bindings::blk_mq_tag_set { 74 self.inner.get() 75 } 76 } 77 78 #[pinned_drop] 79 impl<T: Operations> PinnedDrop for TagSet<T> { 80 fn drop(self: Pin<&mut Self>) { 81 // SAFETY: By type invariant `inner` is valid and has been properly 82 // initialized during construction. 83 unsafe { bindings::blk_mq_free_tag_set(self.inner.get()) }; 84 } 85 } 86