Skip to main content

disk_layered/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! A layered disk implementation, [`LayeredDisk`].
5//!
6//! A layered disk is a disk composed of multiple layers. Each layer is a block
7//! device made up of sectors, but with the added per-sector state of whether
8//! the sector is present or not. When reading a sector, the layered disk will
9//! read from the topmost layer that has the sector present. When writing, the
10//! disk will write to the topmost layer.
11//!
12//! A layer can also have caching behavior. If a layer is configured to cache
13//! reads, then sectors that are read from lower layers are written back to the
14//! layer. If a layer is configured to write through, then writes are written to
15//! the layer and the next layer. These can be useful to implement simple
16//! persistent and non-persistent caches, primarily designed for lazily
17//! populating local backing stores from remote sources.
18//!
19//! Missing from this implementation is write-back caching and cache eviction,
20//! which would be needed for caches that are smaller than the disk. These
21//! require potentially complicated cache management policies and are probably
22//! best implemented in a separate disk implementation.
23//!
24//! # Layer types
25//!
26//! Each layer implements [`LayerIo`], which is similar to [`DiskIo`]
27//! but adds per-sector presence tracking via [`SectorMarker`]. Two concrete
28//! layer implementations exist:
29//!
30//! - **`RamDiskLayer`** (`disklayer_ram`) — ephemeral, in-memory.
31//! - **`SqliteDiskLayer`** (`disklayer_sqlite`) — persistent, file-backed
32//!   (dev/test only).
33//!
34//! A full [`Disk`] can appear at the bottom of the stack
35//! as a fully-present layer via `DiskLayer::from_disk`, which wraps it in
36//! `DiskAsLayer` — a layer that marks all sectors as present on every read.
37//!
38//! # Construction and validation
39//!
40//! [`LayeredDisk::new`] validates the layer stack at construction time:
41//!
42//! - All layers must have matching sector sizes.
43//! - Write-through layers must be contiguous from the top.
44//! - The last layer must not be write-through.
45//! - Layers used as read caches must support [`WriteNoOverwrite`].
46//! - If the disk is writable, all layers in the write path must be writable.
47
48#![forbid(unsafe_code)]
49
50mod bitmap;
51pub mod resolve;
52pub mod resolver;
53
54pub use bitmap::SectorMarker;
55
56use bitmap::Bitmap;
57use disk_backend::Disk;
58use disk_backend::DiskError;
59use disk_backend::DiskIo;
60use disk_backend::UnmapBehavior;
61use guestmem::GuestMemory;
62use guestmem::MemoryWrite;
63use inspect::Inspect;
64use scsi_buffers::OwnedRequestBuffers;
65use scsi_buffers::RequestBuffers;
66use std::convert::Infallible;
67use std::future::Future;
68use std::pin::Pin;
69use thiserror::Error;
70
71/// A disk composed of multiple layers.
72#[derive(Inspect)]
73pub struct LayeredDisk {
74    #[inspect(iter_by_index)]
75    layers: Vec<Layer>,
76    read_only: bool,
77    is_fua_respected: bool,
78    sector_shift: u32,
79    disk_id: Option<[u8; 16]>,
80    physical_sector_size: u32,
81    unmap_behavior: UnmapBehavior,
82    optimal_unmap_sectors: u32,
83}
84
85#[derive(Inspect)]
86struct Layer {
87    backing: Box<dyn DynLayerIo>,
88    visible_sector_count: u64,
89    read_cache: bool,
90    write_through: bool,
91}
92
93/// A single layer which can be attached to a [`LayeredDisk`].
94pub struct DiskLayer(Box<dyn DynLayerAttach>);
95
96impl DiskLayer {
97    /// Creates a new layer from a backing store.
98    pub fn new<T: LayerAttach>(backing: T) -> Self {
99        Self(Box::new(backing))
100    }
101
102    /// Creates a layer from a disk. The resulting layer is always fully
103    /// present.
104    pub fn from_disk(disk: Disk) -> Self {
105        Self::new(DiskAsLayer(disk))
106    }
107}
108
109/// Metadata of a particular layer, collected from various [`LayerIo`] APIs.
110#[derive(Clone)]
111#[expect(missing_docs)] // self-explanatory names
112pub struct DiskLayerMetadata {
113    pub disk_id: Option<[u8; 16]>,
114    pub sector_size: u32,
115    pub sector_count: u64,
116    pub physical_sector_size: u32,
117    pub unmap_behavior: UnmapBehavior,
118    pub optimal_unmap_sectors: u32,
119    pub read_only: bool,
120    pub can_read_cache: bool,
121    pub is_fua_respected: bool,
122}
123
124// DEVNOTE: this is a transient object, used solely in LayeredDisk::new.
125struct AttachedDiskLayer {
126    backing: Box<dyn DynLayerIo>,
127    meta: DiskLayerMetadata,
128}
129
130/// An error returned when creating a [`DiskLayer`].
131#[derive(Debug, Error)]
132pub enum InvalidLayer {
133    /// Failed to attach the layer
134    #[error("failed to attach layer")]
135    AttachFailed(#[source] anyhow::Error),
136    /// Read caching was requested but is not supported.
137    #[error("read caching was requested but is not supported")]
138    ReadCacheNotSupported,
139    /// The sector size is invalid.
140    #[error("sector size {0} is invalid")]
141    InvalidSectorSize(u32),
142    /// The sector size of the layers do not match.
143    #[error("mismatched sector size {found}, expected {expected}")]
144    MismatchedSectorSize {
145        /// The expected sector size.
146        expected: u32,
147        /// The sector size found in the layer.
148        found: u32,
149    },
150    /// A write-through layer is preceeded by a layer that is not write-through, or
151    /// the last layer is write-through.
152    #[error("nothing to write through")]
153    UselessWriteThrough,
154    /// Writing to the layered disk would require this layer to be writable.
155    #[error("read only layer in a writable disk")]
156    ReadOnly,
157}
158
159/// An error returned when creating a [`LayeredDisk`].
160#[derive(Debug, Error)]
161pub enum InvalidLayeredDisk {
162    /// No layers were configured.
163    #[error("no layers were configured")]
164    NoLayers,
165    /// An error occurred in a layer.
166    #[error("invalid layer {0}")]
167    Layer(usize, #[source] InvalidLayer),
168}
169
170/// A configuration for a layer in a [`LayeredDisk`].
171pub struct LayerConfiguration<L = DiskLayer> {
172    /// The backing store for the layer.
173    pub layer: L,
174    /// Writes are written both to this layer and the next one.
175    pub write_through: bool,
176    /// Reads that miss this layer are written back to this layer.
177    pub read_cache: bool,
178}
179
180impl LayeredDisk {
181    /// Creates a new layered disk from a list of layers.
182    ///
183    /// The layers must be ordered from top to bottom, with the top layer being
184    /// the first in the list.
185    pub async fn new(
186        read_only: bool,
187        layers: Vec<LayerConfiguration>,
188    ) -> Result<Self, InvalidLayeredDisk> {
189        if layers.is_empty() {
190            return Err(InvalidLayeredDisk::NoLayers);
191        }
192
193        let mut attached_layers: Vec<LayerConfiguration<AttachedDiskLayer>> = {
194            let mut attached_layers = Vec::new();
195
196            // layers are attached to one another from the bottom-up, hence the need
197            // to iterate in reverse.
198            let mut lower_layer_metadata = None;
199            for (
200                i,
201                LayerConfiguration {
202                    layer,
203                    write_through,
204                    read_cache,
205                },
206            ) in layers.into_iter().enumerate().rev()
207            {
208                let layer_error = |e| InvalidLayeredDisk::Layer(i, e);
209
210                let layer = layer
211                    .0
212                    .attach(lower_layer_metadata.take())
213                    .await
214                    .map_err(|e| layer_error(InvalidLayer::AttachFailed(e)))?;
215
216                let layer_meta = layer.meta.clone();
217
218                attached_layers.push(LayerConfiguration {
219                    layer,
220                    write_through,
221                    read_cache,
222                });
223
224                // perform some layer validation prior to attaching subsequent layers
225                if read_cache && !layer_meta.can_read_cache {
226                    return Err(layer_error(InvalidLayer::ReadCacheNotSupported));
227                }
228                if !layer_meta.sector_size.is_power_of_two() {
229                    return Err(layer_error(InvalidLayer::InvalidSectorSize(
230                        layer_meta.sector_size,
231                    )));
232                }
233                if layer_meta.sector_size != attached_layers[0].layer.meta.sector_size {
234                    // FUTURE: consider supporting different sector sizes, within reason.
235                    return Err(layer_error(InvalidLayer::MismatchedSectorSize {
236                        expected: attached_layers[0].layer.meta.sector_size,
237                        found: layer_meta.sector_size,
238                    }));
239                }
240
241                lower_layer_metadata = Some(layer_meta);
242            }
243
244            attached_layers.reverse();
245            attached_layers
246        };
247
248        // perform top-down validation of the layer-stack, collecting various
249        // common properties of the stack along the way.
250        let mut last_write_through = true;
251        let mut is_fua_respected = true;
252        let mut optimal_unmap_sectors = 1;
253        let mut unmap_must_zero = false;
254        let mut disk_id = None;
255        let mut unmap_behavior = UnmapBehavior::Zeroes;
256        for (
257            i,
258            &LayerConfiguration {
259                ref layer,
260                write_through,
261                read_cache: _,
262            },
263        ) in attached_layers.iter().enumerate()
264        {
265            let layer_error = |e| InvalidLayeredDisk::Layer(i, e);
266
267            if last_write_through {
268                if layer.meta.read_only && !read_only {
269                    return Err(layer_error(InvalidLayer::ReadOnly));
270                }
271                is_fua_respected &= layer.meta.is_fua_respected;
272                // Merge the unmap behavior. If any affected layer ignores
273                // unmap, then force the whole disk to. If all affected layers
274                // zero the sectors, then report that the disk zeroes sectors.
275                //
276                // If there is at least one write-through layer, then unmap only
277                // works if the unmap operation will produce the same result in
278                // all the layers that are being written to. Otherwise, the
279                // guest could see inconsistent disk contents when the write
280                // through layer is removed.
281                unmap_must_zero |= write_through;
282                unmap_behavior = match (unmap_behavior, layer.meta.unmap_behavior) {
283                    (UnmapBehavior::Zeroes, UnmapBehavior::Zeroes) => UnmapBehavior::Zeroes,
284                    _ if unmap_must_zero => UnmapBehavior::Ignored,
285                    (UnmapBehavior::Ignored, _) => UnmapBehavior::Ignored,
286                    (_, UnmapBehavior::Ignored) => UnmapBehavior::Ignored,
287                    _ => UnmapBehavior::Unspecified,
288                };
289                optimal_unmap_sectors = optimal_unmap_sectors.max(layer.meta.optimal_unmap_sectors);
290            } else if write_through {
291                // The write-through layers must all come first.
292                return Err(layer_error(InvalidLayer::UselessWriteThrough));
293            }
294            last_write_through = write_through;
295            if disk_id.is_none() {
296                disk_id = layer.meta.disk_id;
297            }
298        }
299
300        if last_write_through {
301            return Err(InvalidLayeredDisk::Layer(
302                attached_layers.len() - 1,
303                InvalidLayer::UselessWriteThrough,
304            ));
305        }
306
307        let sector_size = attached_layers[0].layer.meta.sector_size;
308        let physical_sector_size = attached_layers[0].layer.meta.physical_sector_size;
309
310        let mut last_sector_count = None;
311        let sector_counts_rev = attached_layers
312            .iter_mut()
313            .rev()
314            .map(|config| *last_sector_count.insert(config.layer.backing.sector_count()))
315            .collect::<Vec<_>>();
316
317        let mut visible_sector_count = !0;
318        let layers = attached_layers
319            .into_iter()
320            .zip(sector_counts_rev.into_iter().rev())
321            .map(|(config, sector_count)| {
322                let LayerConfiguration {
323                    layer,
324                    write_through,
325                    read_cache,
326                } = config;
327                visible_sector_count = sector_count.min(visible_sector_count);
328                Layer {
329                    backing: layer.backing,
330                    visible_sector_count,
331                    read_cache,
332                    write_through,
333                }
334            })
335            .collect::<Vec<_>>();
336
337        Ok(Self {
338            is_fua_respected,
339            read_only,
340            sector_shift: sector_size.trailing_zeros(),
341            disk_id,
342            physical_sector_size,
343            unmap_behavior,
344            optimal_unmap_sectors,
345            layers,
346        })
347    }
348}
349
350trait DynLayerIo: Send + Sync + Inspect {
351    fn sector_count(&self) -> u64;
352
353    fn read<'a>(
354        &'a self,
355        buffers: &'a RequestBuffers<'_>,
356        sector: u64,
357        bitmap: SectorMarker<'a>,
358    ) -> Pin<Box<dyn 'a + Future<Output = Result<(), DiskError>> + Send>>;
359
360    fn write<'a>(
361        &'a self,
362        buffers: &'a RequestBuffers<'_>,
363        sector: u64,
364        fua: bool,
365        no_overwrite: bool,
366    ) -> Pin<Box<dyn 'a + Future<Output = Result<(), DiskError>> + Send>>;
367
368    fn sync_cache(&self) -> Pin<Box<dyn '_ + Future<Output = Result<(), DiskError>> + Send>>;
369
370    fn unmap(
371        &self,
372        sector: u64,
373        count: u64,
374        block_level_only: bool,
375        next_is_zero: bool,
376    ) -> Pin<Box<dyn '_ + Future<Output = Result<(), DiskError>> + Send>>;
377
378    fn wait_resize(&self, sector_count: u64) -> Pin<Box<dyn '_ + Future<Output = u64> + Send>>;
379}
380
381impl<T: LayerIo> DynLayerIo for T {
382    fn sector_count(&self) -> u64 {
383        self.sector_count()
384    }
385
386    fn read<'a>(
387        &'a self,
388        buffers: &'a RequestBuffers<'_>,
389        sector: u64,
390        bitmap: SectorMarker<'a>,
391    ) -> Pin<Box<dyn 'a + Future<Output = Result<(), DiskError>> + Send>> {
392        Box::pin(async move { self.read(buffers, sector, bitmap).await })
393    }
394
395    fn write<'a>(
396        &'a self,
397        buffers: &'a RequestBuffers<'_>,
398        sector: u64,
399        fua: bool,
400        no_overwrite: bool,
401    ) -> Pin<Box<dyn 'a + Future<Output = Result<(), DiskError>> + Send>> {
402        Box::pin(async move {
403            if no_overwrite {
404                self.write_no_overwrite()
405                    .unwrap()
406                    .write_no_overwrite(buffers, sector)
407                    .await
408            } else {
409                self.write(buffers, sector, fua).await
410            }
411        })
412    }
413
414    fn sync_cache(&self) -> Pin<Box<dyn '_ + Future<Output = Result<(), DiskError>> + Send>> {
415        Box::pin(self.sync_cache())
416    }
417
418    fn unmap(
419        &self,
420        sector: u64,
421        count: u64,
422        block_level_only: bool,
423        next_is_zero: bool,
424    ) -> Pin<Box<dyn '_ + Future<Output = Result<(), DiskError>> + Send>> {
425        Box::pin(self.unmap(sector, count, block_level_only, next_is_zero))
426    }
427
428    fn wait_resize(&self, sector_count: u64) -> Pin<Box<dyn '_ + Future<Output = u64> + Send>> {
429        Box::pin(self.wait_resize(sector_count))
430    }
431}
432
433trait DynLayerAttach: Send + Sync {
434    fn attach(
435        self: Box<Self>,
436        lower_layer_metadata: Option<DiskLayerMetadata>,
437    ) -> Pin<Box<dyn Future<Output = anyhow::Result<AttachedDiskLayer>> + Send>>;
438}
439
440impl<T: LayerAttach> DynLayerAttach for T {
441    fn attach(
442        self: Box<Self>,
443        lower_layer_metadata: Option<DiskLayerMetadata>,
444    ) -> Pin<Box<dyn Future<Output = anyhow::Result<AttachedDiskLayer>> + Send>> {
445        Box::pin(async move {
446            Ok({
447                let backing = (*self)
448                    .attach(lower_layer_metadata)
449                    .await
450                    .map_err(|e| anyhow::anyhow!(e.into()))?;
451                let can_read_cache = backing.write_no_overwrite().is_some();
452                AttachedDiskLayer {
453                    meta: DiskLayerMetadata {
454                        sector_count: LayerIo::sector_count(&backing),
455                        disk_id: backing.disk_id(),
456                        is_fua_respected: backing.is_fua_respected(),
457                        sector_size: backing.sector_size(),
458                        physical_sector_size: backing.physical_sector_size(),
459                        unmap_behavior: backing.unmap_behavior(),
460                        optimal_unmap_sectors: backing.optimal_unmap_sectors(),
461                        read_only: backing.is_logically_read_only(),
462                        can_read_cache,
463                    },
464                    backing: Box::new(backing),
465                }
466            })
467        })
468    }
469}
470
471/// Transition a layer from an unattached type-state, into an attached
472/// type-state, capable of performing [`LayerIo`].
473///
474/// Layers which do not require a type-state transition on-attach (e.g: those
475/// which are pre-initialized with a fixed set of metadata) can simply implement
476/// `LayerIo` directly, and leverage the blanket-impl of `impl<T: LayerIo>
477/// LayerAttach for T` which simply returns `Self` during the state transition.
478pub trait LayerAttach: 'static + Send + Sync {
479    /// Error returned if on attach failure.
480    type Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>;
481    /// Object implementating [`LayerIo`] after being attached.
482    type Layer: LayerIo;
483
484    /// Invoked when the layer is being attached to a layer stack.
485    ///
486    /// If the layer is being attached on-top of an existing layer,
487    /// `lower_layer_metadata` can be used to initialize and/or reconfigure the
488    /// layer using the properties of the layer is is being stacked on-top of.
489    fn attach(
490        self,
491        lower_layer_metadata: Option<DiskLayerMetadata>,
492    ) -> impl Future<Output = Result<Self::Layer, Self::Error>> + Send;
493}
494
495impl<T: LayerIo> LayerAttach for T {
496    type Error = Infallible;
497    type Layer = Self;
498    async fn attach(
499        self,
500        _lower_layer_metadata: Option<DiskLayerMetadata>,
501    ) -> Result<Self, Infallible> {
502        Ok(self)
503    }
504}
505
506/// Metadata and IO for disk layers.
507///
508/// # Sector range validation
509///
510/// Layers are subject to the same requirements as [`DiskIo`]: an
511/// implementation must not panic for any sector value, and must return
512/// [`DiskError::IllegalBlock`] for requests outside the layer. Callers do not
513/// pre-validate the range.
514///
515/// Layers also inherit the representability guarantee that [`Disk`] provides to
516/// [`DiskIo`] implementations: the end byte offset of any request is at most
517/// [`i64::MAX`]. This holds because [`LayeredDisk`] never increases the sector
518/// number of a request (it only clamps the end down to the layer's visible
519/// sector count) and never changes the sector size, and because a [`Disk`] used
520/// as a layer re-enters through [`Disk`]'s own entry points.
521pub trait LayerIo: 'static + Send + Sync + Inspect {
522    /// Returns the layer type name as a string.
523    ///
524    /// This is used for diagnostic purposes.
525    fn layer_type(&self) -> &str;
526
527    /// Returns the current sector count.
528    ///
529    /// For some backing stores, this may change at runtime. If it does, then
530    /// the backing store must also implement [`DiskIo::wait_resize`].
531    fn sector_count(&self) -> u64;
532
533    /// Returns the logical sector size of the backing store.
534    ///
535    /// This must not change at runtime.
536    fn sector_size(&self) -> u32;
537
538    /// Optionally returns a 16-byte identifier for the disk, if there is a
539    /// natural one for this backing store.
540    ///
541    /// This may be exposed to the guest as a unique disk identifier.
542    /// This must not change at runtime.
543    fn disk_id(&self) -> Option<[u8; 16]>;
544
545    /// Returns the physical sector size of the backing store.
546    ///
547    /// This must not change at runtime.
548    fn physical_sector_size(&self) -> u32;
549
550    /// Returns true if the `fua` parameter to [`LayerIo::write`] is
551    /// respected by the backing store by ensuring that the IO is immediately
552    /// committed to disk.
553    fn is_fua_respected(&self) -> bool;
554
555    /// Returns true if the layer is logically read only.
556    ///
557    /// If this returns true, the layer might still be writable via
558    /// `write_no_overwrite`, used to populate the layer as a read cache.
559    fn is_logically_read_only(&self) -> bool;
560
561    /// Issues an asynchronous flush operation to the disk.
562    fn sync_cache(&self) -> impl Future<Output = Result<(), DiskError>> + Send;
563
564    /// Reads sectors from the layer.
565    ///
566    /// `marker` is used to specify which sectors have been read. Those that are
567    /// not read will be passed to the next layer, or zeroed if there are no
568    /// more layers.
569    fn read(
570        &self,
571        buffers: &RequestBuffers<'_>,
572        sector: u64,
573        marker: SectorMarker<'_>,
574    ) -> impl Future<Output = Result<(), DiskError>> + Send;
575
576    /// Writes sectors to the layer.
577    ///
578    /// # Panics
579    ///
580    /// The caller must pass a buffer with an integer number of sectors.
581    fn write(
582        &self,
583        buffers: &RequestBuffers<'_>,
584        sector: u64,
585        fua: bool,
586    ) -> impl Future<Output = Result<(), DiskError>> + Send;
587
588    /// Unmap sectors from the layer.
589    ///
590    /// If `next_is_zero` is true, then the next layer's content's are known to
591    /// be zero. A layer can use this information to just discard the sectors
592    /// rather than putting them in the zero state (which make take more space).
593    fn unmap(
594        &self,
595        sector: u64,
596        count: u64,
597        block_level_only: bool,
598        next_is_zero: bool,
599    ) -> impl Future<Output = Result<(), DiskError>> + Send;
600
601    /// Returns the behavior of the unmap operation.
602    fn unmap_behavior(&self) -> UnmapBehavior;
603
604    /// Returns the optimal granularity for unmaps, in sectors.
605    fn optimal_unmap_sectors(&self) -> u32 {
606        1
607    }
608
609    /// Optionally returns a write-no-overwrite implementation.
610    fn write_no_overwrite(&self) -> Option<impl WriteNoOverwrite> {
611        None::<NoIdet>
612    }
613
614    /// Waits for the disk sector size to be different than the specified value.
615    fn wait_resize(&self, sector_count: u64) -> impl Future<Output = u64> + Send {
616        let _ = sector_count;
617        std::future::pending()
618    }
619}
620
621enum NoIdet {}
622
623/// Writes to the layer without overwriting existing data.
624pub trait WriteNoOverwrite: Send + Sync {
625    /// Write to the layer without overwriting existing data. Existing sectors
626    /// must be preserved.
627    ///
628    /// This is used to support read caching, where the data being written may
629    /// be stale by the time it is written back to the layer.
630    fn write_no_overwrite(
631        &self,
632        buffers: &RequestBuffers<'_>,
633        sector: u64,
634    ) -> impl Future<Output = Result<(), DiskError>> + Send;
635}
636
637impl<T: WriteNoOverwrite> WriteNoOverwrite for &T {
638    fn write_no_overwrite(
639        &self,
640        buffers: &RequestBuffers<'_>,
641        sector: u64,
642    ) -> impl Future<Output = Result<(), DiskError>> + Send {
643        (*self).write_no_overwrite(buffers, sector)
644    }
645}
646
647impl WriteNoOverwrite for NoIdet {
648    async fn write_no_overwrite(
649        &self,
650        _buffers: &RequestBuffers<'_>,
651        _sector: u64,
652    ) -> Result<(), DiskError> {
653        unreachable!()
654    }
655}
656
657impl DiskIo for LayeredDisk {
658    fn disk_type(&self) -> &str {
659        "layered"
660    }
661
662    fn sector_count(&self) -> u64 {
663        self.layers[0].backing.sector_count()
664    }
665
666    fn sector_size(&self) -> u32 {
667        1 << self.sector_shift
668    }
669
670    fn disk_id(&self) -> Option<[u8; 16]> {
671        self.disk_id
672    }
673
674    fn physical_sector_size(&self) -> u32 {
675        self.physical_sector_size
676    }
677
678    fn is_fua_respected(&self) -> bool {
679        self.is_fua_respected
680    }
681
682    fn is_read_only(&self) -> bool {
683        self.read_only
684    }
685
686    async fn read_vectored(
687        &self,
688        buffers: &RequestBuffers<'_>,
689        sector: u64,
690    ) -> Result<(), DiskError> {
691        let mut bounce_buffers = None::<(OwnedRequestBuffers, GuestMemory)>;
692        let sector_count = buffers.len() >> self.sector_shift;
693        let mut bitmap = Bitmap::new(sector, sector_count);
694        let mut bits_set = 0;
695        let mut populate_cache = Vec::new();
696        // FUTURE: queue the reads to the layers in parallel.
697        'done: for (i, layer) in self.layers.iter().enumerate() {
698            if bits_set == sector_count {
699                break;
700            }
701            for mut range in bitmap.unset_iter() {
702                let end = if i == 0 {
703                    // The visible sector count of the first layer is unknown,
704                    // since it could change at any time.
705                    range.end_sector()
706                } else {
707                    // Restrict the range to the visible sector count of the
708                    // layer; sectors beyond this are logically zero.
709                    let end = range.end_sector().min(layer.visible_sector_count);
710                    if range.start_sector() == end {
711                        break 'done;
712                    }
713                    end
714                };
715
716                let sectors = end - range.start_sector();
717
718                let this_buffers = if let Some((bounce_buffers, mem)) = &bounce_buffers {
719                    &bounce_buffers.buffer(mem)
720                } else {
721                    buffers
722                };
723                let this_buffers = this_buffers.subrange(
724                    range.start_sector_within_bitmap() << self.sector_shift,
725                    (sectors as usize) << self.sector_shift,
726                );
727
728                layer
729                    .backing
730                    .read(&this_buffers, range.start_sector(), range.view(sectors))
731                    .await?;
732
733                bits_set += range.set_count();
734
735                if range.set_count() as u64 != range.len() && layer.read_cache {
736                    // Allocate bounce buffers to read into to ensure that we get a stable
737                    // copy of the data to populate the cache.
738                    bounce_buffers.get_or_insert_with(|| {
739                        let mem = GuestMemory::allocate(buffers.len());
740                        let owned_buf = OwnedRequestBuffers::linear(0, buffers.len(), true);
741                        (owned_buf, mem)
742                    });
743
744                    populate_cache.extend(range.unset_iter().map(|range| (layer, range)));
745                }
746            }
747        }
748        if bits_set != sector_count {
749            for range in bitmap.unset_iter() {
750                let len = (range.len() as usize) << self.sector_shift;
751                buffers
752                    .subrange(range.start_sector_within_bitmap() << self.sector_shift, len)
753                    .writer()
754                    .zero(len)?;
755            }
756        }
757        if !populate_cache.is_empty() {
758            let (bounce_buffers, mem) = bounce_buffers.unwrap();
759            let bounce_buffers = bounce_buffers.buffer(&mem);
760            for &(layer, ref range) in &populate_cache {
761                assert!(layer.read_cache);
762                let offset = ((range.start - sector) as usize) << self.sector_shift;
763                let len = ((range.end - range.start) as usize) << self.sector_shift;
764                if let Err(err) = layer
765                    .backing
766                    .write(
767                        &bounce_buffers.subrange(offset, len),
768                        range.start,
769                        false,
770                        true,
771                    )
772                    .await
773                {
774                    tracelimit::warn_ratelimited!(
775                        error = &err as &dyn std::error::Error,
776                        sector = range.start,
777                        count = range.end - range.start,
778                        "failed to populate read cache",
779                    );
780                }
781            }
782            let mut mem = mem.into_inner_buf().ok().unwrap();
783            for (_, range) in populate_cache {
784                // Write this bounced range back to the original buffer. This
785                // might be redundant in the presence of multiple cache layers,
786                // but this is the simplest implementation.
787                let offset = ((range.start - sector) as usize) << self.sector_shift;
788                let len = ((range.end - range.start) as usize) << self.sector_shift;
789                buffers
790                    .subrange(offset, len)
791                    .writer()
792                    .write(&mem.as_bytes()[offset..][..len])?;
793            }
794        }
795        Ok(())
796    }
797
798    async fn write_vectored(
799        &self,
800        buffers: &RequestBuffers<'_>,
801        sector: u64,
802        fua: bool,
803    ) -> Result<(), DiskError> {
804        for layer in &self.layers {
805            layer.backing.write(buffers, sector, fua, false).await?;
806            if !layer.write_through {
807                break;
808            }
809        }
810        Ok(())
811    }
812
813    async fn sync_cache(&self) -> Result<(), DiskError> {
814        for layer in &self.layers {
815            layer.backing.sync_cache().await?;
816            if !layer.write_through {
817                break;
818            }
819        }
820        Ok(())
821    }
822
823    fn wait_resize(&self, sector_count: u64) -> impl Future<Output = u64> + Send {
824        self.layers[0].backing.wait_resize(sector_count)
825    }
826
827    async fn unmap(
828        &self,
829        sector_offset: u64,
830        sector_count: u64,
831        block_level_only: bool,
832    ) -> Result<(), DiskError> {
833        if self.unmap_behavior == UnmapBehavior::Ignored {
834            return Ok(());
835        }
836
837        for (layer, next_layer) in self
838            .layers
839            .iter()
840            .zip(self.layers.iter().map(Some).skip(1).chain([None]))
841        {
842            let next_is_zero = if let Some(next_layer) = next_layer {
843                // Sectors beyond the layer's visible sector count are logically
844                // zero.
845                //
846                // FUTURE: consider splitting the unmap operation into multiple
847                // operations across this boundary.
848                sector_offset >= next_layer.visible_sector_count
849            } else {
850                true
851            };
852
853            layer
854                .backing
855                .unmap(sector_offset, sector_count, block_level_only, next_is_zero)
856                .await?;
857            if !layer.write_through {
858                break;
859            }
860        }
861        Ok(())
862    }
863
864    fn unmap_behavior(&self) -> UnmapBehavior {
865        self.unmap_behavior
866    }
867
868    fn optimal_unmap_sectors(&self) -> u32 {
869        self.optimal_unmap_sectors
870    }
871}
872
873/// A disk layer wrapping a full disk.
874#[derive(Inspect)]
875#[inspect(transparent)]
876struct DiskAsLayer(Disk);
877
878impl LayerIo for DiskAsLayer {
879    fn layer_type(&self) -> &str {
880        "disk"
881    }
882
883    fn sector_count(&self) -> u64 {
884        self.0.sector_count()
885    }
886
887    fn sector_size(&self) -> u32 {
888        self.0.sector_size()
889    }
890
891    fn disk_id(&self) -> Option<[u8; 16]> {
892        self.0.disk_id()
893    }
894
895    fn physical_sector_size(&self) -> u32 {
896        self.0.physical_sector_size()
897    }
898
899    fn is_fua_respected(&self) -> bool {
900        self.0.is_fua_respected()
901    }
902
903    fn is_logically_read_only(&self) -> bool {
904        self.0.is_read_only()
905    }
906
907    fn sync_cache(&self) -> impl Future<Output = Result<(), DiskError>> + Send {
908        self.0.sync_cache()
909    }
910
911    async fn read(
912        &self,
913        buffers: &RequestBuffers<'_>,
914        sector: u64,
915        mut bitmap: SectorMarker<'_>,
916    ) -> Result<(), DiskError> {
917        // The disk is fully populated.
918        bitmap.set_all();
919        self.0.read_vectored(buffers, sector).await
920    }
921
922    async fn write(
923        &self,
924        buffers: &RequestBuffers<'_>,
925        sector: u64,
926        fua: bool,
927    ) -> Result<(), DiskError> {
928        self.0.write_vectored(buffers, sector, fua).await
929    }
930
931    fn unmap(
932        &self,
933        sector: u64,
934        count: u64,
935        block_level_only: bool,
936        _lower_is_zero: bool,
937    ) -> impl Future<Output = Result<(), DiskError>> + Send {
938        self.0.unmap(sector, count, block_level_only)
939    }
940
941    fn unmap_behavior(&self) -> UnmapBehavior {
942        self.0.unmap_behavior()
943    }
944}
945
946#[cfg(test)]
947mod tests {
948    use crate::DiskLayer;
949    use crate::LayerConfiguration;
950    use crate::LayerIo;
951    use crate::LayeredDisk;
952    use crate::SectorMarker;
953    use crate::WriteNoOverwrite;
954    use disk_backend::DiskIo;
955    use disk_backend::UnmapBehavior;
956    use guestmem::GuestMemory;
957    use guestmem::MemoryRead as _;
958    use guestmem::MemoryWrite;
959    use inspect::Inspect;
960    use pal_async::async_test;
961    use parking_lot::Mutex;
962    use scsi_buffers::OwnedRequestBuffers;
963    use std::collections::BTreeMap;
964    use std::collections::btree_map::Entry;
965    use std::sync::Arc;
966
967    #[derive(Inspect)]
968    #[inspect(skip)]
969    struct TestLayer {
970        sectors: Mutex<BTreeMap<u64, Data>>,
971        sector_count: u64,
972    }
973
974    impl TestLayer {
975        fn new(sector_count: u64) -> Self {
976            Self {
977                sectors: Mutex::new(BTreeMap::new()),
978                sector_count,
979            }
980        }
981    }
982
983    struct Data(Box<[u8]>);
984
985    impl LayerIo for Arc<TestLayer> {
986        fn layer_type(&self) -> &str {
987            "test"
988        }
989
990        fn sector_count(&self) -> u64 {
991            self.sector_count
992        }
993
994        fn sector_size(&self) -> u32 {
995            512
996        }
997
998        fn disk_id(&self) -> Option<[u8; 16]> {
999            None
1000        }
1001
1002        fn physical_sector_size(&self) -> u32 {
1003            512
1004        }
1005
1006        fn is_fua_respected(&self) -> bool {
1007            false
1008        }
1009
1010        fn is_logically_read_only(&self) -> bool {
1011            false
1012        }
1013
1014        async fn sync_cache(&self) -> Result<(), disk_backend::DiskError> {
1015            Ok(())
1016        }
1017
1018        async fn read(
1019            &self,
1020            buffers: &scsi_buffers::RequestBuffers<'_>,
1021            sector: u64,
1022            mut marker: SectorMarker<'_>,
1023        ) -> Result<(), disk_backend::DiskError> {
1024            let sector_count = buffers.len() / self.sector_size() as usize;
1025            let sectors = self.sectors.lock();
1026            for i in sector..sector + sector_count as u64 {
1027                let Some(data) = sectors.get(&i) else {
1028                    continue;
1029                };
1030                let offset = ((i - sector) * self.sector_size() as u64) as usize;
1031                buffers
1032                    .subrange(offset, self.sector_size() as usize)
1033                    .writer()
1034                    .write(&data.0)?;
1035                marker.set(i);
1036            }
1037            Ok(())
1038        }
1039
1040        async fn write(
1041            &self,
1042            buffers: &scsi_buffers::RequestBuffers<'_>,
1043            sector: u64,
1044            _fua: bool,
1045        ) -> Result<(), disk_backend::DiskError> {
1046            let sector_count = buffers.len() / self.sector_size() as usize;
1047            let mut sectors = self.sectors.lock();
1048            for i in sector..sector + sector_count as u64 {
1049                let offset = ((i - sector) * self.sector_size() as u64) as usize;
1050                let mut data = Data(vec![0; self.sector_size() as usize].into());
1051                buffers
1052                    .subrange(offset, self.sector_size() as usize)
1053                    .reader()
1054                    .read(&mut data.0)?;
1055                sectors.insert(i, data);
1056            }
1057            Ok(())
1058        }
1059
1060        async fn unmap(
1061            &self,
1062            sector: u64,
1063            count: u64,
1064            _block_level_only: bool,
1065            next_is_zero: bool,
1066        ) -> Result<(), disk_backend::DiskError> {
1067            if !next_is_zero {
1068                return Ok(());
1069            }
1070            let mut sectors = self.sectors.lock();
1071            let mut next_sector = sector;
1072            let end = sector + count;
1073            while next_sector < end {
1074                let Some((&sector, _)) = sectors.range_mut(next_sector..).next() else {
1075                    break;
1076                };
1077                if sector >= end {
1078                    break;
1079                }
1080                sectors.remove(&sector);
1081                next_sector = sector + 1;
1082            }
1083            Ok(())
1084        }
1085
1086        fn unmap_behavior(&self) -> UnmapBehavior {
1087            UnmapBehavior::Unspecified
1088        }
1089
1090        fn write_no_overwrite(&self) -> Option<impl WriteNoOverwrite> {
1091            Some(self)
1092        }
1093    }
1094
1095    impl WriteNoOverwrite for Arc<TestLayer> {
1096        async fn write_no_overwrite(
1097            &self,
1098            buffers: &scsi_buffers::RequestBuffers<'_>,
1099            sector: u64,
1100        ) -> Result<(), disk_backend::DiskError> {
1101            let sector_count = buffers.len() / self.sector_size() as usize;
1102            let mut sectors = self.sectors.lock();
1103            for i in sector..sector + sector_count as u64 {
1104                let Entry::Vacant(entry) = sectors.entry(i) else {
1105                    continue;
1106                };
1107                let offset = ((i - sector) * self.sector_size() as u64) as usize;
1108                let mut data = Data(vec![0; self.sector_size() as usize].into());
1109                buffers
1110                    .subrange(offset, self.sector_size() as usize)
1111                    .reader()
1112                    .read(&mut data.0)?;
1113                entry.insert(data);
1114            }
1115            Ok(())
1116        }
1117    }
1118
1119    #[async_test]
1120    async fn test_read_cache() {
1121        const SIZE: u64 = 2048;
1122        let bottom = Arc::new(TestLayer::new(SIZE));
1123        let pattern = |i: u64| {
1124            let mut acc = (i + 1) * 3;
1125            Data(
1126                (0..512)
1127                    .map(|_| {
1128                        acc = acc.wrapping_mul(7);
1129                        acc as u8
1130                    })
1131                    .collect::<Vec<_>>()
1132                    .into(),
1133            )
1134        };
1135        bottom
1136            .sectors
1137            .lock()
1138            .extend((0..SIZE).map(|i| (i, pattern(i))));
1139
1140        let cache = Arc::new(TestLayer::new(SIZE));
1141        let cache_cfg = LayerConfiguration {
1142            layer: DiskLayer::new(cache.clone()),
1143            read_cache: true,
1144            write_through: false,
1145        };
1146        let bottom_cfg = LayerConfiguration {
1147            layer: DiskLayer::new(bottom),
1148            read_cache: false,
1149            write_through: false,
1150        };
1151        let disk = LayeredDisk::new(false, vec![cache_cfg, bottom_cfg])
1152            .await
1153            .unwrap();
1154
1155        let mut mem = GuestMemory::allocate(0x10000);
1156        let buffers = OwnedRequestBuffers::linear(0, 0x10000, true);
1157
1158        for i in [0, 2, 4, 6, 8, 0, 2, 4, 6, 8] {
1159            disk.read_vectored(&buffers.buffer(&mem).subrange(0, 512), i)
1160                .await
1161                .unwrap();
1162
1163            assert_eq!(mem.inner_buf_mut().unwrap()[..512], pattern(i).0[..]);
1164        }
1165
1166        assert_eq!(cache.sectors.lock().len(), 5);
1167
1168        mem.inner_buf_mut().unwrap().fill(0);
1169
1170        disk.read_vectored(&buffers.buffer(&mem).subrange(0, 15 * 512), 1)
1171            .await
1172            .unwrap();
1173
1174        assert_eq!(cache.sectors.lock().len(), 16);
1175
1176        for i in 0..15 {
1177            assert_eq!(
1178                mem.inner_buf_mut().unwrap()[i as usize * 512..][..512],
1179                pattern(i + 1).0[..],
1180                "{i}"
1181            );
1182        }
1183    }
1184}