nvme_common/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Common routines for interoperating between [`nvme_spec`] and
5//! [`disk_backend`] types.
6
7#![forbid(unsafe_code)]
8
9use disk_backend::pr;
10use nvme_spec::nvm;
11use thiserror::Error;
12
13/// Converts a `disk_backend` reservation type to an NVMe reservation type.
14pub fn to_nvme_reservation_type(reservation_type: pr::ReservationType) -> nvm::ReservationType {
15    match reservation_type {
16        pr::ReservationType::WriteExclusive => nvm::ReservationType::WRITE_EXCLUSIVE,
17        pr::ReservationType::ExclusiveAccess => nvm::ReservationType::EXCLUSIVE_ACCESS,
18        pr::ReservationType::WriteExclusiveRegistrantsOnly => {
19            nvm::ReservationType::WRITE_EXCLUSIVE_REGISTRANTS_ONLY
20        }
21        pr::ReservationType::ExclusiveAccessRegistrantsOnly => {
22            nvm::ReservationType::EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
23        }
24        pr::ReservationType::WriteExclusiveAllRegistrants => {
25            nvm::ReservationType::WRITE_EXCLUSIVE_ALL_REGISTRANTS
26        }
27        pr::ReservationType::ExclusiveAccessAllRegistrants => {
28            nvm::ReservationType::EXCLUSIVE_ACCESS_ALL_REGISTRANTS
29        }
30    }
31}
32
33/// Error returned by [`from_nvme_reservation_type`].
34#[derive(Debug, Error)]
35#[error("invalid nvme reservation type: {0:#x?}")]
36pub struct InvalidReservationType(nvm::ReservationType);
37
38/// Converts a `disk_backend` reservation type from an NVMe reservation type.
39pub fn from_nvme_reservation_type(
40    nvme_type: nvm::ReservationType,
41) -> Result<pr::ReservationType, InvalidReservationType> {
42    let reservation_type = match nvme_type {
43        nvm::ReservationType::WRITE_EXCLUSIVE => pr::ReservationType::WriteExclusive,
44        nvm::ReservationType::EXCLUSIVE_ACCESS => pr::ReservationType::ExclusiveAccess,
45        nvm::ReservationType::WRITE_EXCLUSIVE_REGISTRANTS_ONLY => {
46            pr::ReservationType::WriteExclusiveRegistrantsOnly
47        }
48        nvm::ReservationType::EXCLUSIVE_ACCESS_REGISTRANTS_ONLY => {
49            pr::ReservationType::ExclusiveAccessRegistrantsOnly
50        }
51        nvm::ReservationType::WRITE_EXCLUSIVE_ALL_REGISTRANTS => {
52            pr::ReservationType::WriteExclusiveAllRegistrants
53        }
54        nvm::ReservationType::EXCLUSIVE_ACCESS_ALL_REGISTRANTS => {
55            pr::ReservationType::ExclusiveAccessAllRegistrants
56        }
57        _ => return Err(InvalidReservationType(nvme_type)),
58    };
59    Ok(reservation_type)
60}
61
62/// Builds `disk_backend` reservation capabilities from NVMe reservation capabilities.
63pub fn from_nvme_reservation_capabilities(
64    rescap: nvm::ReservationCapabilities,
65) -> pr::ReservationCapabilities {
66    pr::ReservationCapabilities {
67        write_exclusive: rescap.write_exclusive(),
68        exclusive_access: rescap.exclusive_access(),
69        write_exclusive_registrants_only: rescap.write_exclusive_registrants_only(),
70        exclusive_access_registrants_only: rescap.exclusive_access_registrants_only(),
71        write_exclusive_all_registrants: rescap.write_exclusive_all_registrants(),
72        exclusive_access_all_registrants: rescap.exclusive_access_all_registrants(),
73        persist_through_power_loss: rescap.persist_through_power_loss(),
74    }
75}
76
77/// Parses an NVMe reservation report into a `disk_backend` reservation report.
78pub fn from_nvme_reservation_report(
79    report_header: &nvm::ReservationReport,
80    controllers: &[nvm::RegisteredControllerExtended],
81) -> Result<pr::ReservationReport, InvalidReservationType> {
82    let reservation_type = if report_header.rtype.0 != 0 {
83        Some(from_nvme_reservation_type(report_header.rtype)?)
84    } else {
85        None
86    };
87
88    let controllers = controllers
89        .iter()
90        .map(|controller| pr::RegisteredController {
91            key: controller.rkey,
92            holds_reservation: controller.rcsts.holds_reservation(),
93            controller_id: controller.cntlid,
94            host_id: controller.hostid.to_vec(),
95        })
96        .collect();
97
98    let report = pr::ReservationReport {
99        generation: report_header.generation,
100        reservation_type,
101        controllers,
102        persist_through_power_loss: report_header.ptpls != 0,
103    };
104
105    Ok(report)
106}