1mod 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#[must_use = "qcow2 images must be flushed before closing"]
47pub struct Qcow2<S: Storage + 'static, F: WrappedFormat<S> + 'static = FormatAccess<S>> {
48 metadata: Arc<S>,
50
51 writable: bool,
53
54 storage_set: bool,
56 storage: Option<S>,
58 backing_set: bool,
60 backing: Option<F>,
62 storage_open_options: StorageOpenOptions,
64
65 header: Arc<Header>,
67 l1_table: RwLock<L1Table>,
69
70 l2_cache: AsyncLruCache<HostCluster, L2Table, L2CacheBackend<S>>,
72
73 allocator: Option<Mutex<Allocator<S>>>,
77}
78
79impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F> {
80 pub fn builder(image: S) -> Qcow2OpenBuilder<S, F> {
82 Qcow2OpenBuilder::new(image)
83 }
84
85 pub fn builder_path<P: AsRef<Path>>(image_path: P) -> Qcow2OpenBuilder<S, F> {
87 Qcow2OpenBuilder::new_path(image_path)
88 }
89
90 pub fn create_builder(image: S) -> Qcow2CreateBuilder<S, F> {
92 Qcow2CreateBuilder::<S, F>::new(image)
93 }
94
95 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 pub async fn open_image(metadata: S, writable: bool) -> io::Result<Self> {
158 Self::do_open(metadata, writable, StorageOpenOptions::new()).await
159 }
160
161 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 pub fn requires_external_data_file(&self) -> bool {
183 self.header.external_data_file()
184 }
185
186 pub fn implicit_external_data_file(&self) -> Option<&String> {
192 self.header.external_data_filename()
193 }
194
195 pub fn implicit_backing_file(&self) -> Option<&String> {
197 self.header.backing_filename()
198 }
199
200 pub fn implicit_backing_format(&self) -> Option<&String> {
207 self.header.backing_format()
208 }
209
210 pub fn set_data_file(&mut self, file: Option<S>) {
215 self.storage = file;
216 self.storage_set = true;
217 }
218
219 pub fn set_backing(&mut self, backing: Option<F>) {
223 self.backing = backing;
224 self.backing_set = true;
225 }
226
227 fn storage(&self) -> &S {
232 self.storage.as_ref().unwrap_or(&self.metadata)
233 }
234
235 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 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 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 let qcow2 = Box::pin(gate.open_format(opts)).await?;
289 Ok(F::wrap(qcow2))
290 }
291
292 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 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 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 pub async fn open_implicit_dependencies(&mut self) -> io::Result<()> {
382 self.open_implicit_dependencies_gated(PermissiveImplicitOpenGate::default())
383 .await
384 }
385
386 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 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 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 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 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 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 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 Ok(())
590 }
591
592 async unsafe fn invalidate_cache(&self) -> io::Result<()> {
593 unsafe { self.l2_cache.invalidate() }.await?;
595 if let Some(allocator) = self.allocator.as_ref() {
596 let allocator = allocator.lock().await;
597 unsafe { allocator.invalidate_rb_cache() }.await?;
599 }
600
601 unsafe { self.metadata.invalidate_cache() }.await?;
603 if let Some(storage) = self.storage.as_ref() {
604 unsafe { storage.invalidate_cache() }.await?;
606 }
607 if let Some(backing) = self.backing.as_ref() {
608 unsafe { backing.inner().invalidate_cache() }.await?;
610 }
611
612 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 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(()); }
650
651 Self::check_valid_preallocation(prealloc_mode, self.backing.is_some())?;
652
653 if let Some(data_file) = self.storage.as_ref() {
654 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 {
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 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 self.header.set_size(new_size);
707 self.header
708 .write_size(self.metadata.as_ref())
709 .await
710 .inspect_err(|_| {
711 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(()); }
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, Ok((dofs, dlen)) => offset = dofs + dlen,
735 Err(_) => break,
737 }
738 }
739
740 self.header.set_size(new_size);
742
743 self.header
745 .write_size(self.metadata.as_ref())
746 .await
747 .inspect_err(|_| {
748 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}