Skip to content

Commit

Permalink
refactor(bdev/lock): add range lock trait
Browse files Browse the repository at this point in the history
Signed-off-by: Tiago Castro <[email protected]>
  • Loading branch information
tiagolobocastro committed Jan 12, 2024
1 parent a1efae6 commit dfbc4e0
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 83 deletions.
191 changes: 109 additions & 82 deletions src/bdev_desc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<LbaRangeLock<BdevData>, BdevDescError> {
let (s, r) = oneshot::channel::<i32>();

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::<BdevData>::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<BdevData>,
) -> Result<(), BdevDescError> {
let (s, r) = oneshot::channel::<i32>();
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::<BdevData>::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
Expand Down Expand Up @@ -375,3 +293,112 @@ impl<T: BdevOps> LockContext<T> {
pub struct LbaRangeLock<T: BdevOps> {
ctx: Box<LockContext<T>>,
}

/// 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<Self::RangeLock, BdevDescError>;

/// 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<BdevData: BdevOps> LbaRangeLocker for BdevDesc<BdevData> {
type RangeLock = LbaRangeLock<BdevData>;

/// Releases exclusive access over a block range.
async fn unlock_lba_range(
&self,
mut lock: LbaRangeLock<BdevData>,
) -> Result<(), BdevDescError> {
let (s, r) = oneshot::channel::<i32>();
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::<BdevData>::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(())
}

/// 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<LbaRangeLock<BdevData>, BdevDescError> {
let (s, r) = oneshot::channel::<i32>();

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::<BdevData>::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,
})
}
}
9 changes: 8 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down

0 comments on commit dfbc4e0

Please sign in to comment.