diff --git a/src/bdev_desc.rs b/src/bdev_desc.rs index 86d0731..8544f12 100644 --- a/src/bdev_desc.rs +++ b/src/bdev_desc.rs @@ -147,88 +147,6 @@ where } } - /// Gains exclusive access over a block range, and returns - /// a lock object that must be used to unlock the range. - pub async fn lock_lba_range( - &self, - range: LbaRange, - ) -> Result, BdevDescError> { - let (s, r) = oneshot::channel::(); - - let ctx = Box::new(LockContext { - range, - ch: self.io_channel()?, - sender: Some(s), - }); - - unsafe { - let rc = bdev_lock_lba_range( - self.as_ptr(), - ctx.ch.legacy_as_ptr(), - ctx.range.offset, - ctx.range.len, - Some(LockContext::::lba_op_completion_cb), - ctx.as_ref() as *const _ as *mut c_void, - ); - if rc != 0 { - return Err(BdevDescError::LbaLock { - source: nix::errno::from_i32(rc), - bdev_name: self.bdev().name().to_owned(), - }); - } - } - - // Wait for the lock to complete - let rc = r.await.unwrap(); - if rc != 0 { - return Err(BdevDescError::LbaLock { - source: nix::errno::from_i32(rc), - bdev_name: self.bdev().name().to_owned(), - }); - } - - Ok(LbaRangeLock { - ctx, - }) - } - - /// Releases exclusive access over a block range. - pub async fn unlock_lba_range( - &self, - mut lock: LbaRangeLock, - ) -> Result<(), BdevDescError> { - let (s, r) = oneshot::channel::(); - lock.ctx.sender = Some(s); - - unsafe { - let rc = bdev_unlock_lba_range( - self.as_ptr(), - lock.ctx.ch.legacy_as_ptr(), - lock.ctx.range.offset, - lock.ctx.range.len, - Some(LockContext::::lba_op_completion_cb), - lock.ctx.as_ref() as *const _ as *mut c_void, - ); - if rc != 0 { - return Err(BdevDescError::LbaUnlock { - source: nix::errno::from_i32(rc), - bdev_name: self.bdev().name().to_owned(), - }); - } - } - - // Wait for the unlock to complete - let rc = r.await.unwrap(); - if rc != 0 { - return Err(BdevDescError::LbaUnlock { - source: nix::errno::from_i32(rc), - bdev_name: self.bdev().name().to_owned(), - }); - } - - Ok(()) - } - /// Returns a pointer to the underlying `spdk_bdev_desc` structure. pub(crate) fn as_ptr(&self) -> *mut spdk_bdev_desc { self.inner @@ -375,3 +293,112 @@ impl LockContext { pub struct LbaRangeLock { ctx: Box>, } + +/// Allows gaining exclusive access over a block range. +/// # Warning +/// Due to the lack of async drop the range lock must be +/// explicitly released. +#[async_trait::async_trait(?Send)] +pub trait LbaRangeLocker { + type RangeLock; + + /// Gains exclusive access over a block range, and returns + /// a lock object that must be used to unlock the range. + async fn lock_lba_range( + &self, + range: LbaRange, + ) -> Result; + + /// Releases exclusive access over a block range. + async fn unlock_lba_range( + &self, + mut lock: Self::RangeLock, + ) -> Result<(), BdevDescError>; +} + +#[async_trait::async_trait(?Send)] +impl LbaRangeLocker for BdevDesc { + type RangeLock = LbaRangeLock; + + /// Gains exclusive access over a block range, and returns + /// a lock object that must be used to unlock the range. + async fn lock_lba_range( + &self, + range: LbaRange, + ) -> Result, BdevDescError> { + let (s, r) = oneshot::channel::(); + + let ctx = Box::new(LockContext { + range, + ch: self.io_channel()?, + sender: Some(s), + }); + + unsafe { + let rc = bdev_lock_lba_range( + self.as_ptr(), + ctx.ch.legacy_as_ptr(), + ctx.range.offset, + ctx.range.len, + Some(LockContext::::lba_op_completion_cb), + ctx.as_ref() as *const _ as *mut c_void, + ); + if rc != 0 { + return Err(BdevDescError::LbaLock { + source: nix::errno::from_i32(rc), + bdev_name: self.bdev().name().to_owned(), + }); + } + } + + // Wait for the lock to complete + let rc = r.await.unwrap(); + if rc != 0 { + return Err(BdevDescError::LbaLock { + source: nix::errno::from_i32(rc), + bdev_name: self.bdev().name().to_owned(), + }); + } + + Ok(LbaRangeLock { + ctx, + }) + } + + /// Releases exclusive access over a block range. + async fn unlock_lba_range( + &self, + mut lock: LbaRangeLock, + ) -> Result<(), BdevDescError> { + let (s, r) = oneshot::channel::(); + lock.ctx.sender = Some(s); + + unsafe { + let rc = bdev_unlock_lba_range( + self.as_ptr(), + lock.ctx.ch.legacy_as_ptr(), + lock.ctx.range.offset, + lock.ctx.range.len, + Some(LockContext::::lba_op_completion_cb), + lock.ctx.as_ref() as *const _ as *mut c_void, + ); + if rc != 0 { + return Err(BdevDescError::LbaUnlock { + source: nix::errno::from_i32(rc), + bdev_name: self.bdev().name().to_owned(), + }); + } + } + + // Wait for the unlock to complete + let rc = r.await.unwrap(); + if rc != 0 { + return Err(BdevDescError::LbaUnlock { + source: nix::errno::from_i32(rc), + bdev_name: self.bdev().name().to_owned(), + }); + } + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 95836ce..322a0a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,14 @@ pub use crate::{ bdev::Bdev, bdev_async::{BdevAsyncCallContext, BdevStats}, bdev_builder::BdevBuilder, - bdev_desc::{BdevDesc, BdevDescError, BdevEvent, LbaRange, LbaRangeLock}, + bdev_desc::{ + BdevDesc, + BdevDescError, + BdevEvent, + LbaRange, + LbaRangeLock, + LbaRangeLocker, + }, bdev_io::BdevIo, bdev_iter::{BdevGlobalIter, BdevModuleIter}, bdev_module::{