1mod allocation;
4mod builder;
5mod cache;
6#[cfg(all(test, feature = "async"))]
7mod cancel_tests;
8mod compressed;
9mod cow;
10mod io_func;
11mod mappings;
12mod metadata;
13mod preallocation;
14#[cfg(feature = "sync-wrappers")]
15mod sync_wrappers;
16mod types;
17
18use crate::async_lru_cache::AsyncLruCache;
19use crate::format::builder::{FormatCreateBuilder, FormatDriverBuilder};
20use crate::format::drivers::{FormatDriverInstance, PreparedDataMapping};
21use crate::format::gate::{ImplicitOpenGate, PermissiveImplicitOpenGate};
22use crate::format::wrapped::WrappedFormat;
23use crate::format::{Format, PreallocateMode};
24use crate::io_buffers::IoVectorMut;
25use crate::misc_helpers::{invalid_data, ResultErrorContext};
26use crate::raw::Raw;
27use crate::sync_primitives::{Mutex, RwLock};
28use crate::{storage, FormatAccess, ShallowMapping, Storage, StorageExt, StorageOpenOptions};
29use allocation::{Allocator, ClustersToFreeEntry, ClustersToFreeList, PendingClusters};
30pub use builder::{Qcow2CreateBuilder, Qcow2OpenBuilder};
31use cache::MetadataCaches;
32use mappings::{FixedMapping, PreparedMappingState};
33use maybe_async::maybe_async;
34use metadata::*;
35use std::fmt::{self, Debug, Display, Formatter};
36use std::ops::Range;
37use std::path::Path;
38use std::sync::Arc;
39use std::{cmp, io};
40use types::*;
41
42#[must_use = "qcow2 images must be flushed before closing"]
49pub struct Qcow2<S: Storage + 'static, F: WrappedFormat<S> + 'static = FormatAccess<S>> {
50 metadata: Arc<S>,
52
53 writable: bool,
55
56 storage_set: bool,
58 storage: Option<S>,
60 backing_set: bool,
62 backing: Option<F>,
64 storage_open_options: StorageOpenOptions,
66
67 header: Arc<Header>,
69 l1_table: RwLock<L1Table>,
71
72 caches: Arc<MetadataCaches<S>>,
74
75 allocator: Option<Mutex<Allocator<S>>>,
79
80 clusters_to_free: Arc<ClustersToFreeList>,
84}
85
86#[maybe_async]
87impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F> {
88 pub fn builder(image: S) -> Qcow2OpenBuilder<S, F> {
90 Qcow2OpenBuilder::new(image)
91 }
92
93 pub fn builder_path<P: AsRef<Path>>(image_path: P) -> Qcow2OpenBuilder<S, F> {
95 Qcow2OpenBuilder::new_path(image_path)
96 }
97
98 pub fn create_builder(image: S) -> Qcow2CreateBuilder<S, F> {
100 Qcow2CreateBuilder::<S, F>::new(image)
101 }
102
103 async fn do_open(
107 metadata: S,
108 writable: bool,
109 storage_open_options: StorageOpenOptions,
110 ) -> io::Result<Self> {
111 let header = Arc::new(Header::load(&metadata, writable).await?);
112
113 let cb = header.cluster_bits();
114 let l1_offset = header.l1_table_offset();
115 let l1_cluster = l1_offset
116 .checked_cluster(cb)
117 .ok_or_else(|| invalid_data("Unaligned L1 table: {l1_offset}"))?;
118
119 let l1_table =
120 L1Table::load(&metadata, &header, l1_cluster, header.l1_table_entries()).await?;
121
122 let metadata = Arc::new(metadata);
123 let caches = Arc::new(MetadataCaches::new(&metadata, &header, 128, 32));
124 let clusters_to_free = Arc::new(ClustersToFreeList::default());
125
126 let allocator = if writable {
127 let allocator = Allocator::new(
128 Arc::clone(&metadata),
129 Arc::clone(&header),
130 Arc::clone(&caches),
131 Arc::clone(&clusters_to_free),
132 )
133 .await?;
134 Some(Mutex::new(allocator))
135 } else {
136 None
137 };
138
139 Ok(Qcow2 {
140 metadata,
141
142 writable,
143
144 storage_set: false,
145 storage: None,
146 backing_set: false,
147 backing: None,
148 storage_open_options,
149
150 header,
151 l1_table: RwLock::new(l1_table),
152
153 caches,
154 allocator,
155 clusters_to_free,
156 })
157 }
158
159 pub async fn open_image(metadata: S, writable: bool) -> io::Result<Self> {
172 Self::do_open(metadata, writable, StorageOpenOptions::new()).await
173 }
174
175 pub async fn open_path<P: AsRef<Path>>(path: P, writable: bool) -> io::Result<Self> {
188 let storage_opts = StorageOpenOptions::new().write(writable).filename(path);
189 let metadata = S::open(storage_opts).await?;
190 Self::do_open(metadata, writable, StorageOpenOptions::new()).await
191 }
192
193 pub fn requires_external_data_file(&self) -> bool {
197 self.header.external_data_file()
198 }
199
200 pub fn implicit_external_data_file(&self) -> Option<&String> {
206 self.header.external_data_filename()
207 }
208
209 pub fn implicit_backing_file(&self) -> Option<&String> {
211 self.header.backing_filename()
212 }
213
214 pub fn implicit_backing_format(&self) -> Option<&String> {
221 self.header.backing_format()
222 }
223
224 pub fn set_data_file(&mut self, file: Option<S>) {
229 self.storage = file;
230 self.storage_set = true;
231 }
232
233 pub fn set_backing(&mut self, backing: Option<F>) {
237 self.backing = backing;
238 self.backing_set = true;
239 }
240
241 fn storage(&self) -> &S {
246 self.storage.as_ref().unwrap_or(&self.metadata)
247 }
248
249 async fn open_implicit_data_file<G: ImplicitOpenGate<S>>(
251 &self,
252 gate: &mut G,
253 ) -> io::Result<Option<S>> {
254 if !self.header.external_data_file() {
255 return Ok(None);
256 }
257
258 let Some(filename) = self.header.external_data_filename() else {
259 return Err(io::Error::other(
260 "Image requires external data file, but no filename given",
261 ));
262 };
263
264 let absolute = self
265 .metadata
266 .resolve_relative_path(filename)
267 .err_context(|| format!("Cannot resolve external data file name {filename}"))?;
268
269 let opts = self
270 .storage_open_options
271 .clone()
272 .write(true)
273 .filename(absolute.clone());
274
275 let file = gate
276 .open_storage(opts)
277 .await
278 .err_context(|| format!("External data file {absolute:?}"))?;
279 Ok(Some(file))
280 }
281
282 async fn open_raw_backing_file<G: ImplicitOpenGate<S>>(
284 &self,
285 file: S,
286 gate: &mut G,
287 ) -> io::Result<F> {
288 let opts = Raw::builder(file).storage_open_options(self.storage_open_options.clone());
289 let raw = gate.open_format(opts).await?;
290 Ok(F::wrap(raw))
291 }
292
293 async fn open_qcow2_backing_file<G: ImplicitOpenGate<S>>(
295 &self,
296 file: S,
297 gate: &mut G,
298 ) -> io::Result<F> {
299 let opts =
300 Qcow2::<S>::builder(file).storage_open_options(self.storage_open_options.clone());
301 #[cfg(feature = "async")]
303 let qcow2 = Box::pin(gate.open_format(opts)).await?;
304 #[cfg(feature = "sync")]
305 let qcow2 = gate.open_format(opts)?;
306 Ok(F::wrap(qcow2))
307 }
308
309 async fn open_implicit_backing_file<G: ImplicitOpenGate<S>>(
313 &self,
314 gate: &mut G,
315 ) -> io::Result<Option<F>> {
316 let Some(filename) = self.header.backing_filename() else {
317 return Ok(None);
318 };
319
320 let absolute = self
321 .metadata
322 .resolve_relative_path(filename)
323 .err_context(|| format!("Cannot resolve backing file name {filename}"))?;
324
325 let file_opts = self
326 .storage_open_options
327 .clone()
328 .filename(absolute.clone())
329 .write(false);
330
331 let file = gate
332 .open_storage(file_opts)
333 .await
334 .err_context(|| format!("Backing file {absolute:?}"))?;
335
336 let result = match self.header.backing_format().map(|f| f.as_str()) {
337 Some("qcow2") => self.open_qcow2_backing_file(file, gate).await.map(Some),
338 Some("raw") | Some("file") => self.open_raw_backing_file(file, gate).await.map(Some),
339
340 Some(fmt) => Err(io::Error::other(format!("Unknown backing format {fmt}"))),
341
342 None => match unsafe { Self::probe(&file) }.await {
346 Ok(true) => self.open_qcow2_backing_file(file, gate).await.map(Some),
347 Ok(false) => self.open_raw_backing_file(file, gate).await.map(Some),
348 Err(err) => Err(err),
349 },
350 };
351
352 result.err_context(|| format!("Backing file {absolute:?}"))
353 }
354
355 pub async fn open_implicit_dependencies_gated<G: ImplicitOpenGate<S>>(
375 &mut self,
376 mut gate: G,
377 ) -> io::Result<()> {
378 if !self.storage_set {
379 self.storage = self.open_implicit_data_file(&mut gate).await?;
380 self.storage_set = true;
381 }
382
383 if !self.backing_set {
384 self.backing = self.open_implicit_backing_file(&mut gate).await?;
385 self.backing_set = true;
386 }
387
388 Ok(())
389 }
390
391 pub async fn open_implicit_dependencies(&mut self) -> io::Result<()> {
399 self.open_implicit_dependencies_gated(PermissiveImplicitOpenGate::default())
400 .await
401 }
402
403 fn need_writable(&self) -> io::Result<()> {
405 self.writable
406 .then_some(())
407 .ok_or_else(|| io::Error::other("Image is read-only"))
408 }
409
410 fn check_disk_bounds<D: Display>(&self, offset: u64, length: u64, req: D) -> io::Result<()> {
412 let size = self.header.size();
413 let length_until_eof = size.saturating_sub(offset);
414 if length_until_eof >= length {
415 Ok(())
416 } else {
417 Err(io::Error::new(
418 io::ErrorKind::UnexpectedEof,
419 format!("Cannot {req} beyond the disk size ({length} + {offset} > {size})"),
420 ))
421 }
422 }
423
424 fn check_valid_preallocation(
428 prealloc_mode: PreallocateMode,
429 with_backing: bool,
430 ) -> io::Result<()> {
431 if !with_backing {
432 return Ok(());
433 }
434
435 match prealloc_mode {
436 PreallocateMode::None | PreallocateMode::Zero => Ok(()),
437
438 PreallocateMode::FormatAllocate
439 | PreallocateMode::FullAllocate
440 | PreallocateMode::WriteData => Err(io::Error::new(
441 io::ErrorKind::Unsupported,
442 "Preallocation is not yet supported for images with a backing file",
443 )),
444 }
445 }
446}
447
448#[maybe_async(?Send)]
449impl<S: Storage, F: WrappedFormat<S>> FormatDriverInstance for Qcow2<S, F> {
450 type Storage = S;
451
452 fn format(&self) -> Format {
453 Format::Qcow2
454 }
455
456 async unsafe fn probe(metadata: &S) -> io::Result<bool>
457 where
458 Self: Sized,
459 {
460 let mut magic_version = [0u8; 8];
461 metadata.read(&mut magic_version[..], 0).await?;
462
463 let magic = u32::from_be_bytes((&magic_version[..4]).try_into().unwrap());
464 let version = u32::from_be_bytes((&magic_version[4..]).try_into().unwrap());
465 Ok(magic == MAGIC && (version == 2 || (version == 3)))
466 }
467
468 fn size(&self) -> u64 {
469 self.header.size()
470 }
471
472 fn zero_granularity(&self) -> Option<u64> {
473 self.header.require_version(3).ok()?;
474 Some(self.header.cluster_size() as u64)
475 }
476
477 fn collect_storage_dependencies(&self) -> Vec<&S> {
478 let mut v = self
479 .backing
480 .as_ref()
481 .map(|b| b.inner().collect_storage_dependencies())
482 .unwrap_or_default();
483
484 v.push(&self.metadata);
485 if let Some(storage) = self.storage.as_ref() {
486 v.push(storage);
487 }
488
489 v
490 }
491
492 fn writable(&self) -> bool {
493 self.writable
494 }
495
496 #[allow(clippy::needless_lifetimes)] async fn get_mapping<'a>(
498 &'a self,
499 offset: u64,
500 max_length: u64,
501 ) -> io::Result<(ShallowMapping<'a, S>, u64)> {
502 let length_until_eof = match self.header.size().checked_sub(offset) {
503 None | Some(0) => return Ok((ShallowMapping::Eof {}, 0)),
504 Some(length) => length,
505 };
506
507 let max_length = cmp::min(max_length, length_until_eof);
508 let offset = GuestOffset(offset);
509 self.do_get_mapping(offset, max_length).await
510 }
511
512 #[allow(clippy::needless_lifetimes)] async fn prepare_data_mapping<'a>(
514 &'a self,
515 offset: u64,
516 length: u64,
517 overwrite: bool,
518 ) -> io::Result<PreparedDataMapping<'a, S>> {
519 self.check_disk_bounds(offset, length, "allocate")?;
520
521 if length == 0 {
522 return Ok(PreparedDataMapping::existing(self.storage(), 0, 0));
523 }
524
525 self.need_writable()?;
526 let (host_offset, length, state) = self
527 .do_prepare_data_mapping(GuestOffset(offset), length, overwrite, false)
528 .await?;
529
530 let pdm = if let Some(state) = state {
531 PreparedDataMapping::to_commit(self.storage(), host_offset, length, Box::new(state))
532 } else {
533 PreparedDataMapping::existing(self.storage(), host_offset, length)
534 };
535 Ok(pdm)
536 }
537
538 async fn commit_data_mapping(&self, mapping: PreparedDataMapping<'_, S>) -> io::Result<()> {
539 let Some(state) = mapping.into_state() else {
540 return Ok(());
542 };
543
544 let state = state
546 .downcast::<PreparedMappingState>()
547 .ok()
548 .filter(|state| state.belongs_to(self))
549 .ok_or_else(|| {
550 io::Error::new(
551 io::ErrorKind::InvalidInput,
552 "Prepared data mapping does not belong to this image",
553 )
554 })?;
555
556 self.do_commit_data_mapping(*state).await;
557 Ok(())
558 }
559
560 async fn ensure_zero_mapping(&self, offset: u64, length: u64) -> io::Result<(u64, u64)> {
561 self.need_writable()?;
562 self.check_disk_bounds(offset, length, "write")?;
563
564 self.ensure_fixed_mapping(
565 GuestOffset(offset),
566 length,
567 FixedMapping::ZeroRetainAllocation,
568 )
569 .await
570 .map(|(ofs, len)| (ofs.0, len))
571 }
572
573 async unsafe fn discard_to_zero_unsafe(
574 &self,
575 offset: u64,
576 length: u64,
577 ) -> io::Result<(u64, u64)> {
578 self.need_writable()?;
579 self.check_disk_bounds(offset, length, "discard")?;
580
581 self.ensure_fixed_mapping(GuestOffset(offset), length, FixedMapping::ZeroDiscard)
585 .await
586 .map(|(ofs, len)| (ofs.0, len))
587 }
588
589 async unsafe fn discard_to_any_unsafe(
590 &self,
591 offset: u64,
592 length: u64,
593 ) -> io::Result<(u64, u64)> {
594 unsafe { self.discard_to_zero_unsafe(offset, length).await }
596 }
597
598 async unsafe fn discard_to_backing_unsafe(
599 &self,
600 offset: u64,
601 length: u64,
602 ) -> io::Result<(u64, u64)> {
603 self.need_writable()?;
604 self.check_disk_bounds(offset, length, "discard")?;
605
606 self.ensure_fixed_mapping(GuestOffset(offset), length, FixedMapping::FullDiscard)
608 .await
609 .map(|(ofs, len)| (ofs.0, len))
610 }
611
612 async fn readv_special(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
613 match self.do_readv_special(bufv, GuestOffset(offset)).await? {
614 None => Ok(()),
615 Some((_, tail_offset)) => Err(io::Error::other(format!(
616 "Range at {tail_offset:#x} is not compressed (anymore)"
617 ))),
618 }
619 }
620
621 async fn try_readv_special<'a>(
622 &self,
623 bufv: IoVectorMut<'a>,
624 offset: u64,
625 ) -> io::Result<Option<(IoVectorMut<'a>, u64)>> {
626 self.do_readv_special(bufv, GuestOffset(offset)).await
627 }
628
629 async fn flush(&self) -> io::Result<()> {
630 self.process_clusters_to_free().await;
632 self.caches.flush_all().await?;
633 self.metadata.flush().await?;
634 if let Some(storage) = self.storage.as_ref() {
635 storage.flush().await?;
636 }
637 Ok(())
639 }
640
641 async fn sync(&self) -> io::Result<()> {
642 self.metadata.sync().await?;
643 if let Some(storage) = self.storage.as_ref() {
644 storage.sync().await?;
645 }
646 Ok(())
648 }
649
650 async unsafe fn invalidate_cache(&self) -> io::Result<()> {
651 self.clusters_to_free.take();
655
656 unsafe { self.caches.invalidate_l2() }.await?;
658 if let Some(allocator) = self.allocator.as_ref() {
659 let allocator = allocator.lock().await;
660 unsafe { allocator.invalidate_rb_cache() }.await?;
662 }
663
664 unsafe { self.metadata.invalidate_cache() }.await?;
666 if let Some(storage) = self.storage.as_ref() {
667 unsafe { storage.invalidate_cache() }.await?;
669 }
670 if let Some(backing) = self.backing.as_ref() {
671 unsafe { backing.inner().invalidate_cache() }.await?;
673 }
674
675 let new_header = Header::load(self.metadata.as_ref(), false).await?;
681 self.header.update(&new_header)?;
682
683 if let Some(allocator) = self.allocator.as_ref() {
684 *allocator.lock().await = Allocator::new(
685 Arc::clone(&self.metadata),
686 Arc::clone(&self.header),
687 Arc::clone(&self.caches),
688 Arc::clone(&self.clusters_to_free),
689 )
690 .await?;
691 }
692
693 let l1_cluster = self
695 .header
696 .l1_table_offset()
697 .cluster(self.header.cluster_bits());
698
699 *self.l1_table.write().await = L1Table::load(
700 self.metadata.as_ref(),
701 &self.header,
702 l1_cluster,
703 self.header.l1_table_entries(),
704 )
705 .await?;
706
707 Ok(())
708 }
709
710 async fn resize_grow(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
711 self.need_writable()?;
712
713 let old_size = self.size();
714 let grown_length = new_size.saturating_sub(old_size);
715 if grown_length == 0 {
716 return Ok(()); }
718
719 Self::check_valid_preallocation(prealloc_mode, self.backing.is_some())?;
720
721 if let Some(data_file) = self.storage.as_ref() {
722 match prealloc_mode {
725 PreallocateMode::None => {
726 data_file
727 .resize(new_size, storage::PreallocateMode::None)
728 .await?;
729 }
730 PreallocateMode::Zero => {
731 data_file
732 .resize(new_size, storage::PreallocateMode::Zero)
733 .await?;
734 }
735 PreallocateMode::FormatAllocate
736 | PreallocateMode::FullAllocate
737 | PreallocateMode::WriteData => (),
738 }
739 }
740
741 {
747 let l1_locked = self.l1_table.write().await;
748 let l1_index =
749 GuestOffset(new_size.saturating_sub(1)).l1_index(self.header.cluster_bits());
750 let _l1_locked = self.grow_l1_table(l1_locked, l1_index).await?;
751 }
752
753 match prealloc_mode {
755 PreallocateMode::None => (),
756 PreallocateMode::Zero => self.preallocate_zero(old_size, grown_length).await?,
757 PreallocateMode::FormatAllocate => {
758 self.preallocate(old_size, grown_length, storage::PreallocateMode::Zero)
759 .await?;
760 }
761 PreallocateMode::FullAllocate => {
762 self.preallocate(old_size, grown_length, storage::PreallocateMode::Allocate)
763 .await?;
764 }
765 PreallocateMode::WriteData => {
766 self.preallocate(old_size, grown_length, storage::PreallocateMode::WriteData)
767 .await?
768 }
769 }
770
771 self.header.set_size(new_size);
775 self.header
776 .write_size(self.metadata.as_ref())
777 .await
778 .inspect_err(|_| {
779 self.header.set_size(old_size)
781 })
782 }
783
784 async fn resize_shrink(&mut self, new_size: u64) -> io::Result<()> {
785 self.need_writable()?;
786
787 let old_size = self.size();
788 if new_size >= old_size {
789 return Ok(()); }
791
792 if let Some(data_file) = self.storage.as_ref() {
793 data_file
794 .resize(new_size, storage::PreallocateMode::None)
795 .await?;
796 }
797
798 let mut offset = new_size;
799 while offset < old_size {
800 match self.discard_to_backing(offset, old_size - offset).await {
801 Ok((_, 0)) => break, Ok((dofs, dlen)) => offset = dofs + dlen,
803 Err(_) => break,
805 }
806 }
807
808 self.header.set_size(new_size);
810
811 self.header
813 .write_size(self.metadata.as_ref())
814 .await
815 .inspect_err(|_| {
816 self.header.set_size(old_size);
818 })
819 }
820}
821
822impl<S: Storage + 'static, F: WrappedFormat<S>> Debug for Qcow2<S, F> {
823 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
824 f.debug_struct("Qcow2")
825 .field("metadata", &self.metadata)
826 .field("storage_set", &self.storage_set)
827 .field("storage", &self.storage)
828 .field("backing_set", &self.backing_set)
829 .field("backing", &self.backing)
830 .finish()
831 }
832}
833
834impl<S: Storage + 'static, F: WrappedFormat<S>> Display for Qcow2<S, F> {
835 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
836 write!(f, "qcow2[{}]", self.metadata)
837 }
838}