imago/qcow2/
mod.rs

1//! Qcow2 implementation.
2
3mod allocation;
4mod builder;
5mod cache;
6mod compressed;
7mod cow;
8mod io_func;
9mod mappings;
10mod metadata;
11mod preallocation;
12#[cfg(feature = "sync-wrappers")]
13mod sync_wrappers;
14mod types;
15
16use crate::async_lru_cache::AsyncLruCache;
17use crate::format::builder::{FormatCreateBuilder, FormatDriverBuilder};
18use crate::format::drivers::FormatDriverInstance;
19use crate::format::gate::{ImplicitOpenGate, PermissiveImplicitOpenGate};
20use crate::format::wrapped::WrappedFormat;
21use crate::format::{Format, PreallocateMode};
22use crate::io_buffers::IoVectorMut;
23use crate::misc_helpers::{invalid_data, ResultErrorContext};
24use crate::raw::Raw;
25use crate::{storage, FormatAccess, ShallowMapping, Storage, StorageExt, StorageOpenOptions};
26use allocation::Allocator;
27use async_trait::async_trait;
28pub use builder::{Qcow2CreateBuilder, Qcow2OpenBuilder};
29use cache::MetadataCaches;
30use mappings::FixedMapping;
31use metadata::*;
32use std::fmt::{self, Debug, Display, Formatter};
33use std::ops::Range;
34use std::path::Path;
35use std::sync::Arc;
36use std::{cmp, io};
37use tokio::sync::{Mutex, RwLock};
38use types::*;
39
40/// Access qcow2 images.
41///
42/// Allows access to qcow2 images (v2 and v3), referencing the following objects:
43/// - Metadata storage object: The image file itself
44/// - Data file (storage object): May be the image file itself, or an external data file
45/// - Backing image `WrappedFormat<S>`: A backing disk image in any format
46#[must_use = "qcow2 images must be flushed before closing"]
47pub struct Qcow2<S: Storage + 'static, F: WrappedFormat<S> + 'static = FormatAccess<S>> {
48    /// Image file (which contains the qcow2 metadata).
49    metadata: Arc<S>,
50
51    /// Whether this image may be modified.
52    writable: bool,
53
54    /// Whether the user explicitly assigned a data file storage object (or `None`).
55    storage_set: bool,
56    /// Data file storage object; will use `metadata` if `None`.
57    storage: Option<S>,
58    /// Whether the user explicitly assigned a backing file (or `None`).
59    backing_set: bool,
60    /// Backing image.
61    backing: Option<F>,
62    /// Base options to be used for implicitly opened storage objects.
63    storage_open_options: StorageOpenOptions,
64
65    /// Qcow2 header.
66    header: Arc<Header>,
67    /// L1 table.
68    l1_table: RwLock<L1Table>,
69
70    /// L2 and refblock caches
71    caches: Arc<MetadataCaches<S>>,
72
73    /// Allocates clusters.
74    ///
75    /// Is `None` for read-only images.
76    allocator: Option<Mutex<Allocator<S>>>,
77}
78
79impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F> {
80    /// Create a new [`FormatDriverBuilder`] instance for the given image.
81    pub fn builder(image: S) -> Qcow2OpenBuilder<S, F> {
82        Qcow2OpenBuilder::new(image)
83    }
84
85    /// Create a new [`FormatDriverBuilder`] instance for an image under the given path.
86    pub fn builder_path<P: AsRef<Path>>(image_path: P) -> Qcow2OpenBuilder<S, F> {
87        Qcow2OpenBuilder::new_path(image_path)
88    }
89
90    /// Create a new [`FormatCreateBuilder`] instance to format the given file.
91    pub fn create_builder(image: S) -> Qcow2CreateBuilder<S, F> {
92        Qcow2CreateBuilder::<S, F>::new(image)
93    }
94
95    /// Internal implementation for opening a qcow2 image.
96    ///
97    /// Does not open external dependencies.
98    async fn do_open(
99        metadata: S,
100        writable: bool,
101        storage_open_options: StorageOpenOptions,
102    ) -> io::Result<Self> {
103        let header = Arc::new(Header::load(&metadata, writable).await?);
104
105        let cb = header.cluster_bits();
106        let l1_offset = header.l1_table_offset();
107        let l1_cluster = l1_offset
108            .checked_cluster(cb)
109            .ok_or_else(|| invalid_data("Unaligned L1 table: {l1_offset}"))?;
110
111        let l1_table =
112            L1Table::load(&metadata, &header, l1_cluster, header.l1_table_entries()).await?;
113
114        let metadata = Arc::new(metadata);
115        let caches = Arc::new(MetadataCaches::new(&metadata, &header, 128, 32));
116
117        let allocator = if writable {
118            let allocator = Allocator::new(
119                Arc::clone(&metadata),
120                Arc::clone(&header),
121                Arc::clone(&caches),
122            )
123            .await?;
124            Some(Mutex::new(allocator))
125        } else {
126            None
127        };
128
129        Ok(Qcow2 {
130            metadata,
131
132            writable,
133
134            storage_set: false,
135            storage: None,
136            backing_set: false,
137            backing: None,
138            storage_open_options,
139
140            header,
141            l1_table: RwLock::new(l1_table),
142
143            caches,
144            allocator,
145        })
146    }
147
148    /// Opens a qcow2 file.
149    ///
150    /// `metadata` is the file containing the qcow2 metadata.  If `writable` is not set, no
151    /// modifications are permitted.
152    ///
153    /// This will not open any other storage objects needed, i.e. no backing image, no external
154    /// data file.  If you want to handle those manually, check whether an external data file is
155    /// needed via [`Qcow2::requires_external_data_file()`], and, if necessary, assign one via
156    /// [`Qcow2::set_data_file()`]; and assign a backing image via [`Qcow2::set_backing()`].
157    ///
158    /// If you want to use the implicit references given in the image header, use
159    /// [`Qcow2::open_implicit_dependencies()`].
160    pub async fn open_image(metadata: S, writable: bool) -> io::Result<Self> {
161        Self::do_open(metadata, writable, StorageOpenOptions::new()).await
162    }
163
164    /// Open a qcow2 file at the given path.
165    ///
166    /// Open the file as a storage object via [`Storage::open()`], with write access if specified,
167    /// then pass that object to [`Qcow2::open_image()`].
168    ///
169    /// This will not open any other storage objects needed, i.e. no backing image, no external
170    /// data file.  If you want to handle those manually, check whether an external data file is
171    /// needed via [`Qcow2::requires_external_data_file()`], and, if necessary, assign one via
172    /// [`Qcow2::set_data_file()`]; and assign a backing image via [`Qcow2::set_backing()`].
173    ///
174    /// If you want to use the implicit references given in the image header, use
175    /// [`Qcow2::open_implicit_dependencies()`].
176    pub async fn open_path<P: AsRef<Path>>(path: P, writable: bool) -> io::Result<Self> {
177        let storage_opts = StorageOpenOptions::new().write(writable).filename(path);
178        let metadata = S::open(storage_opts).await?;
179        Self::do_open(metadata, writable, StorageOpenOptions::new()).await
180    }
181
182    /// Does this qcow2 image require an external data file?
183    ///
184    /// Conversely, if this is `false`, this image must not use an external data file.
185    pub fn requires_external_data_file(&self) -> bool {
186        self.header.external_data_file()
187    }
188
189    /// External data file filename given in the image header.
190    ///
191    /// Note that even if an image requires an external data file, the header may not contain its
192    /// filename.  In this case, an external data file must be set explicitly via
193    /// [`Qcow2::set_data_file()`].
194    pub fn implicit_external_data_file(&self) -> Option<&String> {
195        self.header.external_data_filename()
196    }
197
198    /// Backing image filename given in the image header.
199    pub fn implicit_backing_file(&self) -> Option<&String> {
200        self.header.backing_filename()
201    }
202
203    /// Backing image format given in the image header.
204    ///
205    /// If this is `None`, the backing image’s format should be probed.  Note that this may be
206    /// dangerous if guests have write access to the backing file: Given a raw image, a guest can
207    /// write a qcow2 header into it, resulting in the image being opened as qcow2 the next time,
208    /// allowing the guest to read arbitrary files (e.g. by setting them as backing files).
209    pub fn implicit_backing_format(&self) -> Option<&String> {
210        self.header.backing_format()
211    }
212
213    /// Assign the data file.
214    ///
215    /// `None` means using the same data storage for both metadata and data, which should be used
216    /// if [`Qcow2::requires_external_data_file()`] is `false`.
217    pub fn set_data_file(&mut self, file: Option<S>) {
218        self.storage = file;
219        self.storage_set = true;
220    }
221
222    /// Assign a backing image.
223    ///
224    /// `None` means no backing image, i.e. reading from unallocated areas will produce zeroes.
225    pub fn set_backing(&mut self, backing: Option<F>) {
226        self.backing = backing;
227        self.backing_set = true;
228    }
229
230    /// Get the data storage object.
231    ///
232    /// If we have an external data file, return that.  Otherwise, return the image (metadata)
233    /// file.
234    fn storage(&self) -> &S {
235        self.storage.as_ref().unwrap_or(&self.metadata)
236    }
237
238    /// Return the image’s implicit data file (as given in the image header).
239    async fn open_implicit_data_file<G: ImplicitOpenGate<S>>(
240        &self,
241        gate: &mut G,
242    ) -> io::Result<Option<S>> {
243        if !self.header.external_data_file() {
244            return Ok(None);
245        }
246
247        let Some(filename) = self.header.external_data_filename() else {
248            return Err(io::Error::other(
249                "Image requires external data file, but no filename given",
250            ));
251        };
252
253        let absolute = self
254            .metadata
255            .resolve_relative_path(filename)
256            .err_context(|| format!("Cannot resolve external data file name {filename}"))?;
257
258        let opts = self
259            .storage_open_options
260            .clone()
261            .write(true)
262            .filename(absolute.clone());
263
264        let file = gate
265            .open_storage(opts)
266            .await
267            .err_context(|| format!("External data file {absolute:?}"))?;
268        Ok(Some(file))
269    }
270
271    /// Wrap `file` in the `Raw` format.  Helper for [`Qcow2::implicit_backing_file()`].
272    async fn open_raw_backing_file<G: ImplicitOpenGate<S>>(
273        &self,
274        file: S,
275        gate: &mut G,
276    ) -> io::Result<F> {
277        let opts = Raw::builder(file).storage_open_options(self.storage_open_options.clone());
278        let raw = gate.open_format(opts).await?;
279        Ok(F::wrap(raw))
280    }
281
282    /// Wrap `file` in the `Qcow2` format.  Helper for [`Qcow2::implicit_backing_file()`].
283    async fn open_qcow2_backing_file<G: ImplicitOpenGate<S>>(
284        &self,
285        file: S,
286        gate: &mut G,
287    ) -> io::Result<F> {
288        let opts =
289            Qcow2::<S>::builder(file).storage_open_options(self.storage_open_options.clone());
290        // Recursive, so needs to be boxed
291        let qcow2 = Box::pin(gate.open_format(opts)).await?;
292        Ok(F::wrap(qcow2))
293    }
294
295    /// Return the image’s implicit backing image (as given in the image header).
296    ///
297    /// Anything opened will be passed through `gate`.
298    async fn open_implicit_backing_file<G: ImplicitOpenGate<S>>(
299        &self,
300        gate: &mut G,
301    ) -> io::Result<Option<F>> {
302        let Some(filename) = self.header.backing_filename() else {
303            return Ok(None);
304        };
305
306        let absolute = self
307            .metadata
308            .resolve_relative_path(filename)
309            .err_context(|| format!("Cannot resolve backing file name {filename}"))?;
310
311        let file_opts = self
312            .storage_open_options
313            .clone()
314            .filename(absolute.clone())
315            .write(false);
316
317        let file = gate
318            .open_storage(file_opts)
319            .await
320            .err_context(|| format!("Backing file {absolute:?}"))?;
321
322        let result = match self.header.backing_format().map(|f| f.as_str()) {
323            Some("qcow2") => self.open_qcow2_backing_file(file, gate).await.map(Some),
324            Some("raw") | Some("file") => self.open_raw_backing_file(file, gate).await.map(Some),
325
326            Some(fmt) => Err(io::Error::other(format!("Unknown backing format {fmt}"))),
327
328            // Reasonably safe: The backing image is supposed to be read-only.  We could run into
329            // trouble if a guest is on a raw image, which is then snapshotted, and now we see a
330            // qcow2 image; but let’s rely on such images always having a backing format set.
331            None => match unsafe { Self::probe(&file) }.await {
332                Ok(true) => self.open_qcow2_backing_file(file, gate).await.map(Some),
333                Ok(false) => self.open_raw_backing_file(file, gate).await.map(Some),
334                Err(err) => Err(err),
335            },
336        };
337
338        result.err_context(|| format!("Backing file {absolute:?}"))
339    }
340
341    /// Open all implicit dependencies.
342    ///
343    /// Qcow2 images have dependencies:
344    /// - The metadata file, which is the image file itself.
345    /// - The data file, which may be the same as the metadata file, or may be an external data
346    ///   file.
347    /// - A backing disk image in any format.
348    ///
349    /// All of this can be set explicitly:
350    /// - The metadata file is always given explicitly to [`Qcow2::open_image()`].
351    /// - The data file can be set via [`Qcow2::set_data_file()`].
352    /// - The backing image can be set via [`Qcow2::set_backing()`].
353    ///
354    /// But the image header can also provide “default” references to the data file and a backing
355    /// image, which we call *implicit* dependencies.  This function opens all such implicit
356    /// dependencies if they have not been overridden with prior calls to
357    /// [`Qcow2::set_data_file()`] or [`Qcow2::set_backing()`], respectively.
358    ///
359    /// Any image or file is opened through `gate`.
360    pub async fn open_implicit_dependencies_gated<G: ImplicitOpenGate<S>>(
361        &mut self,
362        mut gate: G,
363    ) -> io::Result<()> {
364        if !self.storage_set {
365            self.storage = self.open_implicit_data_file(&mut gate).await?;
366            self.storage_set = true;
367        }
368
369        if !self.backing_set {
370            self.backing = self.open_implicit_backing_file(&mut gate).await?;
371            self.backing_set = true;
372        }
373
374        Ok(())
375    }
376
377    /// Open all implicit dependencies, ungated.
378    ///
379    /// Same as [`Qcow2::open_implicit_dependencies_gated`], but does not perform any gating on
380    /// implicitly opened images/files.
381    ///
382    /// See the cautionary notes on [`PermissiveImplicitOpenGate`] on
383    /// [`FormatDriverInstance::probe()`] on why this may be dangerous.
384    pub async fn open_implicit_dependencies(&mut self) -> io::Result<()> {
385        self.open_implicit_dependencies_gated(PermissiveImplicitOpenGate::default())
386            .await
387    }
388
389    /// Require write access, i.e. return an error for read-only images.
390    fn need_writable(&self) -> io::Result<()> {
391        self.writable
392            .then_some(())
393            .ok_or_else(|| io::Error::other("Image is read-only"))
394    }
395
396    /// Check whether `length + offset` is within the disk size.
397    fn check_disk_bounds<D: Display>(&self, length: u64, offset: u64, req: D) -> io::Result<()> {
398        let size = self.header.size();
399        let length_until_eof = size.saturating_sub(offset);
400        if length_until_eof >= length {
401            Ok(())
402        } else {
403            Err(io::Error::new(
404                io::ErrorKind::UnexpectedEof,
405                format!("Cannot {req} beyond the disk size ({length} + {offset} > {size}"),
406            ))
407        }
408    }
409
410    /// Check whether we support the given preallocation mode.
411    ///
412    /// `with_backing` designates whether the (new) image (should) have a backing file.
413    fn check_valid_preallocation(
414        prealloc_mode: PreallocateMode,
415        with_backing: bool,
416    ) -> io::Result<()> {
417        if !with_backing {
418            return Ok(());
419        }
420
421        match prealloc_mode {
422            PreallocateMode::None | PreallocateMode::Zero => Ok(()),
423
424            PreallocateMode::FormatAllocate
425            | PreallocateMode::FullAllocate
426            | PreallocateMode::WriteData => Err(io::Error::new(
427                io::ErrorKind::Unsupported,
428                "Preallocation is not yet supported for images with a backing file",
429            )),
430        }
431    }
432}
433
434#[async_trait(?Send)]
435impl<S: Storage, F: WrappedFormat<S>> FormatDriverInstance for Qcow2<S, F> {
436    type Storage = S;
437
438    fn format(&self) -> Format {
439        Format::Qcow2
440    }
441
442    async unsafe fn probe(metadata: &S) -> io::Result<bool>
443    where
444        Self: Sized,
445    {
446        let mut magic_version = [0u8; 8];
447        metadata.read(&mut magic_version[..], 0).await?;
448
449        let magic = u32::from_be_bytes((&magic_version[..4]).try_into().unwrap());
450        let version = u32::from_be_bytes((&magic_version[4..]).try_into().unwrap());
451        Ok(magic == MAGIC && (version == 2 || (version == 3)))
452    }
453
454    fn size(&self) -> u64 {
455        self.header.size()
456    }
457
458    fn zero_granularity(&self) -> Option<u64> {
459        self.header.require_version(3).ok()?;
460        Some(self.header.cluster_size() as u64)
461    }
462
463    fn collect_storage_dependencies(&self) -> Vec<&S> {
464        let mut v = self
465            .backing
466            .as_ref()
467            .map(|b| b.inner().collect_storage_dependencies())
468            .unwrap_or_default();
469
470        v.push(&self.metadata);
471        if let Some(storage) = self.storage.as_ref() {
472            v.push(storage);
473        }
474
475        v
476    }
477
478    fn writable(&self) -> bool {
479        self.writable
480    }
481
482    async fn get_mapping<'a>(
483        &'a self,
484        offset: u64,
485        max_length: u64,
486    ) -> io::Result<(ShallowMapping<'a, S>, u64)> {
487        let length_until_eof = match self.header.size().checked_sub(offset) {
488            None | Some(0) => return Ok((ShallowMapping::Eof {}, 0)),
489            Some(length) => length,
490        };
491
492        let max_length = cmp::min(max_length, length_until_eof);
493        let offset = GuestOffset(offset);
494        self.do_get_mapping(offset, max_length).await
495    }
496
497    async fn ensure_data_mapping<'a>(
498        &'a self,
499        offset: u64,
500        length: u64,
501        overwrite: bool,
502    ) -> io::Result<(&'a S, u64, u64)> {
503        self.check_disk_bounds(offset, length, "allocate")?;
504
505        if length == 0 {
506            return Ok((self.storage(), 0, 0));
507        }
508
509        self.need_writable()?;
510        let offset = GuestOffset(offset);
511        self.do_ensure_data_mapping(offset, length, overwrite, false)
512            .await
513    }
514
515    async fn ensure_zero_mapping(&self, offset: u64, length: u64) -> io::Result<(u64, u64)> {
516        self.need_writable()?;
517        self.check_disk_bounds(offset, length, "write")?;
518
519        self.ensure_fixed_mapping(
520            GuestOffset(offset),
521            length,
522            FixedMapping::ZeroRetainAllocation,
523        )
524        .await
525        .map(|(ofs, len)| (ofs.0, len))
526    }
527
528    async unsafe fn discard_to_zero_unsafe(
529        &self,
530        offset: u64,
531        length: u64,
532    ) -> io::Result<(u64, u64)> {
533        self.need_writable()?;
534        self.check_disk_bounds(offset, length, "discard")?;
535
536        // Safe to discard: We have a mutable `self` reference
537        // Note this will return an `Unsupported` error for v2 images.  That’s OK, safely
538        // discarding on them is a hairy affair, and they are really outdated by now.
539        self.ensure_fixed_mapping(GuestOffset(offset), length, FixedMapping::ZeroDiscard)
540            .await
541            .map(|(ofs, len)| (ofs.0, len))
542    }
543
544    async unsafe fn discard_to_any_unsafe(
545        &self,
546        offset: u64,
547        length: u64,
548    ) -> io::Result<(u64, u64)> {
549        // Safe: Our caller guarantees that invalidating mappings is safe
550        unsafe { self.discard_to_zero_unsafe(offset, length).await }
551    }
552
553    async unsafe fn discard_to_backing_unsafe(
554        &self,
555        offset: u64,
556        length: u64,
557    ) -> io::Result<(u64, u64)> {
558        self.need_writable()?;
559        self.check_disk_bounds(offset, length, "discard")?;
560
561        // Safe to discard: We have a mutable `self` reference
562        self.ensure_fixed_mapping(GuestOffset(offset), length, FixedMapping::FullDiscard)
563            .await
564            .map(|(ofs, len)| (ofs.0, len))
565    }
566
567    async fn readv_special(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
568        let offset = GuestOffset(offset);
569        self.do_readv_special(bufv, offset).await
570    }
571
572    async fn flush(&self) -> io::Result<()> {
573        self.caches.flush_all().await?;
574        self.metadata.flush().await?;
575        if let Some(storage) = self.storage.as_ref() {
576            storage.flush().await?;
577        }
578        // Backing file is read-only, so need not be flushed from us.
579        Ok(())
580    }
581
582    async fn sync(&self) -> io::Result<()> {
583        self.metadata.sync().await?;
584        if let Some(storage) = self.storage.as_ref() {
585            storage.sync().await?;
586        }
587        // Backing file is read-only, so need not be synced from us.
588        Ok(())
589    }
590
591    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
592        // Safe: Caller says we should do this
593        unsafe { self.caches.invalidate_l2() }.await?;
594        if let Some(allocator) = self.allocator.as_ref() {
595            let allocator = allocator.lock().await;
596            // Safe: Caller says we should do this
597            unsafe { allocator.invalidate_rb_cache() }.await?;
598        }
599
600        // Safe: Caller says we should do this
601        unsafe { self.metadata.invalidate_cache() }.await?;
602        if let Some(storage) = self.storage.as_ref() {
603            // Safe: Caller says we should do this
604            unsafe { storage.invalidate_cache() }.await?;
605        }
606        if let Some(backing) = self.backing.as_ref() {
607            // Safe: Caller says we should do this
608            unsafe { backing.inner().invalidate_cache() }.await?;
609        }
610
611        // TODO: Ideally we would reload the whole image header, but that would require putting it
612        // in a lock.  We probably do not want to put things like cluster_bits behind a lock.  For
613        // the time being, all we need to reload are things that are mutable at runtime anyway
614        // (because the source instance would not have been able to change other things), so just
615        // reload the L1 and refcount table positions.
616        let new_header = Header::load(self.metadata.as_ref(), false).await?;
617        self.header.update(&new_header)?;
618
619        if let Some(allocator) = self.allocator.as_ref() {
620            *allocator.lock().await = Allocator::new(
621                Arc::clone(&self.metadata),
622                Arc::clone(&self.header),
623                Arc::clone(&self.caches),
624            )
625            .await?;
626        }
627
628        // Alignment checked in `load()`
629        let l1_cluster = self
630            .header
631            .l1_table_offset()
632            .cluster(self.header.cluster_bits());
633
634        *self.l1_table.write().await = L1Table::load(
635            self.metadata.as_ref(),
636            &self.header,
637            l1_cluster,
638            self.header.l1_table_entries(),
639        )
640        .await?;
641
642        Ok(())
643    }
644
645    async fn resize_grow(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
646        self.need_writable()?;
647
648        let old_size = self.size();
649        let grown_length = new_size.saturating_sub(old_size);
650        if grown_length == 0 {
651            return Ok(()); // only grow, else do nothing
652        }
653
654        Self::check_valid_preallocation(prealloc_mode, self.backing.is_some())?;
655
656        if let Some(data_file) = self.storage.as_ref() {
657            // Options that allocate data mappings in qcow2 will resize the data file via
658            // `preallocate()`.  Those that don’t won’t, so they need to be handled here.
659            match prealloc_mode {
660                PreallocateMode::None => {
661                    data_file
662                        .resize(new_size, storage::PreallocateMode::None)
663                        .await?;
664                }
665                PreallocateMode::Zero => {
666                    data_file
667                        .resize(new_size, storage::PreallocateMode::Zero)
668                        .await?;
669                }
670                PreallocateMode::FormatAllocate
671                | PreallocateMode::FullAllocate
672                | PreallocateMode::WriteData => (),
673            }
674        }
675
676        // QEMU requires the L1 table to at least match the image’s size.
677        // On that note, note that this would make an L1 state’s data visible to the guest (and
678        // also effectively invalidate it, because it is no longer L1 state, but just data), but
679        // QEMU does not care either.  (We could see whether there are allocated clusters after the
680        // image end to find out.)
681        {
682            let l1_locked = self.l1_table.write().await;
683            let l1_index =
684                GuestOffset(new_size.saturating_sub(1)).l1_index(self.header.cluster_bits());
685            let _l1_locked = self.grow_l1_table(l1_locked, l1_index).await?;
686        }
687
688        // Preallocate the entire new range (beyond the current image end)
689        match prealloc_mode {
690            PreallocateMode::None => (),
691            PreallocateMode::Zero => self.preallocate_zero(old_size, grown_length).await?,
692            PreallocateMode::FormatAllocate => {
693                self.preallocate(old_size, grown_length, storage::PreallocateMode::Zero)
694                    .await?;
695            }
696            PreallocateMode::FullAllocate => {
697                self.preallocate(old_size, grown_length, storage::PreallocateMode::Allocate)
698                    .await?;
699            }
700            PreallocateMode::WriteData => {
701                self.preallocate(old_size, grown_length, storage::PreallocateMode::WriteData)
702                    .await?
703            }
704        }
705
706        // Now that preallocation is complete, it’s safe to actually set the new size (otherwise
707        // someone might see a backing image’s data peek through briefly in case it is longer than
708        // `old_size`)
709        self.header.set_size(new_size);
710        self.header
711            .write_size(self.metadata.as_ref())
712            .await
713            .inspect_err(|_| {
714                // Reset to old size
715                self.header.set_size(old_size)
716            })
717    }
718
719    async fn resize_shrink(&mut self, new_size: u64) -> io::Result<()> {
720        self.need_writable()?;
721
722        let old_size = self.size();
723        if new_size >= old_size {
724            return Ok(()); // only shrink, else do nothing
725        }
726
727        if let Some(data_file) = self.storage.as_ref() {
728            data_file
729                .resize(new_size, storage::PreallocateMode::None)
730                .await?;
731        }
732
733        let mut offset = new_size;
734        while offset < old_size {
735            match self.discard_to_backing(offset, old_size - offset).await {
736                Ok((_, 0)) => break, // cannot discard tail
737                Ok((dofs, dlen)) => offset = dofs + dlen,
738                // Basically ignore errors, but stop trying to discard
739                Err(_) => break,
740            }
741        }
742
743        // Shrink after discarding (so we can discard)
744        self.header.set_size(new_size);
745
746        // Do this last because we may not be able to undo it
747        self.header
748            .write_size(self.metadata.as_ref())
749            .await
750            .inspect_err(|_| {
751                // Reset to old size
752                self.header.set_size(old_size);
753            })
754    }
755}
756
757impl<S: Storage + 'static, F: WrappedFormat<S>> Debug for Qcow2<S, F> {
758    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
759        f.debug_struct("Qcow2")
760            .field("metadata", &self.metadata)
761            .field("storage_set", &self.storage_set)
762            .field("storage", &self.storage)
763            .field("backing_set", &self.backing_set)
764            .field("backing", &self.backing)
765            .finish()
766    }
767}
768
769impl<S: Storage + 'static, F: WrappedFormat<S>> Display for Qcow2<S, F> {
770    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
771        write!(f, "qcow2[{}]", self.metadata)
772    }
773}