use std::ffi::c_void;
use libnvme_sys::{
nvme_resv_acquire, nvme_resv_acquire_args, nvme_resv_register, nvme_resv_register_args,
nvme_resv_release, nvme_resv_release_args, nvme_resv_report, nvme_resv_report_args,
};
use crate::error::{check_ret, Error, Result};
use crate::namespace::Namespace;
pub use libnvme_sys::nvme_resv_status;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
#[repr(u8)]
pub enum ReservationType {
WriteExclusive = 1,
ExclusiveAccess = 2,
WriteExclusiveRegistrantsOnly = 3,
ExclusiveAccessRegistrantsOnly = 4,
WriteExclusiveAllRegistrants = 5,
ExclusiveAccessAllRegistrants = 6,
}
impl ReservationType {
fn as_raw(self) -> u32 {
self as u8 as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
#[repr(u8)]
pub enum ReservationAcquireAction {
#[default]
Acquire = 0,
Preempt = 1,
PreemptAndAbort = 2,
}
impl ReservationAcquireAction {
fn as_raw(self) -> u32 {
self as u8 as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
#[repr(u8)]
pub enum ReservationRegisterAction {
#[default]
Register = 0,
Unregister = 1,
Replace = 2,
}
impl ReservationRegisterAction {
fn as_raw(self) -> u32 {
self as u8 as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
#[repr(u8)]
pub enum ReservationReleaseAction {
#[default]
Release = 0,
Clear = 1,
}
impl ReservationReleaseAction {
fn as_raw(self) -> u32 {
self as u8 as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
#[repr(u8)]
pub enum PtplChange {
#[default]
NoChange = 0,
Clear = 2,
Persist = 3,
}
impl PtplChange {
fn as_raw(self) -> u32 {
self as u8 as u32
}
}
#[must_use = "this builder does nothing until `.execute()` is called"]
pub struct ReservationAcquire<'a, 'r> {
ns: &'a Namespace<'r>,
crkey: u64,
nrkey: u64,
rtype: ReservationType,
action: ReservationAcquireAction,
iekey: bool,
timeout_ms: u32,
}
impl<'a, 'r> ReservationAcquire<'a, 'r> {
pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
ReservationAcquire {
ns,
crkey: 0,
nrkey: 0,
rtype: ReservationType::WriteExclusive,
action: ReservationAcquireAction::default(),
iekey: false,
timeout_ms: 0,
}
}
pub fn key(mut self, crkey: u64) -> Self {
self.crkey = crkey;
self
}
pub fn new_key(mut self, nrkey: u64) -> Self {
self.nrkey = nrkey;
self
}
pub fn rtype(mut self, rtype: ReservationType) -> Self {
self.rtype = rtype;
self
}
pub fn action(mut self, action: ReservationAcquireAction) -> Self {
self.action = action;
self
}
pub fn ignore_existing_key(mut self) -> Self {
self.iekey = true;
self
}
pub fn timeout_ms(mut self, ms: u32) -> Self {
self.timeout_ms = ms;
self
}
pub fn execute(self) -> Result<u32> {
let fd = ns_fd(self.ns)?;
let mut result: u32 = 0;
let mut args = nvme_resv_acquire_args {
crkey: self.crkey,
nrkey: self.nrkey,
result: &mut result,
args_size: std::mem::size_of::<nvme_resv_acquire_args>() as i32,
fd,
timeout: self.timeout_ms,
nsid: self.ns.nsid(),
rtype: self.rtype.as_raw(),
racqa: self.action.as_raw(),
iekey: self.iekey,
};
let ret = unsafe { nvme_resv_acquire(&mut args) };
check_ret(ret)?;
Ok(result)
}
}
#[must_use = "this builder does nothing until `.execute()` is called"]
pub struct ReservationRegister<'a, 'r> {
ns: &'a Namespace<'r>,
crkey: u64,
nrkey: u64,
action: ReservationRegisterAction,
cptpl: PtplChange,
iekey: bool,
timeout_ms: u32,
}
impl<'a, 'r> ReservationRegister<'a, 'r> {
pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
ReservationRegister {
ns,
crkey: 0,
nrkey: 0,
action: ReservationRegisterAction::default(),
cptpl: PtplChange::default(),
iekey: false,
timeout_ms: 0,
}
}
pub fn key(mut self, crkey: u64) -> Self {
self.crkey = crkey;
self
}
pub fn new_key(mut self, nrkey: u64) -> Self {
self.nrkey = nrkey;
self
}
pub fn action(mut self, action: ReservationRegisterAction) -> Self {
self.action = action;
self
}
pub fn ptpl(mut self, cptpl: PtplChange) -> Self {
self.cptpl = cptpl;
self
}
pub fn ignore_existing_key(mut self) -> Self {
self.iekey = true;
self
}
pub fn timeout_ms(mut self, ms: u32) -> Self {
self.timeout_ms = ms;
self
}
pub fn execute(self) -> Result<u32> {
let fd = ns_fd(self.ns)?;
let mut result: u32 = 0;
let mut args = nvme_resv_register_args {
crkey: self.crkey,
nrkey: self.nrkey,
result: &mut result,
args_size: std::mem::size_of::<nvme_resv_register_args>() as i32,
fd,
timeout: self.timeout_ms,
nsid: self.ns.nsid(),
rrega: self.action.as_raw(),
cptpl: self.cptpl.as_raw(),
iekey: self.iekey,
};
let ret = unsafe { nvme_resv_register(&mut args) };
check_ret(ret)?;
Ok(result)
}
}
#[must_use = "this builder does nothing until `.execute()` is called"]
pub struct ReservationRelease<'a, 'r> {
ns: &'a Namespace<'r>,
crkey: u64,
rtype: ReservationType,
action: ReservationReleaseAction,
iekey: bool,
timeout_ms: u32,
}
impl<'a, 'r> ReservationRelease<'a, 'r> {
pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
ReservationRelease {
ns,
crkey: 0,
rtype: ReservationType::WriteExclusive,
action: ReservationReleaseAction::default(),
iekey: false,
timeout_ms: 0,
}
}
pub fn key(mut self, crkey: u64) -> Self {
self.crkey = crkey;
self
}
pub fn rtype(mut self, rtype: ReservationType) -> Self {
self.rtype = rtype;
self
}
pub fn action(mut self, action: ReservationReleaseAction) -> Self {
self.action = action;
self
}
pub fn ignore_existing_key(mut self) -> Self {
self.iekey = true;
self
}
pub fn timeout_ms(mut self, ms: u32) -> Self {
self.timeout_ms = ms;
self
}
pub fn execute(self) -> Result<u32> {
let fd = ns_fd(self.ns)?;
let mut result: u32 = 0;
let mut args = nvme_resv_release_args {
crkey: self.crkey,
result: &mut result,
args_size: std::mem::size_of::<nvme_resv_release_args>() as i32,
fd,
timeout: self.timeout_ms,
nsid: self.ns.nsid(),
rtype: self.rtype.as_raw(),
rrela: self.action.as_raw(),
iekey: self.iekey,
};
let ret = unsafe { nvme_resv_release(&mut args) };
check_ret(ret)?;
Ok(result)
}
}
#[must_use = "this builder does nothing until `.execute()` is called"]
pub struct ReservationReport<'a, 'r> {
ns: &'a Namespace<'r>,
buf: Option<&'a mut [u8]>,
eds: bool,
timeout_ms: u32,
}
impl<'a, 'r> ReservationReport<'a, 'r> {
pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
ReservationReport {
ns,
buf: None,
eds: false,
timeout_ms: 0,
}
}
pub fn buffer(mut self, buf: &'a mut [u8]) -> Self {
self.buf = Some(buf);
self
}
pub fn extended(mut self) -> Self {
self.eds = true;
self
}
pub fn timeout_ms(mut self, ms: u32) -> Self {
self.timeout_ms = ms;
self
}
pub fn execute(self) -> Result<u32> {
let buf = self.buf.ok_or(Error::invalid_argument(
"ReservationReport requires a buffer via .buffer()",
))?;
if buf.len() < std::mem::size_of::<nvme_resv_status>() {
return Err(Error::invalid_argument(
"ReservationReport buffer smaller than nvme_resv_status header",
));
}
let fd = ns_fd(self.ns)?;
let mut result: u32 = 0;
let mut args = nvme_resv_report_args {
result: &mut result,
report: buf.as_mut_ptr() as *mut nvme_resv_status,
args_size: std::mem::size_of::<nvme_resv_report_args>() as i32,
fd,
timeout: self.timeout_ms,
nsid: self.ns.nsid(),
len: buf.len() as u32,
eds: self.eds,
};
let ret = unsafe { nvme_resv_report(&mut args) };
check_ret(ret)?;
Ok(result)
}
pub fn execute_to_vec(self) -> Result<Vec<u8>> {
let eds = self.eds;
let timeout_ms = self.timeout_ms;
let ns = self.ns;
let mut buf = vec![0u8; 4096];
ReservationReport {
ns,
buf: Some(&mut buf),
eds,
timeout_ms,
}
.execute()?;
Ok(buf)
}
}
fn ns_fd(ns: &Namespace<'_>) -> Result<std::os::raw::c_int> {
let fd = unsafe { libnvme_sys::nvme_ns_get_fd(ns.raw_handle()) };
if fd < 0 {
return Err(Error::Os(std::io::Error::last_os_error()));
}
Ok(fd)
}
#[allow(dead_code)]
const _C_VOID_HINT: Option<*const c_void> = None;