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::sync_primitives::{Mutex, RwLock};
26use crate::{storage, FormatAccess, ShallowMapping, Storage, StorageExt, StorageOpenOptions};
27use allocation::Allocator;
28pub use builder::{Qcow2CreateBuilder, Qcow2OpenBuilder};
29use cache::MetadataCaches;
30use mappings::FixedMapping;
31use maybe_async::maybe_async;
32use metadata::*;
33use std::fmt::{self, Debug, Display, Formatter};
34use std::ops::Range;
35use std::path::Path;
36use std::sync::Arc;
37use std::{cmp, io};
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 caches: Arc<MetadataCaches<S>>,
72
73 allocator: Option<Mutex<Allocator<S>>>,
77}
78
79#[maybe_async]
80impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F> {
81 pub fn builder(image: S) -> Qcow2OpenBuilder<S, F> {
83 Qcow2OpenBuilder::new(image)
84 }
85
86 pub fn builder_path<P: AsRef<Path>>(image_path: P) -> Qcow2OpenBuilder<S, F> {
88 Qcow2OpenBuilder::new_path(image_path)
89 }
90
91 pub fn create_builder(image: S) -> Qcow2CreateBuilder<S, F> {
93 Qcow2CreateBuilder::<S, F>::new(image)
94 }
95
96 async fn do_open(
100 metadata: S,
101 writable: bool,
102 storage_open_options: StorageOpenOptions,
103 ) -> io::Result<Self> {
104 let header = Arc::new(Header::load(&metadata, writable).await?);
105
106 let cb = header.cluster_bits();
107 let l1_offset = header.l1_table_offset();
108 let l1_cluster = l1_offset
109 .checked_cluster(cb)
110 .ok_or_else(|| invalid_data("Unaligned L1 table: {l1_offset}"))?;
111
112 let l1_table =
113 L1Table::load(&metadata, &header, l1_cluster, header.l1_table_entries()).await?;
114
115 let metadata = Arc::new(metadata);
116 let caches = Arc::new(MetadataCaches::new(&metadata, &header, 128, 32));
117
118 let allocator = if writable {
119 let allocator = Allocator::new(
120 Arc::clone(&metadata),
121 Arc::clone(&header),
122 Arc::clone(&caches),
123 )
124 .await?;
125 Some(Mutex::new(allocator))
126 } else {
127 None
128 };
129
130 Ok(Qcow2 {
131 metadata,
132
133 writable,
134
135 storage_set: false,
136 storage: None,
137 backing_set: false,
138 backing: None,
139 storage_open_options,
140
141 header,
142 l1_table: RwLock::new(l1_table),
143
144 caches,
145 allocator,
146 })
147 }
148
149 pub async fn open_image(metadata: S, writable: bool) -> io::Result<Self> {
162 Self::do_open(metadata, writable, StorageOpenOptions::new()).await
163 }
164
165 pub async fn open_path<P: AsRef<Path>>(path: P, writable: bool) -> io::Result<Self> {
178 let storage_opts = StorageOpenOptions::new().write(writable).filename(path);
179 let metadata = S::open(storage_opts).await?;
180 Self::do_open(metadata, writable, StorageOpenOptions::new()).await
181 }
182
183 pub fn requires_external_data_file(&self) -> bool {
187 self.header.external_data_file()
188 }
189
190 pub fn implicit_external_data_file(&self) -> Option<&String> {
196 self.header.external_data_filename()
197 }
198
199 pub fn implicit_backing_file(&self) -> Option<&String> {
201 self.header.backing_filename()
202 }
203
204 pub fn implicit_backing_format(&self) -> Option<&String> {
211 self.header.backing_format()
212 }
213
214 pub fn set_data_file(&mut self, file: Option<S>) {
219 self.storage = file;
220 self.storage_set = true;
221 }
222
223 pub fn set_backing(&mut self, backing: Option<F>) {
227 self.backing = backing;
228 self.backing_set = true;
229 }
230
231 fn storage(&self) -> &S {
236 self.storage.as_ref().unwrap_or(&self.metadata)
237 }
238
239 async fn open_implicit_data_file<G: ImplicitOpenGate<S>>(
241 &self,
242 gate: &mut G,
243 ) -> io::Result<Option<S>> {
244 if !self.header.external_data_file() {
245 return Ok(None);
246 }
247
248 let Some(filename) = self.header.external_data_filename() else {
249 return Err(io::Error::other(
250 "Image requires external data file, but no filename given",
251 ));
252 };
253
254 let absolute = self
255 .metadata
256 .resolve_relative_path(filename)
257 .err_context(|| format!("Cannot resolve external data file name {filename}"))?;
258
259 let opts = self
260 .storage_open_options
261 .clone()
262 .write(true)
263 .filename(absolute.clone());
264
265 let file = gate
266 .open_storage(opts)
267 .await
268 .err_context(|| format!("External data file {absolute:?}"))?;
269 Ok(Some(file))
270 }
271
272 async fn open_raw_backing_file<G: ImplicitOpenGate<S>>(
274 &self,
275 file: S,
276 gate: &mut G,
277 ) -> io::Result<F> {
278 let opts = Raw::builder(file).storage_open_options(self.storage_open_options.clone());
279 let raw = gate.open_format(opts).await?;
280 Ok(F::wrap(raw))
281 }
282
283 async fn open_qcow2_backing_file<G: ImplicitOpenGate<S>>(
285 &self,
286 file: S,
287 gate: &mut G,
288 ) -> io::Result<F> {
289 let opts =
290 Qcow2::<S>::builder(file).storage_open_options(self.storage_open_options.clone());
291 #[cfg(feature = "async")]
293 let qcow2 = Box::pin(gate.open_format(opts)).await?;
294 #[cfg(feature = "sync")]
295 let qcow2 = gate.open_format(opts)?;
296 Ok(F::wrap(qcow2))
297 }
298
299 async fn open_implicit_backing_file<G: ImplicitOpenGate<S>>(
303 &self,
304 gate: &mut G,
305 ) -> io::Result<Option<F>> {
306 let Some(filename) = self.header.backing_filename() else {
307 return Ok(None);
308 };
309
310 let absolute = self
311 .metadata
312 .resolve_relative_path(filename)
313 .err_context(|| format!("Cannot resolve backing file name {filename}"))?;
314
315 let file_opts = self
316 .storage_open_options
317 .clone()
318 .filename(absolute.clone())
319 .write(false);
320
321 let file = gate
322 .open_storage(file_opts)
323 .await
324 .err_context(|| format!("Backing file {absolute:?}"))?;
325
326 let result = match self.header.backing_format().map(|f| f.as_str()) {
327 Some("qcow2") => self.open_qcow2_backing_file(file, gate).await.map(Some),
328 Some("raw") | Some("file") => self.open_raw_backing_file(file, gate).await.map(Some),
329
330 Some(fmt) => Err(io::Error::other(format!("Unknown backing format {fmt}"))),
331
332 None => match unsafe { Self::probe(&file) }.await {
336 Ok(true) => self.open_qcow2_backing_file(file, gate).await.map(Some),
337 Ok(false) => self.open_raw_backing_file(file, gate).await.map(Some),
338 Err(err) => Err(err),
339 },
340 };
341
342 result.err_context(|| format!("Backing file {absolute:?}"))
343 }
344
345 pub async fn open_implicit_dependencies_gated<G: ImplicitOpenGate<S>>(
365 &mut self,
366 mut gate: G,
367 ) -> io::Result<()> {
368 if !self.storage_set {
369 self.storage = self.open_implicit_data_file(&mut gate).await?;
370 self.storage_set = true;
371 }
372
373 if !self.backing_set {
374 self.backing = self.open_implicit_backing_file(&mut gate).await?;
375 self.backing_set = true;
376 }
377
378 Ok(())
379 }
380
381 pub async fn open_implicit_dependencies(&mut self) -> io::Result<()> {
389 self.open_implicit_dependencies_gated(PermissiveImplicitOpenGate::default())
390 .await
391 }
392
393 fn need_writable(&self) -> io::Result<()> {
395 self.writable
396 .then_some(())
397 .ok_or_else(|| io::Error::other("Image is read-only"))
398 }
399
400 fn check_disk_bounds<D: Display>(&self, length: u64, offset: u64, req: D) -> io::Result<()> {
402 let size = self.header.size();
403 let length_until_eof = size.saturating_sub(offset);
404 if length_until_eof >= length {
405 Ok(())
406 } else {
407 Err(io::Error::new(
408 io::ErrorKind::UnexpectedEof,
409 format!("Cannot {req} beyond the disk size ({length} + {offset} > {size}"),
410 ))
411 }
412 }
413
414 fn check_valid_preallocation(
418 prealloc_mode: PreallocateMode,
419 with_backing: bool,
420 ) -> io::Result<()> {
421 if !with_backing {
422 return Ok(());
423 }
424
425 match prealloc_mode {
426 PreallocateMode::None | PreallocateMode::Zero => Ok(()),
427
428 PreallocateMode::FormatAllocate
429 | PreallocateMode::FullAllocate
430 | PreallocateMode::WriteData => Err(io::Error::new(
431 io::ErrorKind::Unsupported,
432 "Preallocation is not yet supported for images with a backing file",
433 )),
434 }
435 }
436}
437
438#[maybe_async(?Send)]
439impl<S: Storage, F: WrappedFormat<S>> FormatDriverInstance for Qcow2<S, F> {
440 type Storage = S;
441
442 fn format(&self) -> Format {
443 Format::Qcow2
444 }
445
446 async unsafe fn probe(metadata: &S) -> io::Result<bool>
447 where
448 Self: Sized,
449 {
450 let mut magic_version = [0u8; 8];
451 metadata.read(&mut magic_version[..], 0).await?;
452
453 let magic = u32::from_be_bytes((&magic_version[..4]).try_into().unwrap());
454 let version = u32::from_be_bytes((&magic_version[4..]).try_into().unwrap());
455 Ok(magic == MAGIC && (version == 2 || (version == 3)))
456 }
457
458 fn size(&self) -> u64 {
459 self.header.size()
460 }
461
462 fn zero_granularity(&self) -> Option<u64> {
463 self.header.require_version(3).ok()?;
464 Some(self.header.cluster_size() as u64)
465 }
466
467 fn collect_storage_dependencies(&self) -> Vec<&S> {
468 let mut v = self
469 .backing
470 .as_ref()
471 .map(|b| b.inner().collect_storage_dependencies())
472 .unwrap_or_default();
473
474 v.push(&self.metadata);
475 if let Some(storage) = self.storage.as_ref() {
476 v.push(storage);
477 }
478
479 v
480 }
481
482 fn writable(&self) -> bool {
483 self.writable
484 }
485
486 #[allow(clippy::needless_lifetimes)] async fn get_mapping<'a>(
488 &'a self,
489 offset: u64,
490 max_length: u64,
491 ) -> io::Result<(ShallowMapping<'a, S>, u64)> {
492 let length_until_eof = match self.header.size().checked_sub(offset) {
493 None | Some(0) => return Ok((ShallowMapping::Eof {}, 0)),
494 Some(length) => length,
495 };
496
497 let max_length = cmp::min(max_length, length_until_eof);
498 let offset = GuestOffset(offset);
499 self.do_get_mapping(offset, max_length).await
500 }
501
502 #[allow(clippy::needless_lifetimes)] async fn ensure_data_mapping<'a>(
504 &'a self,
505 offset: u64,
506 length: u64,
507 overwrite: bool,
508 ) -> io::Result<(&'a S, u64, u64)> {
509 self.check_disk_bounds(offset, length, "allocate")?;
510
511 if length == 0 {
512 return Ok((self.storage(), 0, 0));
513 }
514
515 self.need_writable()?;
516 let offset = GuestOffset(offset);
517 self.do_ensure_data_mapping(offset, length, overwrite, false)
518 .await
519 }
520
521 async fn ensure_zero_mapping(&self, offset: u64, length: u64) -> io::Result<(u64, u64)> {
522 self.need_writable()?;
523 self.check_disk_bounds(offset, length, "write")?;
524
525 self.ensure_fixed_mapping(
526 GuestOffset(offset),
527 length,
528 FixedMapping::ZeroRetainAllocation,
529 )
530 .await
531 .map(|(ofs, len)| (ofs.0, len))
532 }
533
534 async unsafe fn discard_to_zero_unsafe(
535 &self,
536 offset: u64,
537 length: u64,
538 ) -> io::Result<(u64, u64)> {
539 self.need_writable()?;
540 self.check_disk_bounds(offset, length, "discard")?;
541
542 self.ensure_fixed_mapping(GuestOffset(offset), length, FixedMapping::ZeroDiscard)
546 .await
547 .map(|(ofs, len)| (ofs.0, len))
548 }
549
550 async unsafe fn discard_to_any_unsafe(
551 &self,
552 offset: u64,
553 length: u64,
554 ) -> io::Result<(u64, u64)> {
555 unsafe { self.discard_to_zero_unsafe(offset, length).await }
557 }
558
559 async unsafe fn discard_to_backing_unsafe(
560 &self,
561 offset: u64,
562 length: u64,
563 ) -> io::Result<(u64, u64)> {
564 self.need_writable()?;
565 self.check_disk_bounds(offset, length, "discard")?;
566
567 self.ensure_fixed_mapping(GuestOffset(offset), length, FixedMapping::FullDiscard)
569 .await
570 .map(|(ofs, len)| (ofs.0, len))
571 }
572
573 async fn readv_special(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
574 let offset = GuestOffset(offset);
575 self.do_readv_special(bufv, offset).await
576 }
577
578 async fn flush(&self) -> io::Result<()> {
579 self.caches.flush_all().await?;
580 self.metadata.flush().await?;
581 if let Some(storage) = self.storage.as_ref() {
582 storage.flush().await?;
583 }
584 Ok(())
586 }
587
588 async fn sync(&self) -> io::Result<()> {
589 self.metadata.sync().await?;
590 if let Some(storage) = self.storage.as_ref() {
591 storage.sync().await?;
592 }
593 Ok(())
595 }
596
597 async unsafe fn invalidate_cache(&self) -> io::Result<()> {
598 unsafe { self.caches.invalidate_l2() }.await?;
600 if let Some(allocator) = self.allocator.as_ref() {
601 let allocator = allocator.lock().await;
602 unsafe { allocator.invalidate_rb_cache() }.await?;
604 }
605
606 unsafe { self.metadata.invalidate_cache() }.await?;
608 if let Some(storage) = self.storage.as_ref() {
609 unsafe { storage.invalidate_cache() }.await?;
611 }
612 if let Some(backing) = self.backing.as_ref() {
613 unsafe { backing.inner().invalidate_cache() }.await?;
615 }
616
617 let new_header = Header::load(self.metadata.as_ref(), false).await?;
623 self.header.update(&new_header)?;
624
625 if let Some(allocator) = self.allocator.as_ref() {
626 *allocator.lock().await = Allocator::new(
627 Arc::clone(&self.metadata),
628 Arc::clone(&self.header),
629 Arc::clone(&self.caches),
630 )
631 .await?;
632 }
633
634 let l1_cluster = self
636 .header
637 .l1_table_offset()
638 .cluster(self.header.cluster_bits());
639
640 *self.l1_table.write().await = L1Table::load(
641 self.metadata.as_ref(),
642 &self.header,
643 l1_cluster,
644 self.header.l1_table_entries(),
645 )
646 .await?;
647
648 Ok(())
649 }
650
651 async fn resize_grow(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
652 self.need_writable()?;
653
654 let old_size = self.size();
655 let grown_length = new_size.saturating_sub(old_size);
656 if grown_length == 0 {
657 return Ok(()); }
659
660 Self::check_valid_preallocation(prealloc_mode, self.backing.is_some())?;
661
662 if let Some(data_file) = self.storage.as_ref() {
663 match prealloc_mode {
666 PreallocateMode::None => {
667 data_file
668 .resize(new_size, storage::PreallocateMode::None)
669 .await?;
670 }
671 PreallocateMode::Zero => {
672 data_file
673 .resize(new_size, storage::PreallocateMode::Zero)
674 .await?;
675 }
676 PreallocateMode::FormatAllocate
677 | PreallocateMode::FullAllocate
678 | PreallocateMode::WriteData => (),
679 }
680 }
681
682 {
688 let l1_locked = self.l1_table.write().await;
689 let l1_index =
690 GuestOffset(new_size.saturating_sub(1)).l1_index(self.header.cluster_bits());
691 let _l1_locked = self.grow_l1_table(l1_locked, l1_index).await?;
692 }
693
694 match prealloc_mode {
696 PreallocateMode::None => (),
697 PreallocateMode::Zero => self.preallocate_zero(old_size, grown_length).await?,
698 PreallocateMode::FormatAllocate => {
699 self.preallocate(old_size, grown_length, storage::PreallocateMode::Zero)
700 .await?;
701 }
702 PreallocateMode::FullAllocate => {
703 self.preallocate(old_size, grown_length, storage::PreallocateMode::Allocate)
704 .await?;
705 }
706 PreallocateMode::WriteData => {
707 self.preallocate(old_size, grown_length, storage::PreallocateMode::WriteData)
708 .await?
709 }
710 }
711
712 self.header.set_size(new_size);
716 self.header
717 .write_size(self.metadata.as_ref())
718 .await
719 .inspect_err(|_| {
720 self.header.set_size(old_size)
722 })
723 }
724
725 async fn resize_shrink(&mut self, new_size: u64) -> io::Result<()> {
726 self.need_writable()?;
727
728 let old_size = self.size();
729 if new_size >= old_size {
730 return Ok(()); }
732
733 if let Some(data_file) = self.storage.as_ref() {
734 data_file
735 .resize(new_size, storage::PreallocateMode::None)
736 .await?;
737 }
738
739 let mut offset = new_size;
740 while offset < old_size {
741 match self.discard_to_backing(offset, old_size - offset).await {
742 Ok((_, 0)) => break, Ok((dofs, dlen)) => offset = dofs + dlen,
744 Err(_) => break,
746 }
747 }
748
749 self.header.set_size(new_size);
751
752 self.header
754 .write_size(self.metadata.as_ref())
755 .await
756 .inspect_err(|_| {
757 self.header.set_size(old_size);
759 })
760 }
761}
762
763impl<S: Storage + 'static, F: WrappedFormat<S>> Debug for Qcow2<S, F> {
764 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
765 f.debug_struct("Qcow2")
766 .field("metadata", &self.metadata)
767 .field("storage_set", &self.storage_set)
768 .field("storage", &self.storage)
769 .field("backing_set", &self.backing_set)
770 .field("backing", &self.backing)
771 .finish()
772 }
773}
774
775impl<S: Storage + 'static, F: WrappedFormat<S>> Display for Qcow2<S, F> {
776 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
777 write!(f, "qcow2[{}]", self.metadata)
778 }
779}