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