1use std::ffi::c_void;
15
16use libnvme_sys::{
17 nvme_resv_acquire, nvme_resv_acquire_args, nvme_resv_register, nvme_resv_register_args,
18 nvme_resv_release, nvme_resv_release_args, nvme_resv_report, nvme_resv_report_args,
19};
20
21use crate::error::{check_ret, Error, Result};
22use crate::namespace::Namespace;
23
24pub use libnvme_sys::nvme_resv_status;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43#[non_exhaustive]
44#[repr(u8)]
45pub enum ReservationType {
46 WriteExclusive = 1,
48 ExclusiveAccess = 2,
50 WriteExclusiveRegistrantsOnly = 3,
52 ExclusiveAccessRegistrantsOnly = 4,
54 WriteExclusiveAllRegistrants = 5,
56 ExclusiveAccessAllRegistrants = 6,
58}
59
60impl ReservationType {
61 fn as_raw(self) -> u32 {
62 self as u8 as u32
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
68#[non_exhaustive]
69#[repr(u8)]
70pub enum ReservationAcquireAction {
71 #[default]
73 Acquire = 0,
74 Preempt = 1,
76 PreemptAndAbort = 2,
78}
79
80impl ReservationAcquireAction {
81 fn as_raw(self) -> u32 {
82 self as u8 as u32
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
88#[non_exhaustive]
89#[repr(u8)]
90pub enum ReservationRegisterAction {
91 #[default]
93 Register = 0,
94 Unregister = 1,
96 Replace = 2,
98}
99
100impl ReservationRegisterAction {
101 fn as_raw(self) -> u32 {
102 self as u8 as u32
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
108#[non_exhaustive]
109#[repr(u8)]
110pub enum ReservationReleaseAction {
111 #[default]
113 Release = 0,
114 Clear = 1,
116}
117
118impl ReservationReleaseAction {
119 fn as_raw(self) -> u32 {
120 self as u8 as u32
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
126#[non_exhaustive]
127#[repr(u8)]
128pub enum PtplChange {
129 #[default]
131 NoChange = 0,
132 Clear = 2,
134 Persist = 3,
136}
137
138impl PtplChange {
139 fn as_raw(self) -> u32 {
140 self as u8 as u32
141 }
142}
143
144#[must_use = "this builder does nothing until `.execute()` is called"]
150pub struct ReservationAcquire<'a, 'r> {
151 ns: &'a Namespace<'r>,
152 crkey: u64,
153 nrkey: u64,
154 rtype: ReservationType,
155 action: ReservationAcquireAction,
156 iekey: bool,
157 timeout_ms: u32,
158}
159
160impl<'a, 'r> ReservationAcquire<'a, 'r> {
161 pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
162 ReservationAcquire {
163 ns,
164 crkey: 0,
165 nrkey: 0,
166 rtype: ReservationType::WriteExclusive,
167 action: ReservationAcquireAction::default(),
168 iekey: false,
169 timeout_ms: 0,
170 }
171 }
172
173 pub fn key(mut self, crkey: u64) -> Self {
175 self.crkey = crkey;
176 self
177 }
178
179 pub fn new_key(mut self, nrkey: u64) -> Self {
182 self.nrkey = nrkey;
183 self
184 }
185
186 pub fn rtype(mut self, rtype: ReservationType) -> Self {
188 self.rtype = rtype;
189 self
190 }
191
192 pub fn action(mut self, action: ReservationAcquireAction) -> Self {
194 self.action = action;
195 self
196 }
197
198 pub fn ignore_existing_key(mut self) -> Self {
200 self.iekey = true;
201 self
202 }
203
204 pub fn timeout_ms(mut self, ms: u32) -> Self {
206 self.timeout_ms = ms;
207 self
208 }
209
210 pub fn execute(self) -> Result<u32> {
212 let fd = ns_fd(self.ns)?;
213 let mut result: u32 = 0;
214 let mut args = nvme_resv_acquire_args {
215 crkey: self.crkey,
216 nrkey: self.nrkey,
217 result: &mut result,
218 args_size: std::mem::size_of::<nvme_resv_acquire_args>() as i32,
219 fd,
220 timeout: self.timeout_ms,
221 nsid: self.ns.nsid(),
222 rtype: self.rtype.as_raw(),
223 racqa: self.action.as_raw(),
224 iekey: self.iekey,
225 };
226 let ret = unsafe { nvme_resv_acquire(&mut args) };
229 check_ret(ret)?;
230 Ok(result)
231 }
232}
233
234#[must_use = "this builder does nothing until `.execute()` is called"]
240pub struct ReservationRegister<'a, 'r> {
241 ns: &'a Namespace<'r>,
242 crkey: u64,
243 nrkey: u64,
244 action: ReservationRegisterAction,
245 cptpl: PtplChange,
246 iekey: bool,
247 timeout_ms: u32,
248}
249
250impl<'a, 'r> ReservationRegister<'a, 'r> {
251 pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
252 ReservationRegister {
253 ns,
254 crkey: 0,
255 nrkey: 0,
256 action: ReservationRegisterAction::default(),
257 cptpl: PtplChange::default(),
258 iekey: false,
259 timeout_ms: 0,
260 }
261 }
262
263 pub fn key(mut self, crkey: u64) -> Self {
266 self.crkey = crkey;
267 self
268 }
269
270 pub fn new_key(mut self, nrkey: u64) -> Self {
272 self.nrkey = nrkey;
273 self
274 }
275
276 pub fn action(mut self, action: ReservationRegisterAction) -> Self {
278 self.action = action;
279 self
280 }
281
282 pub fn ptpl(mut self, cptpl: PtplChange) -> Self {
284 self.cptpl = cptpl;
285 self
286 }
287
288 pub fn ignore_existing_key(mut self) -> Self {
290 self.iekey = true;
291 self
292 }
293
294 pub fn timeout_ms(mut self, ms: u32) -> Self {
296 self.timeout_ms = ms;
297 self
298 }
299
300 pub fn execute(self) -> Result<u32> {
302 let fd = ns_fd(self.ns)?;
303 let mut result: u32 = 0;
304 let mut args = nvme_resv_register_args {
305 crkey: self.crkey,
306 nrkey: self.nrkey,
307 result: &mut result,
308 args_size: std::mem::size_of::<nvme_resv_register_args>() as i32,
309 fd,
310 timeout: self.timeout_ms,
311 nsid: self.ns.nsid(),
312 rrega: self.action.as_raw(),
313 cptpl: self.cptpl.as_raw(),
314 iekey: self.iekey,
315 };
316 let ret = unsafe { nvme_resv_register(&mut args) };
318 check_ret(ret)?;
319 Ok(result)
320 }
321}
322
323#[must_use = "this builder does nothing until `.execute()` is called"]
329pub struct ReservationRelease<'a, 'r> {
330 ns: &'a Namespace<'r>,
331 crkey: u64,
332 rtype: ReservationType,
333 action: ReservationReleaseAction,
334 iekey: bool,
335 timeout_ms: u32,
336}
337
338impl<'a, 'r> ReservationRelease<'a, 'r> {
339 pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
340 ReservationRelease {
341 ns,
342 crkey: 0,
343 rtype: ReservationType::WriteExclusive,
344 action: ReservationReleaseAction::default(),
345 iekey: false,
346 timeout_ms: 0,
347 }
348 }
349
350 pub fn key(mut self, crkey: u64) -> Self {
352 self.crkey = crkey;
353 self
354 }
355
356 pub fn rtype(mut self, rtype: ReservationType) -> Self {
358 self.rtype = rtype;
359 self
360 }
361
362 pub fn action(mut self, action: ReservationReleaseAction) -> Self {
364 self.action = action;
365 self
366 }
367
368 pub fn ignore_existing_key(mut self) -> Self {
370 self.iekey = true;
371 self
372 }
373
374 pub fn timeout_ms(mut self, ms: u32) -> Self {
376 self.timeout_ms = ms;
377 self
378 }
379
380 pub fn execute(self) -> Result<u32> {
382 let fd = ns_fd(self.ns)?;
383 let mut result: u32 = 0;
384 let mut args = nvme_resv_release_args {
385 crkey: self.crkey,
386 result: &mut result,
387 args_size: std::mem::size_of::<nvme_resv_release_args>() as i32,
388 fd,
389 timeout: self.timeout_ms,
390 nsid: self.ns.nsid(),
391 rtype: self.rtype.as_raw(),
392 rrela: self.action.as_raw(),
393 iekey: self.iekey,
394 };
395 let ret = unsafe { nvme_resv_release(&mut args) };
397 check_ret(ret)?;
398 Ok(result)
399 }
400}
401
402#[must_use = "this builder does nothing until `.execute()` is called"]
414pub struct ReservationReport<'a, 'r> {
415 ns: &'a Namespace<'r>,
416 buf: Option<&'a mut [u8]>,
417 eds: bool,
418 timeout_ms: u32,
419}
420
421impl<'a, 'r> ReservationReport<'a, 'r> {
422 pub(crate) fn new(ns: &'a Namespace<'r>) -> Self {
423 ReservationReport {
424 ns,
425 buf: None,
426 eds: false,
427 timeout_ms: 0,
428 }
429 }
430
431 pub fn buffer(mut self, buf: &'a mut [u8]) -> Self {
436 self.buf = Some(buf);
437 self
438 }
439
440 pub fn extended(mut self) -> Self {
443 self.eds = true;
444 self
445 }
446
447 pub fn timeout_ms(mut self, ms: u32) -> Self {
449 self.timeout_ms = ms;
450 self
451 }
452
453 pub fn execute(self) -> Result<u32> {
455 let buf = self.buf.ok_or(Error::invalid_argument(
456 "ReservationReport requires a buffer via .buffer()",
457 ))?;
458 if buf.len() < std::mem::size_of::<nvme_resv_status>() {
459 return Err(Error::invalid_argument(
460 "ReservationReport buffer smaller than nvme_resv_status header",
461 ));
462 }
463 let fd = ns_fd(self.ns)?;
464 let mut result: u32 = 0;
465 let mut args = nvme_resv_report_args {
466 result: &mut result,
467 report: buf.as_mut_ptr() as *mut nvme_resv_status,
468 args_size: std::mem::size_of::<nvme_resv_report_args>() as i32,
469 fd,
470 timeout: self.timeout_ms,
471 nsid: self.ns.nsid(),
472 len: buf.len() as u32,
473 eds: self.eds,
474 };
475 let ret = unsafe { nvme_resv_report(&mut args) };
478 check_ret(ret)?;
479 Ok(result)
480 }
481
482 pub fn execute_to_vec(self) -> Result<Vec<u8>> {
486 let eds = self.eds;
487 let timeout_ms = self.timeout_ms;
488 let ns = self.ns;
489 let mut buf = vec![0u8; 4096];
490 ReservationReport {
491 ns,
492 buf: Some(&mut buf),
493 eds,
494 timeout_ms,
495 }
496 .execute()?;
497 Ok(buf)
498 }
499}
500
501fn ns_fd(ns: &Namespace<'_>) -> Result<std::os::raw::c_int> {
506 let fd = unsafe { libnvme_sys::nvme_ns_get_fd(ns.raw_handle()) };
509 if fd < 0 {
510 return Err(Error::Os(std::io::Error::last_os_error()));
511 }
512 Ok(fd)
513}
514
515#[allow(dead_code)]
518const _C_VOID_HINT: Option<*const c_void> = None;