disk_backend/
pr.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Persistent reservation support.
5
6use crate::DiskError;
7use inspect::Inspect;
8
9/// Trait implemented by disks that support SCSI-style persistent reservations.
10#[async_trait::async_trait]
11pub trait PersistentReservation: Sync {
12    /// Returns the disk's capabilities.
13    fn capabilities(&self) -> ReservationCapabilities;
14
15    /// Returns a report of the current registration and reservation state.
16    async fn report(&self) -> Result<ReservationReport, DiskError>;
17
18    /// Updates the registration for this client.
19    ///
20    /// If the current key does not match `old_key`, then fails with
21    /// [`DiskError::ReservationConflict`]. If `old_key` is `None`, then update
22    /// the registration regardless.
23    ///
24    /// If `new_key` is 0, then remove the registration.
25    ///
26    /// `ptpl` provides an optional new state for "persist through power loss".
27    async fn register(
28        &self,
29        current_key: Option<u64>,
30        new_key: u64,
31        ptpl: Option<bool>,
32    ) -> Result<(), DiskError>;
33
34    /// Creates a reservation for this client with type `reservation_type`.
35    ///
36    /// Fails with [`DiskError::ReservationConflict`] if there is a key mismatch.
37    async fn reserve(&self, key: u64, reservation_type: ReservationType) -> Result<(), DiskError>;
38
39    /// Releases the reservation for this client with type `reservation_type`.
40    ///
41    /// Fails with [`DiskError::ReservationConflict`] if there is a key or type
42    /// mismatch.
43    async fn release(&self, key: u64, reservation_type: ReservationType) -> Result<(), DiskError>;
44
45    /// Clears any reservation and registration for this client.
46    ///
47    /// Fails with [`DiskError::ReservationConflict`] if there is a key mismatch.
48    async fn clear(&self, key: u64) -> Result<(), DiskError>;
49
50    /// Preempts an existing reservation. See the SCSI spec for the precise
51    /// behavior of this.
52    async fn preempt(
53        &self,
54        current_key: u64,
55        preempt_key: u64,
56        reservation_type: ReservationType,
57        abort: bool,
58    ) -> Result<(), DiskError>;
59}
60
61/// Capabilities returned by [`PersistentReservation::capabilities`].
62///
63/// These bits correspond to values in [`ReservationType`].
64#[expect(missing_docs)] // TODO
65pub struct ReservationCapabilities {
66    pub write_exclusive: bool,
67    pub exclusive_access: bool,
68    pub write_exclusive_registrants_only: bool,
69    pub exclusive_access_registrants_only: bool,
70    pub write_exclusive_all_registrants: bool,
71    pub exclusive_access_all_registrants: bool,
72    pub persist_through_power_loss: bool,
73}
74
75/// The reservation type.
76///
77/// These are defined in the SCSI spec.
78#[derive(Debug, Copy, Clone, PartialEq, Eq, Inspect)]
79#[expect(missing_docs)] // TODO
80pub enum ReservationType {
81    WriteExclusive,
82    ExclusiveAccess,
83    WriteExclusiveRegistrantsOnly,
84    ExclusiveAccessRegistrantsOnly,
85    WriteExclusiveAllRegistrants,
86    ExclusiveAccessAllRegistrants,
87}
88
89/// A registered controller.
90#[derive(Debug, Clone)]
91pub struct RegisteredController {
92    /// The registration key.
93    pub key: u64,
94    /// The host ID of the client.
95    pub host_id: Vec<u8>,
96    /// The controller ID within the host.
97    pub controller_id: u16,
98    /// If true, the controller holds the reservation.
99    pub holds_reservation: bool,
100}
101
102/// The report returned by [`PersistentReservation::report`].
103#[derive(Debug, Clone)]
104pub struct ReservationReport {
105    /// A counter that increases every time a registration changes.
106    pub generation: u32,
107    /// The current reservation type for the disk.
108    pub reservation_type: Option<ReservationType>,
109    /// The persist through power loss state.
110    pub persist_through_power_loss: bool,
111    /// The registered controllers.
112    pub controllers: Vec<RegisteredController>,
113}