1*3253aba3SAndreas Hindborg // SPDX-License-Identifier: GPL-2.0 2*3253aba3SAndreas Hindborg 3*3253aba3SAndreas Hindborg //! This module provides an interface for blk-mq drivers to implement. 4*3253aba3SAndreas Hindborg //! 5*3253aba3SAndreas Hindborg //! C header: [`include/linux/blk-mq.h`](srctree/include/linux/blk-mq.h) 6*3253aba3SAndreas Hindborg 7*3253aba3SAndreas Hindborg use crate::{ 8*3253aba3SAndreas Hindborg bindings, 9*3253aba3SAndreas Hindborg block::mq::request::RequestDataWrapper, 10*3253aba3SAndreas Hindborg block::mq::Request, 11*3253aba3SAndreas Hindborg error::{from_result, Result}, 12*3253aba3SAndreas Hindborg types::ARef, 13*3253aba3SAndreas Hindborg }; 14*3253aba3SAndreas Hindborg use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering}; 15*3253aba3SAndreas Hindborg 16*3253aba3SAndreas Hindborg /// Implement this trait to interface blk-mq as block devices. 17*3253aba3SAndreas Hindborg /// 18*3253aba3SAndreas Hindborg /// To implement a block device driver, implement this trait as described in the 19*3253aba3SAndreas Hindborg /// [module level documentation]. The kernel will use the implementation of the 20*3253aba3SAndreas Hindborg /// functions defined in this trait to interface a block device driver. Note: 21*3253aba3SAndreas Hindborg /// There is no need for an exit_request() implementation, because the `drop` 22*3253aba3SAndreas Hindborg /// implementation of the [`Request`] type will be invoked by automatically by 23*3253aba3SAndreas Hindborg /// the C/Rust glue logic. 24*3253aba3SAndreas Hindborg /// 25*3253aba3SAndreas Hindborg /// [module level documentation]: kernel::block::mq 26*3253aba3SAndreas Hindborg #[macros::vtable] 27*3253aba3SAndreas Hindborg pub trait Operations: Sized { 28*3253aba3SAndreas Hindborg /// Called by the kernel to queue a request with the driver. If `is_last` is 29*3253aba3SAndreas Hindborg /// `false`, the driver is allowed to defer committing the request. queue_rq(rq: ARef<Request<Self>>, is_last: bool) -> Result30*3253aba3SAndreas Hindborg fn queue_rq(rq: ARef<Request<Self>>, is_last: bool) -> Result; 31*3253aba3SAndreas Hindborg 32*3253aba3SAndreas Hindborg /// Called by the kernel to indicate that queued requests should be submitted. commit_rqs()33*3253aba3SAndreas Hindborg fn commit_rqs(); 34*3253aba3SAndreas Hindborg 35*3253aba3SAndreas Hindborg /// Called by the kernel to poll the device for completed requests. Only 36*3253aba3SAndreas Hindborg /// used for poll queues. poll() -> bool37*3253aba3SAndreas Hindborg fn poll() -> bool { 38*3253aba3SAndreas Hindborg crate::build_error(crate::error::VTABLE_DEFAULT_ERROR) 39*3253aba3SAndreas Hindborg } 40*3253aba3SAndreas Hindborg } 41*3253aba3SAndreas Hindborg 42*3253aba3SAndreas Hindborg /// A vtable for blk-mq to interact with a block device driver. 43*3253aba3SAndreas Hindborg /// 44*3253aba3SAndreas Hindborg /// A `bindings::blk_mq_ops` vtable is constructed from pointers to the `extern 45*3253aba3SAndreas Hindborg /// "C"` functions of this struct, exposed through the `OperationsVTable::VTABLE`. 46*3253aba3SAndreas Hindborg /// 47*3253aba3SAndreas Hindborg /// For general documentation of these methods, see the kernel source 48*3253aba3SAndreas Hindborg /// documentation related to `struct blk_mq_operations` in 49*3253aba3SAndreas Hindborg /// [`include/linux/blk-mq.h`]. 50*3253aba3SAndreas Hindborg /// 51*3253aba3SAndreas Hindborg /// [`include/linux/blk-mq.h`]: srctree/include/linux/blk-mq.h 52*3253aba3SAndreas Hindborg pub(crate) struct OperationsVTable<T: Operations>(PhantomData<T>); 53*3253aba3SAndreas Hindborg 54*3253aba3SAndreas Hindborg impl<T: Operations> OperationsVTable<T> { 55*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 56*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 57*3253aba3SAndreas Hindborg /// 58*3253aba3SAndreas Hindborg /// # Safety 59*3253aba3SAndreas Hindborg /// 60*3253aba3SAndreas Hindborg /// - The caller of this function must ensure that the pointee of `bd` is 61*3253aba3SAndreas Hindborg /// valid for reads for the duration of this function. 62*3253aba3SAndreas Hindborg /// - This function must be called for an initialized and live `hctx`. That 63*3253aba3SAndreas Hindborg /// is, `Self::init_hctx_callback` was called and 64*3253aba3SAndreas Hindborg /// `Self::exit_hctx_callback()` was not yet called. 65*3253aba3SAndreas Hindborg /// - `(*bd).rq` must point to an initialized and live `bindings:request`. 66*3253aba3SAndreas Hindborg /// That is, `Self::init_request_callback` was called but 67*3253aba3SAndreas Hindborg /// `Self::exit_request_callback` was not yet called for the request. 68*3253aba3SAndreas Hindborg /// - `(*bd).rq` must be owned by the driver. That is, the block layer must 69*3253aba3SAndreas Hindborg /// promise to not access the request until the driver calls 70*3253aba3SAndreas Hindborg /// `bindings::blk_mq_end_request` for the request. queue_rq_callback( _hctx: *mut bindings::blk_mq_hw_ctx, bd: *const bindings::blk_mq_queue_data, ) -> bindings::blk_status_t71*3253aba3SAndreas Hindborg unsafe extern "C" fn queue_rq_callback( 72*3253aba3SAndreas Hindborg _hctx: *mut bindings::blk_mq_hw_ctx, 73*3253aba3SAndreas Hindborg bd: *const bindings::blk_mq_queue_data, 74*3253aba3SAndreas Hindborg ) -> bindings::blk_status_t { 75*3253aba3SAndreas Hindborg // SAFETY: `bd.rq` is valid as required by the safety requirement for 76*3253aba3SAndreas Hindborg // this function. 77*3253aba3SAndreas Hindborg let request = unsafe { &*(*bd).rq.cast::<Request<T>>() }; 78*3253aba3SAndreas Hindborg 79*3253aba3SAndreas Hindborg // One refcount for the ARef, one for being in flight 80*3253aba3SAndreas Hindborg request.wrapper_ref().refcount().store(2, Ordering::Relaxed); 81*3253aba3SAndreas Hindborg 82*3253aba3SAndreas Hindborg // SAFETY: 83*3253aba3SAndreas Hindborg // - We own a refcount that we took above. We pass that to `ARef`. 84*3253aba3SAndreas Hindborg // - By the safety requirements of this function, `request` is a valid 85*3253aba3SAndreas Hindborg // `struct request` and the private data is properly initialized. 86*3253aba3SAndreas Hindborg // - `rq` will be alive until `blk_mq_end_request` is called and is 87*3253aba3SAndreas Hindborg // reference counted by `ARef` until then. 88*3253aba3SAndreas Hindborg let rq = unsafe { Request::aref_from_raw((*bd).rq) }; 89*3253aba3SAndreas Hindborg 90*3253aba3SAndreas Hindborg // SAFETY: We have exclusive access and we just set the refcount above. 91*3253aba3SAndreas Hindborg unsafe { Request::start_unchecked(&rq) }; 92*3253aba3SAndreas Hindborg 93*3253aba3SAndreas Hindborg let ret = T::queue_rq( 94*3253aba3SAndreas Hindborg rq, 95*3253aba3SAndreas Hindborg // SAFETY: `bd` is valid as required by the safety requirement for 96*3253aba3SAndreas Hindborg // this function. 97*3253aba3SAndreas Hindborg unsafe { (*bd).last }, 98*3253aba3SAndreas Hindborg ); 99*3253aba3SAndreas Hindborg 100*3253aba3SAndreas Hindborg if let Err(e) = ret { 101*3253aba3SAndreas Hindborg e.to_blk_status() 102*3253aba3SAndreas Hindborg } else { 103*3253aba3SAndreas Hindborg bindings::BLK_STS_OK as _ 104*3253aba3SAndreas Hindborg } 105*3253aba3SAndreas Hindborg } 106*3253aba3SAndreas Hindborg 107*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 108*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 109*3253aba3SAndreas Hindborg /// 110*3253aba3SAndreas Hindborg /// # Safety 111*3253aba3SAndreas Hindborg /// 112*3253aba3SAndreas Hindborg /// This function may only be called by blk-mq C infrastructure. commit_rqs_callback(_hctx: *mut bindings::blk_mq_hw_ctx)113*3253aba3SAndreas Hindborg unsafe extern "C" fn commit_rqs_callback(_hctx: *mut bindings::blk_mq_hw_ctx) { 114*3253aba3SAndreas Hindborg T::commit_rqs() 115*3253aba3SAndreas Hindborg } 116*3253aba3SAndreas Hindborg 117*3253aba3SAndreas Hindborg /// This function is called by the C kernel. It is not currently 118*3253aba3SAndreas Hindborg /// implemented, and there is no way to exercise this code path. 119*3253aba3SAndreas Hindborg /// 120*3253aba3SAndreas Hindborg /// # Safety 121*3253aba3SAndreas Hindborg /// 122*3253aba3SAndreas Hindborg /// This function may only be called by blk-mq C infrastructure. complete_callback(_rq: *mut bindings::request)123*3253aba3SAndreas Hindborg unsafe extern "C" fn complete_callback(_rq: *mut bindings::request) {} 124*3253aba3SAndreas Hindborg 125*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 126*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 127*3253aba3SAndreas Hindborg /// 128*3253aba3SAndreas Hindborg /// # Safety 129*3253aba3SAndreas Hindborg /// 130*3253aba3SAndreas Hindborg /// This function may only be called by blk-mq C infrastructure. poll_callback( _hctx: *mut bindings::blk_mq_hw_ctx, _iob: *mut bindings::io_comp_batch, ) -> core::ffi::c_int131*3253aba3SAndreas Hindborg unsafe extern "C" fn poll_callback( 132*3253aba3SAndreas Hindborg _hctx: *mut bindings::blk_mq_hw_ctx, 133*3253aba3SAndreas Hindborg _iob: *mut bindings::io_comp_batch, 134*3253aba3SAndreas Hindborg ) -> core::ffi::c_int { 135*3253aba3SAndreas Hindborg T::poll().into() 136*3253aba3SAndreas Hindborg } 137*3253aba3SAndreas Hindborg 138*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 139*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 140*3253aba3SAndreas Hindborg /// 141*3253aba3SAndreas Hindborg /// # Safety 142*3253aba3SAndreas Hindborg /// 143*3253aba3SAndreas Hindborg /// This function may only be called by blk-mq C infrastructure. This 144*3253aba3SAndreas Hindborg /// function may only be called once before `exit_hctx_callback` is called 145*3253aba3SAndreas Hindborg /// for the same context. init_hctx_callback( _hctx: *mut bindings::blk_mq_hw_ctx, _tagset_data: *mut core::ffi::c_void, _hctx_idx: core::ffi::c_uint, ) -> core::ffi::c_int146*3253aba3SAndreas Hindborg unsafe extern "C" fn init_hctx_callback( 147*3253aba3SAndreas Hindborg _hctx: *mut bindings::blk_mq_hw_ctx, 148*3253aba3SAndreas Hindborg _tagset_data: *mut core::ffi::c_void, 149*3253aba3SAndreas Hindborg _hctx_idx: core::ffi::c_uint, 150*3253aba3SAndreas Hindborg ) -> core::ffi::c_int { 151*3253aba3SAndreas Hindborg from_result(|| Ok(0)) 152*3253aba3SAndreas Hindborg } 153*3253aba3SAndreas Hindborg 154*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 155*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 156*3253aba3SAndreas Hindborg /// 157*3253aba3SAndreas Hindborg /// # Safety 158*3253aba3SAndreas Hindborg /// 159*3253aba3SAndreas Hindborg /// This function may only be called by blk-mq C infrastructure. exit_hctx_callback( _hctx: *mut bindings::blk_mq_hw_ctx, _hctx_idx: core::ffi::c_uint, )160*3253aba3SAndreas Hindborg unsafe extern "C" fn exit_hctx_callback( 161*3253aba3SAndreas Hindborg _hctx: *mut bindings::blk_mq_hw_ctx, 162*3253aba3SAndreas Hindborg _hctx_idx: core::ffi::c_uint, 163*3253aba3SAndreas Hindborg ) { 164*3253aba3SAndreas Hindborg } 165*3253aba3SAndreas Hindborg 166*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 167*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 168*3253aba3SAndreas Hindborg /// 169*3253aba3SAndreas Hindborg /// # Safety 170*3253aba3SAndreas Hindborg /// 171*3253aba3SAndreas Hindborg /// - This function may only be called by blk-mq C infrastructure. 172*3253aba3SAndreas Hindborg /// - `_set` must point to an initialized `TagSet<T>`. 173*3253aba3SAndreas Hindborg /// - `rq` must point to an initialized `bindings::request`. 174*3253aba3SAndreas Hindborg /// - The allocation pointed to by `rq` must be at the size of `Request` 175*3253aba3SAndreas Hindborg /// plus the size of `RequestDataWrapper`. init_request_callback( _set: *mut bindings::blk_mq_tag_set, rq: *mut bindings::request, _hctx_idx: core::ffi::c_uint, _numa_node: core::ffi::c_uint, ) -> core::ffi::c_int176*3253aba3SAndreas Hindborg unsafe extern "C" fn init_request_callback( 177*3253aba3SAndreas Hindborg _set: *mut bindings::blk_mq_tag_set, 178*3253aba3SAndreas Hindborg rq: *mut bindings::request, 179*3253aba3SAndreas Hindborg _hctx_idx: core::ffi::c_uint, 180*3253aba3SAndreas Hindborg _numa_node: core::ffi::c_uint, 181*3253aba3SAndreas Hindborg ) -> core::ffi::c_int { 182*3253aba3SAndreas Hindborg from_result(|| { 183*3253aba3SAndreas Hindborg // SAFETY: By the safety requirements of this function, `rq` points 184*3253aba3SAndreas Hindborg // to a valid allocation. 185*3253aba3SAndreas Hindborg let pdu = unsafe { Request::wrapper_ptr(rq.cast::<Request<T>>()) }; 186*3253aba3SAndreas Hindborg 187*3253aba3SAndreas Hindborg // SAFETY: The refcount field is allocated but not initialized, so 188*3253aba3SAndreas Hindborg // it is valid for writes. 189*3253aba3SAndreas Hindborg unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(AtomicU64::new(0)) }; 190*3253aba3SAndreas Hindborg 191*3253aba3SAndreas Hindborg Ok(0) 192*3253aba3SAndreas Hindborg }) 193*3253aba3SAndreas Hindborg } 194*3253aba3SAndreas Hindborg 195*3253aba3SAndreas Hindborg /// This function is called by the C kernel. A pointer to this function is 196*3253aba3SAndreas Hindborg /// installed in the `blk_mq_ops` vtable for the driver. 197*3253aba3SAndreas Hindborg /// 198*3253aba3SAndreas Hindborg /// # Safety 199*3253aba3SAndreas Hindborg /// 200*3253aba3SAndreas Hindborg /// - This function may only be called by blk-mq C infrastructure. 201*3253aba3SAndreas Hindborg /// - `_set` must point to an initialized `TagSet<T>`. 202*3253aba3SAndreas Hindborg /// - `rq` must point to an initialized and valid `Request`. exit_request_callback( _set: *mut bindings::blk_mq_tag_set, rq: *mut bindings::request, _hctx_idx: core::ffi::c_uint, )203*3253aba3SAndreas Hindborg unsafe extern "C" fn exit_request_callback( 204*3253aba3SAndreas Hindborg _set: *mut bindings::blk_mq_tag_set, 205*3253aba3SAndreas Hindborg rq: *mut bindings::request, 206*3253aba3SAndreas Hindborg _hctx_idx: core::ffi::c_uint, 207*3253aba3SAndreas Hindborg ) { 208*3253aba3SAndreas Hindborg // SAFETY: The tagset invariants guarantee that all requests are allocated with extra memory 209*3253aba3SAndreas Hindborg // for the request data. 210*3253aba3SAndreas Hindborg let pdu = unsafe { bindings::blk_mq_rq_to_pdu(rq) }.cast::<RequestDataWrapper>(); 211*3253aba3SAndreas Hindborg 212*3253aba3SAndreas Hindborg // SAFETY: `pdu` is valid for read and write and is properly initialised. 213*3253aba3SAndreas Hindborg unsafe { core::ptr::drop_in_place(pdu) }; 214*3253aba3SAndreas Hindborg } 215*3253aba3SAndreas Hindborg 216*3253aba3SAndreas Hindborg const VTABLE: bindings::blk_mq_ops = bindings::blk_mq_ops { 217*3253aba3SAndreas Hindborg queue_rq: Some(Self::queue_rq_callback), 218*3253aba3SAndreas Hindborg queue_rqs: None, 219*3253aba3SAndreas Hindborg commit_rqs: Some(Self::commit_rqs_callback), 220*3253aba3SAndreas Hindborg get_budget: None, 221*3253aba3SAndreas Hindborg put_budget: None, 222*3253aba3SAndreas Hindborg set_rq_budget_token: None, 223*3253aba3SAndreas Hindborg get_rq_budget_token: None, 224*3253aba3SAndreas Hindborg timeout: None, 225*3253aba3SAndreas Hindborg poll: if T::HAS_POLL { 226*3253aba3SAndreas Hindborg Some(Self::poll_callback) 227*3253aba3SAndreas Hindborg } else { 228*3253aba3SAndreas Hindborg None 229*3253aba3SAndreas Hindborg }, 230*3253aba3SAndreas Hindborg complete: Some(Self::complete_callback), 231*3253aba3SAndreas Hindborg init_hctx: Some(Self::init_hctx_callback), 232*3253aba3SAndreas Hindborg exit_hctx: Some(Self::exit_hctx_callback), 233*3253aba3SAndreas Hindborg init_request: Some(Self::init_request_callback), 234*3253aba3SAndreas Hindborg exit_request: Some(Self::exit_request_callback), 235*3253aba3SAndreas Hindborg cleanup_rq: None, 236*3253aba3SAndreas Hindborg busy: None, 237*3253aba3SAndreas Hindborg map_queues: None, 238*3253aba3SAndreas Hindborg #[cfg(CONFIG_BLK_DEBUG_FS)] 239*3253aba3SAndreas Hindborg show_rq: None, 240*3253aba3SAndreas Hindborg }; 241*3253aba3SAndreas Hindborg build() -> &'static bindings::blk_mq_ops242*3253aba3SAndreas Hindborg pub(crate) const fn build() -> &'static bindings::blk_mq_ops { 243*3253aba3SAndreas Hindborg &Self::VTABLE 244*3253aba3SAndreas Hindborg } 245*3253aba3SAndreas Hindborg } 246