1use super::allocation::{ClustersToFreeEntry, PendingClusters};
4use super::compressed::CompressedClusterReadGuard;
5use super::types::*;
6use crate::io_buffers::IoBuffer;
7use crate::macros::numerical_enum;
8use crate::macros::on_disk_struct::{on_disk_struct, OnDiskStruct};
9use crate::misc_helpers::{invalid_data, DropGuard};
10use crate::sync_primitives::{Mutex, MutexGuard, OwnedRwLock, OwnedRwLockWriteGuard};
11use crate::{Storage, StorageExt};
12use maybe_async::maybe_async;
13use std::collections::HashMap;
14use std::mem::size_of;
15use std::num::{NonZero, TryFromIntError};
16use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, AtomicU64, AtomicU8, Ordering};
17use std::sync::Arc;
18use std::{cmp, io};
19use tracing::error;
20
21pub(super) const MAGIC: u32 = 0x51_46_49_fb;
23
24const MAX_FILE_LENGTH: u64 = 0x0100_0000_0000_0000u64;
26
27pub(super) const MAX_OFFSET: HostOffset = HostOffset(MAX_FILE_LENGTH - 512);
29
30pub(super) const MIN_CLUSTER_SIZE: usize = 512;
34
35pub(super) const MAX_CLUSTER_SIZE: usize = 2 * 1024 * 1024;
39
40pub(super) const MIN_REFCOUNT_WIDTH: usize = 1;
42
43pub(super) const MAX_REFCOUNT_WIDTH: usize = 64;
45
46on_disk_struct! {
47struct V2Header/BE, no_gaps {
49 magic: u32[0],
51
52 version: u32[4],
54
55 backing_file_offset: u64[8],
61
62 backing_file_size: u32[16],
65
66 cluster_bits: u32[20],
75
76 size: AtomicU64[24],
84
85 crypt_method: u32[32],
91
92 l1_size: AtomicU32[36],
94
95 l1_table_offset: AtomicU64[40],
98
99 refcount_table_offset: AtomicU64[48],
102
103 refcount_table_clusters: AtomicU32[56],
105
106 nb_snapshots: u32[60],
108
109 snapshots_offset: u64[64],
112}
113}
114
115on_disk_struct! {
116struct V3HeaderBase/BE, no_gaps {
118 incompatible_features: u64[0],
139
140 compatible_features: u64[8],
148
149 autoclear_features: u64[16],
165
166 refcount_order: u32[24],
170
171 header_length: u32[28],
174}
175}
176
177impl Default for V3HeaderBase {
178 fn default() -> Self {
179 V3HeaderBase {
180 incompatible_features: 0,
181 compatible_features: 0,
182 autoclear_features: 0,
183 refcount_order: 4,
184 header_length: (V2Header::ON_DISK_SIZE + V3HeaderBase::ON_DISK_SIZE) as u32,
185 }
186 }
187}
188
189numerical_enum! {
190 pub(super) enum IncompatibleFeatures as u64 {
192 Dirty = 1 << 0,
193 Corrupt = 1 << 1,
194 ExternalDataFile = 1 << 2,
195 CompressionType = 1 << 3,
196 ExtendedL2Entries = 1 << 4,
197 }
198}
199
200impl From<IncompatibleFeatures> for (FeatureType, u8) {
201 fn from(feat: IncompatibleFeatures) -> (FeatureType, u8) {
203 assert!((feat as u64).is_power_of_two());
204 (
205 FeatureType::Incompatible,
206 (feat as u64).trailing_zeros() as u8,
207 )
208 }
209}
210
211numerical_enum! {
212 pub(super) enum CompatibleFeatures as u64 {
214 LazyRefcounts = 1 << 0,
215 }
216}
217
218impl From<CompatibleFeatures> for (FeatureType, u8) {
219 fn from(feat: CompatibleFeatures) -> (FeatureType, u8) {
221 assert!((feat as u64).is_power_of_two());
222 (
223 FeatureType::Compatible,
224 (feat as u64).trailing_zeros() as u8,
225 )
226 }
227}
228
229numerical_enum! {
230 pub(super) enum AutoclearFeatures as u64 {
232 Bitmaps = 1 << 0,
233 RawExternalData = 1 << 1,
234 }
235}
236
237impl From<AutoclearFeatures> for (FeatureType, u8) {
238 fn from(feat: AutoclearFeatures) -> (FeatureType, u8) {
240 assert!((feat as u64).is_power_of_two());
241 (FeatureType::Autoclear, (feat as u64).trailing_zeros() as u8)
242 }
243}
244
245numerical_enum! {
246 pub(super) enum HeaderExtensionType as u32 {
248 End = 0,
250
251 BackingFileFormat = 0xe2792aca,
253
254 FeatureNameTable = 0x6803f857,
256
257 ExternalDataFileName = 0x44415441,
259 }
260}
261
262on_disk_struct! {
263#[derive(Default)]
265struct HeaderExtensionHeader/BE, no_gaps {
266 extension_type: u32[0],
268
269 length: u32[4],
271}
272}
273
274numerical_enum! {
275 #[derive(Hash)]
277 pub(super) enum FeatureType as u8 {
278 Incompatible = 0,
279 Compatible = 1,
280 Autoclear = 2,
281 }
282}
283
284#[derive(Debug, Clone, Eq, PartialEq)]
286pub(super) enum HeaderExtension {
287 BackingFileFormat(String),
289
290 FeatureNameTable(HashMap<(FeatureType, u8), String>),
292
293 ExternalDataFileName(String),
295
296 Unknown {
298 extension_type: u32,
300 data: Vec<u8>,
302 },
303}
304
305pub(super) struct Header {
307 v2: V2Header,
309
310 v3: V3HeaderBase,
312
313 unknown_header_fields: Vec<u8>,
315
316 backing_filename: Option<String>,
318
319 extensions: Vec<HeaderExtension>,
321
322 external_data_file: bool,
324}
325
326#[maybe_async]
327impl Header {
328 pub async fn load<S: Storage>(image: &S, writable: bool) -> io::Result<Self> {
332 let mut header_buf = vec![0u8; V2Header::ON_DISK_SIZE];
334 image.read(header_buf.as_mut_slice(), 0).await?;
335
336 let header: V2Header = decode_binary(&header_buf)?;
337 if header.magic != MAGIC {
338 return Err(invalid_data("Not a qcow2 file"));
339 }
340
341 let v3header_base = if header.version == 2 {
342 V3HeaderBase::default()
343 } else if header.version == 3 {
344 let mut header_buf = vec![0u8; V3HeaderBase::ON_DISK_SIZE];
345 image
346 .read(header_buf.as_mut_slice(), V2Header::ON_DISK_SIZE as u64)
347 .await?;
348 decode_binary(&header_buf)?
349 } else {
350 return Err(invalid_data(format!(
351 "qcow2 v{} is not supported",
352 header.version
353 )));
354 };
355
356 let cluster_size = 1usize.checked_shl(header.cluster_bits).ok_or_else(|| {
357 invalid_data(format!("Invalid cluster size: 2^{}", header.cluster_bits))
358 })?;
359 if !(MIN_CLUSTER_SIZE..=MAX_CLUSTER_SIZE).contains(&cluster_size) {
360 return Err(invalid_data(format!(
361 "Invalid cluster size: {cluster_size}; must be between {MIN_CLUSTER_SIZE} and {MAX_CLUSTER_SIZE}",
362 )));
363 }
364
365 let min_header_size = V2Header::ON_DISK_SIZE + V3HeaderBase::ON_DISK_SIZE;
366 if (v3header_base.header_length as usize) < min_header_size {
367 return Err(invalid_data(format!(
368 "qcow2 header too short: {} < {min_header_size}",
369 v3header_base.header_length,
370 )));
371 } else if (v3header_base.header_length as usize) > cluster_size {
372 return Err(invalid_data(format!(
373 "qcow2 header too big: {} > {cluster_size}",
374 v3header_base.header_length,
375 )));
376 }
377
378 let unknown_header_fields = if header.version == 2 {
379 Vec::new()
380 } else {
381 let mut unknown_header_fields =
382 vec![0u8; v3header_base.header_length as usize - min_header_size];
383 image
384 .read(&mut unknown_header_fields, min_header_size as u64)
385 .await?;
386 unknown_header_fields
387 };
388
389 let l1_offset = HostOffset(header.l1_table_offset.load(Ordering::Relaxed));
390 l1_offset
391 .checked_cluster(header.cluster_bits)
392 .ok_or_else(|| invalid_data(format!("Unaligned L1 table: {l1_offset}")))?;
393
394 let rt_offset = HostOffset(header.refcount_table_offset.load(Ordering::Relaxed));
395 rt_offset
396 .checked_cluster(header.cluster_bits)
397 .ok_or_else(|| invalid_data(format!("Unaligned refcount table: {rt_offset}")))?;
398
399 let rc_width = 1usize
400 .checked_shl(v3header_base.refcount_order)
401 .ok_or_else(|| {
402 invalid_data(format!(
403 "Invalid refcount width: 2^{}",
404 v3header_base.refcount_order
405 ))
406 })?;
407 if !(MIN_REFCOUNT_WIDTH..=MAX_REFCOUNT_WIDTH).contains(&rc_width) {
408 return Err(invalid_data(format!(
409 "Invalid refcount width: {rc_width}; must be between {MIN_REFCOUNT_WIDTH} and {MAX_REFCOUNT_WIDTH}",
410 )));
411 }
412
413 let backing_filename = if header.backing_file_offset != 0 {
414 let (offset, length) = (header.backing_file_offset, header.backing_file_size);
415 if length > 1023 {
416 return Err(invalid_data(format!(
417 "Backing file name is too long ({length}, must not exceed 1023)"
418 )));
419 }
420
421 let end = offset.checked_add(length as u64).ok_or(invalid_data(
422 "Backing file name offset is invalid (too high)",
423 ))?;
424 if end >= cluster_size as u64 {
425 return Err(invalid_data(
426 "Backing file name offset is invalid (beyond first cluster)",
427 ));
428 }
429
430 let mut backing_buf = vec![0; length as usize];
431 image.read(&mut backing_buf, offset).await?;
432
433 Some(
434 String::from_utf8(backing_buf)
435 .map_err(|err| invalid_data(format!("Backing file name is invalid: {err}")))?,
436 )
437 } else {
438 None
439 };
440
441 let extensions = if header.version == 2 {
442 Vec::new()
443 } else {
444 let mut ext_offset: u64 = v3header_base.header_length as u64;
445 let mut extensions = Vec::<HeaderExtension>::new();
446 loop {
447 if ext_offset + HeaderExtensionHeader::ON_DISK_SIZE as u64 > cluster_size as u64 {
448 return Err(invalid_data("Header extensions exceed the first cluster"));
449 }
450
451 let mut ext_hdr_buf = vec![0; HeaderExtensionHeader::ON_DISK_SIZE];
452 image.read(&mut ext_hdr_buf, ext_offset).await?;
453
454 ext_offset += HeaderExtensionHeader::ON_DISK_SIZE as u64;
455
456 let ext_hdr: HeaderExtensionHeader = decode_binary(&ext_hdr_buf)?;
457 let ext_end = ext_offset
458 .checked_add(ext_hdr.length as u64)
459 .ok_or_else(|| invalid_data("Header size overflow"))?;
460 if ext_end > cluster_size as u64 {
461 return Err(invalid_data("Header extensions exceed the first cluster"));
462 }
463
464 let mut ext_data = vec![0; ext_hdr.length as usize];
465 image.read(&mut ext_data, ext_offset).await?;
466
467 ext_offset += (ext_hdr.length as u64).next_multiple_of(8);
468
469 let Some(extension) =
470 HeaderExtension::deserialize(ext_hdr.extension_type, ext_data)?
471 else {
472 break;
473 };
474
475 extensions.push(extension);
476 }
477 extensions
478 };
479
480 let backing_fmt = extensions
482 .iter()
483 .find(|ext| matches!(ext, HeaderExtension::BackingFileFormat(_)));
484 if let Some(backing_fmt) = backing_fmt {
485 let conflicting = extensions.iter().find(|ext| {
486 matches!(ext, HeaderExtension::BackingFileFormat(_)) && ext != &backing_fmt
487 });
488 if let Some(conflicting) = conflicting {
489 return Err(io::Error::other(format!(
490 "Found conflicting backing file formats: {backing_fmt:?} != {conflicting:?}",
491 )));
492 }
493 }
494 let ext_data_file = extensions
495 .iter()
496 .find(|ext| matches!(ext, HeaderExtension::ExternalDataFileName(_)));
497 if let Some(ext_data_file) = ext_data_file {
498 let conflicting = extensions.iter().find(|ext| {
499 matches!(ext, HeaderExtension::ExternalDataFileName(_)) && ext != &ext_data_file
500 });
501 if let Some(conflicting) = conflicting {
502 return Err(io::Error::other(format!(
503 "Found conflicting external data file names: {ext_data_file:?} != {conflicting:?}",
504 )));
505 }
506 }
507
508 let mut incompatible_features = v3header_base.incompatible_features;
509 let autoclear_features = v3header_base.autoclear_features;
510
511 let external_data_file =
512 incompatible_features & IncompatibleFeatures::ExternalDataFile as u64 != 0;
513 incompatible_features &= !(IncompatibleFeatures::ExternalDataFile as u64);
514
515 let mut header = Header {
516 v2: header,
517 v3: v3header_base,
518 unknown_header_fields,
519 backing_filename,
520 extensions,
521 external_data_file,
522 };
523
524 if autoclear_features != 0 && writable {
526 header.v3.autoclear_features = 0;
527 header.write(image).await?;
528 }
529
530 if incompatible_features != 0 {
531 let feats = (0..64)
532 .filter(|bit| header.v3.incompatible_features & (1u64 << bit) != 0)
533 .map(|bit| {
534 if let Some(name) = header.feature_name(FeatureType::Incompatible, bit) {
535 format!("{bit} ({name})")
536 } else {
537 format!("{bit}")
538 }
539 })
540 .collect::<Vec<String>>();
541
542 return Err(invalid_data(format!(
543 "Unrecognized incompatible feature(s) {}",
544 feats.join(", ")
545 )));
546 }
547
548 Ok(header)
549 }
550
551 pub async fn write<S: Storage>(&mut self, image: &S) -> io::Result<()> {
553 let header_len = if self.v2.version > 2 {
554 let len =
555 self.v2.on_disk_size() + self.v3.on_disk_size() + self.unknown_header_fields.len();
556 let len = len.next_multiple_of(8);
557 self.v3.header_length = len as u32;
558 len
559 } else {
560 V2Header::ON_DISK_SIZE
561 };
562
563 let mut header_exts;
566 let mut backing_file_ofs;
567 loop {
568 header_exts = self.serialize_extensions()?;
569
570 backing_file_ofs = header_len
571 .checked_add(header_exts.len())
572 .ok_or_else(|| invalid_data("Header size overflow"))?;
573 let backing_file_len = self
574 .backing_filename
575 .as_ref()
576 .map(|n| n.len()) .unwrap_or(0);
578 let header_end = backing_file_ofs
579 .checked_add(backing_file_len)
580 .ok_or_else(|| invalid_data("Header size overflow"))?;
581
582 if header_end <= self.cluster_size() {
583 break;
584 }
585
586 if !self
587 .extensions
588 .iter()
589 .any(|e| e.extension_type() == HeaderExtensionType::FeatureNameTable as u32)
590 {
591 return Err(io::Error::other(format!(
592 "Header would be too long ({header_end} > {})",
593 self.cluster_size()
594 )));
595 }
596 self.extensions
597 .retain(|e| e.extension_type() != HeaderExtensionType::FeatureNameTable as u32);
598 }
599
600 if let Some(backing) = self.backing_filename.as_ref() {
601 self.v2.backing_file_offset = backing_file_ofs as u64;
602 self.v2.backing_file_size = backing.len() as u32; } else {
604 self.v2.backing_file_offset = 0;
605 self.v2.backing_file_size = 0;
606 };
607
608 let mut full_buf = encode_binary(&self.v2)?;
609 if self.v2.version > 2 {
610 full_buf.append(&mut encode_binary(&self.v3)?);
611 full_buf.extend_from_slice(&self.unknown_header_fields);
612 full_buf.resize(full_buf.len().next_multiple_of(8), 0);
613 }
614
615 full_buf.append(&mut header_exts);
616
617 if let Some(backing) = self.backing_filename.as_ref() {
618 full_buf.extend_from_slice(backing.as_bytes());
619 }
620
621 if full_buf.len() > self.cluster_size() {
622 return Err(io::Error::other(format!(
623 "Header is too big to write ({}, larger than a cluster ({}))",
624 full_buf.len(),
625 self.cluster_size(),
626 )));
627 }
628
629 image.write(&full_buf, 0).await
630 }
631
632 pub fn new(
634 cluster_bits: u32,
635 refcount_order: u32,
636 backing_filename: Option<String>,
637 backing_format: Option<String>,
638 external_data_file: Option<String>,
639 ) -> Self {
640 assert!((MIN_CLUSTER_SIZE..=MAX_CLUSTER_SIZE)
641 .contains(&1usize.checked_shl(cluster_bits).unwrap()));
642 assert!((MIN_REFCOUNT_WIDTH..=MAX_REFCOUNT_WIDTH)
643 .contains(&1usize.checked_shl(refcount_order).unwrap()));
644
645 let has_external_data_file = external_data_file.is_some();
646 let incompatible_features = if has_external_data_file {
647 IncompatibleFeatures::ExternalDataFile as u64
648 } else {
649 0
650 };
651
652 let mut extensions = vec![HeaderExtension::feature_name_table()];
653 if let Some(backing_format) = backing_format {
654 extensions.push(HeaderExtension::BackingFileFormat(backing_format));
655 }
656 if let Some(external_data_file) = external_data_file {
657 extensions.push(HeaderExtension::ExternalDataFileName(external_data_file));
658 }
659
660 Header {
661 v2: V2Header {
662 magic: MAGIC,
663 version: 3,
664 backing_file_offset: 0, backing_file_size: 0, cluster_bits,
667 size: 0.into(),
668 crypt_method: 0,
669 l1_size: 0.into(),
670 l1_table_offset: 0.into(),
671 refcount_table_offset: 0.into(),
672 refcount_table_clusters: 0.into(),
673 nb_snapshots: 0,
674 snapshots_offset: 0,
675 },
676 v3: V3HeaderBase {
677 incompatible_features,
678 compatible_features: 0,
679 autoclear_features: 0,
680 refcount_order,
681 header_length: 0, },
683 unknown_header_fields: Vec::new(),
684 backing_filename,
685 extensions,
686 external_data_file: has_external_data_file,
687 }
688 }
689
690 pub fn update(&self, new_header: &Header) -> io::Result<()> {
695 macro_rules! check_field {
697 ($($field:ident).*) => {
698 (self.$($field).* == new_header.$($field).*).then_some(()).ok_or_else(|| {
699 io::Error::other(format!(
700 "Incompatible header modification on {}: {} != {}",
701 stringify!($($field).*),
702 self.$($field).*,
703 new_header.$($field).*
704 ))
705 })
706 };
707 }
708
709 check_field!(v2.magic)?;
710 check_field!(v2.version)?;
711 check_field!(v2.backing_file_offset)?; check_field!(v2.backing_file_size)?; check_field!(v2.cluster_bits)?;
714 check_field!(v2.crypt_method)?;
718 check_field!(v2.nb_snapshots)?; check_field!(v2.snapshots_offset)?; check_field!(v3.incompatible_features)?; check_field!(v3.compatible_features)?; check_field!(v3.autoclear_features)?; check_field!(v3.refcount_order)?;
724 (self.unknown_header_fields == new_header.unknown_header_fields)
728 .then_some(())
729 .ok_or_else(|| io::Error::other("Unknown header fields modified"))?;
730 (self.backing_filename == new_header.backing_filename)
732 .then_some(())
733 .ok_or_else(|| io::Error::other("Backing filename modified"))?;
734 (self.extensions == new_header.extensions)
736 .then_some(())
737 .ok_or_else(|| io::Error::other("Header extensions modified"))?;
738
739 check_field!(external_data_file)?;
740
741 self.v2.size.store(
742 new_header.v2.size.load(Ordering::Relaxed),
743 Ordering::Relaxed,
744 );
745
746 self.v2.l1_table_offset.store(
747 new_header.v2.l1_table_offset.load(Ordering::Relaxed),
748 Ordering::Relaxed,
749 );
750 self.v2.l1_size.store(
751 new_header.v2.l1_size.load(Ordering::Relaxed),
752 Ordering::Relaxed,
753 );
754 self.v2.refcount_table_offset.store(
755 new_header.v2.refcount_table_offset.load(Ordering::Relaxed),
756 Ordering::Relaxed,
757 );
758 self.v2.refcount_table_clusters.store(
759 new_header
760 .v2
761 .refcount_table_clusters
762 .load(Ordering::Relaxed),
763 Ordering::Relaxed,
764 );
765
766 Ok(())
767 }
768
769 pub fn size(&self) -> u64 {
771 self.v2.size.load(Ordering::Relaxed)
772 }
773
774 pub fn require_version(&self, minimum: u32) -> io::Result<()> {
778 let version = self.v2.version;
779 if version >= minimum {
780 Ok(())
781 } else {
782 Err(io::Error::new(
783 io::ErrorKind::Unsupported,
784 format!("qcow2 version {minimum} required, image has version {version}"),
785 ))
786 }
787 }
788
789 pub fn set_size(&self, new_size: u64) {
791 self.v2.size.store(new_size, Ordering::Relaxed)
792 }
793
794 pub fn cluster_bits(&self) -> u32 {
796 self.v2.cluster_bits
797 }
798
799 pub fn cluster_size(&self) -> usize {
801 1 << self.cluster_bits()
802 }
803
804 pub fn l2_entries(&self) -> usize {
806 1 << (self.cluster_bits() - 3)
808 }
809
810 pub fn rb_bits(&self) -> u32 {
812 self.cluster_bits() + 3 - self.refcount_order()
816 }
817
818 pub fn rb_entries(&self) -> usize {
820 1 << self.rb_bits()
821 }
822
823 pub fn refcount_order(&self) -> u32 {
825 self.v3.refcount_order
826 }
827
828 pub fn l1_table_offset(&self) -> HostOffset {
830 HostOffset(self.v2.l1_table_offset.load(Ordering::Relaxed))
831 }
832
833 pub fn l1_table_entries(&self) -> usize {
835 self.v2.l1_size.load(Ordering::Relaxed) as usize
836 }
837
838 pub fn set_l1_table(
843 &self,
844 l1_table: &L1Table,
845 new_allocation: Option<PendingClusters>,
846 ) -> io::Result<()> {
847 if let Some(new_allocation) = new_allocation.as_ref() {
848 debug_assert_eq!(Some(new_allocation.cluster()), l1_table.get_cluster());
849 }
850
851 let offset = l1_table.get_offset().ok_or_else(|| {
852 io::Error::new(
853 io::ErrorKind::InvalidInput,
854 "New L1 table has no assigned offset",
855 )
856 })?;
857
858 let entries = l1_table.entries();
859 let entries = entries
860 .try_into()
861 .map_err(|err| invalid_data(format!("Too many L1 entries ({entries}): {err}")))?;
862
863 self.v2.l1_table_offset.store(offset.0, Ordering::Relaxed);
864 self.v2.l1_size.store(entries, Ordering::Relaxed);
865 if let Some(new_allocation) = new_allocation {
866 new_allocation.make_persistent();
867 }
868
869 Ok(())
870 }
871
872 pub fn reftable_offset(&self) -> HostOffset {
874 HostOffset(self.v2.refcount_table_offset.load(Ordering::Relaxed))
875 }
876
877 pub fn reftable_clusters(&self) -> ClusterCount {
879 ClusterCount(self.v2.refcount_table_clusters.load(Ordering::Relaxed) as u64)
880 }
881
882 pub fn reftable_entries(&self) -> usize {
884 (self.reftable_clusters().byte_size(self.cluster_bits()) >> 3) as usize
886 }
887
888 pub fn set_reftable(&self, reftable: &RefTable) -> io::Result<()> {
890 let offset = reftable.get_offset().ok_or_else(|| {
891 io::Error::new(
892 io::ErrorKind::InvalidInput,
893 "New refcount table has no assigned offset",
894 )
895 })?;
896
897 let clusters = reftable.cluster_count();
898 let clusters = clusters.0.try_into().map_err(|err| {
899 invalid_data(format!("Too many reftable clusters ({clusters}): {err}"))
900 })?;
901
902 self.v2
903 .refcount_table_clusters
904 .store(clusters, Ordering::Relaxed);
905
906 self.v2
907 .refcount_table_offset
908 .store(offset.0, Ordering::Relaxed);
909
910 Ok(())
911 }
912
913 pub fn backing_filename(&self) -> Option<&String> {
915 self.backing_filename.as_ref()
916 }
917
918 pub fn backing_format(&self) -> Option<&String> {
920 self.extensions.iter().find_map(|e| match e {
921 HeaderExtension::BackingFileFormat(fmt) => Some(fmt),
922 _ => None,
923 })
924 }
925
926 pub fn external_data_file(&self) -> bool {
928 self.external_data_file
929 }
930
931 pub fn external_data_filename(&self) -> Option<&String> {
933 self.extensions.iter().find_map(|e| match e {
934 HeaderExtension::ExternalDataFileName(filename) => Some(filename),
935 _ => None,
936 })
937 }
938
939 pub fn feature_name(&self, feat_type: FeatureType, bit: u32) -> Option<&String> {
943 for e in &self.extensions {
944 if let HeaderExtension::FeatureNameTable(names) = e {
945 if let Some(name) = names.get(&(feat_type, bit as u8)) {
946 return Some(name);
947 }
948 }
949 }
950
951 None
952 }
953
954 fn serialize_extensions(&self) -> io::Result<Vec<u8>> {
956 let mut result = Vec::new();
957 for e in &self.extensions {
958 let mut data = e.serialize_data()?;
959 let ext_hdr = HeaderExtensionHeader {
960 extension_type: e.extension_type(),
961 length: data.len().try_into().map_err(|err| {
962 invalid_data(format!("Header extension too long ({}): {err}", data.len()))
963 })?,
964 };
965 result.append(&mut encode_binary(&ext_hdr)?);
966 result.append(&mut data);
967 result.resize(result.len().next_multiple_of(8), 0);
968 }
969
970 let end_ext = HeaderExtensionHeader {
971 extension_type: HeaderExtensionType::End as u32,
972 length: 0,
973 };
974 result.append(&mut encode_binary(&end_ext)?);
975 result.resize(result.len().next_multiple_of(8), 0);
976
977 Ok(result)
978 }
979
980 async fn write_v2_header<S: Storage>(&self, image: &S) -> io::Result<()> {
982 let v2_header = encode_binary(&self.v2)?;
983 image.write(&v2_header, 0).await
984 }
985
986 pub async fn write_reftable_pointer<S: Storage>(&self, image: &S) -> io::Result<()> {
988 self.write_v2_header(image).await
990 }
991
992 pub async fn write_l1_table_pointer<S: Storage>(&self, image: &S) -> io::Result<()> {
994 self.write_v2_header(image).await
996 }
997
998 pub async fn write_size<S: Storage>(&self, image: &S) -> io::Result<()> {
1000 self.write_v2_header(image).await
1002 }
1003}
1004
1005impl HeaderExtension {
1006 fn deserialize(ext_type: u32, data: Vec<u8>) -> io::Result<Option<Self>> {
1009 let ext = if let Ok(ext_type) = HeaderExtensionType::try_from(ext_type) {
1010 match ext_type {
1011 HeaderExtensionType::End => return Ok(None),
1012 HeaderExtensionType::BackingFileFormat => {
1013 let fmt = String::from_utf8(data).map_err(|err| {
1014 invalid_data(format!("Invalid backing file format: {err}"))
1015 })?;
1016 HeaderExtension::BackingFileFormat(fmt)
1017 }
1018 HeaderExtensionType::FeatureNameTable => {
1019 let mut feats = HashMap::new();
1020 for feat in data.chunks(48) {
1021 let feat_type: FeatureType = match feat[0].try_into() {
1022 Ok(ft) => ft,
1023 Err(_) => continue, };
1025 let feat_name_bytes = feat[2..].split(|c| *c == 0).next().unwrap();
1028 let feat_name = String::from_utf8_lossy(feat_name_bytes);
1030 feats.insert((feat_type, feat[1]), feat_name.to_string());
1031 }
1032 HeaderExtension::FeatureNameTable(feats)
1033 }
1034 HeaderExtensionType::ExternalDataFileName => {
1035 let filename = String::from_utf8(data).map_err(|err| {
1036 invalid_data(format!("Invalid external data file name: {err}"))
1037 })?;
1038 HeaderExtension::ExternalDataFileName(filename)
1039 }
1040 }
1041 } else {
1042 HeaderExtension::Unknown {
1043 extension_type: ext_type,
1044 data,
1045 }
1046 };
1047
1048 Ok(Some(ext))
1049 }
1050
1051 fn extension_type(&self) -> u32 {
1053 match self {
1054 HeaderExtension::BackingFileFormat(_) => HeaderExtensionType::BackingFileFormat as u32,
1055 HeaderExtension::FeatureNameTable(_) => HeaderExtensionType::FeatureNameTable as u32,
1056 HeaderExtension::ExternalDataFileName(_) => {
1057 HeaderExtensionType::ExternalDataFileName as u32
1058 }
1059 HeaderExtension::Unknown {
1060 extension_type,
1061 data: _,
1062 } => *extension_type,
1063 }
1064 }
1065
1066 fn serialize_data(&self) -> io::Result<Vec<u8>> {
1068 match self {
1069 HeaderExtension::BackingFileFormat(fmt) => Ok(fmt.as_bytes().into()),
1070 HeaderExtension::FeatureNameTable(map) => {
1071 let mut result = Vec::new();
1072 for (bit, name) in map {
1073 result.push(bit.0 as u8);
1074 result.push(bit.1);
1075
1076 let mut padded_name = vec![0; 46];
1077 let name_bytes = name.as_bytes();
1078 let truncated_len = cmp::min(name_bytes.len(), 46);
1081 padded_name[..truncated_len].copy_from_slice(&name_bytes[..truncated_len]);
1082 result.extend_from_slice(&padded_name);
1083 }
1084 Ok(result)
1085 }
1086 HeaderExtension::ExternalDataFileName(filename) => Ok(filename.as_bytes().into()),
1087 HeaderExtension::Unknown {
1088 extension_type: _,
1089 data,
1090 } => Ok(data.clone()),
1091 }
1092 }
1093
1094 fn feature_name_table() -> Self {
1096 use AutoclearFeatures as A;
1097 use CompatibleFeatures as C;
1098 use IncompatibleFeatures as I;
1099
1100 let mut map = HashMap::new();
1101
1102 map.insert(I::Dirty.into(), "dirty".into());
1103 map.insert(I::Corrupt.into(), "corrupt".into());
1104 map.insert(I::ExternalDataFile.into(), "external data file".into());
1105 map.insert(
1106 I::CompressionType.into(),
1107 "extended compression type".into(),
1108 );
1109 map.insert(I::ExtendedL2Entries.into(), "extended L2 entries".into());
1110
1111 map.insert(C::LazyRefcounts.into(), "lazy refcounts".into());
1112
1113 map.insert(A::Bitmaps.into(), "persistent dirty bitmaps".into());
1114 map.insert(A::RawExternalData.into(), "raw external data file".into());
1115
1116 HeaderExtension::FeatureNameTable(map)
1117 }
1118}
1119
1120#[derive(Copy, Clone, Default, Debug)]
1130pub(super) struct L1Entry(u64);
1131
1132impl L1Entry {
1133 pub fn l2_offset(&self) -> Option<HostOffset> {
1135 let ofs = self.0 & 0x00ff_ffff_ffff_fe00u64;
1136 if ofs == 0 {
1137 None
1138 } else {
1139 Some(HostOffset(ofs))
1140 }
1141 }
1142
1143 pub fn is_copied(&self) -> bool {
1147 self.0 & (1u64 << 63) != 0
1148 }
1149
1150 pub fn reserved_bits(&self) -> u64 {
1152 self.0 & 0x7f00_0000_0000_01feu64
1153 }
1154}
1155
1156impl TableEntry for L1Entry {
1157 fn try_from_plain(value: u64, header: &Header) -> io::Result<Self> {
1158 let entry = L1Entry(value);
1159
1160 if entry.reserved_bits() != 0 {
1161 return Err(invalid_data(format!(
1162 "Invalid L1 entry 0x{value:x}, reserved bits set (0x{:x})",
1163 entry.reserved_bits(),
1164 )));
1165 }
1166
1167 if let Some(l2_ofs) = entry.l2_offset() {
1168 if l2_ofs.in_cluster_offset(header.cluster_bits()) != 0 {
1169 return Err(invalid_data(format!(
1170 "Invalid L1 entry 0x{value:x}, offset ({l2_ofs}) is not aligned to cluster size (0x{:x})",
1171 header.cluster_size(),
1172 )));
1173 }
1174 }
1175
1176 Ok(entry)
1177 }
1178
1179 fn to_plain(&self) -> u64 {
1180 self.0
1181 }
1182}
1183
1184#[derive(Debug)]
1186pub(super) struct L1Table {
1187 cluster: Option<HostCluster>,
1189
1190 data: Box<[L1Entry]>,
1192
1193 cluster_bits: u32,
1195
1196 modified: AtomicBool,
1198}
1199
1200impl L1Table {
1201 pub fn clone_and_grow(&self, at_least_index: usize, header: &Header) -> io::Result<Self> {
1203 let new_entry_count = cmp::max(at_least_index + 1, self.data.len());
1204 let new_entry_count =
1205 new_entry_count.next_multiple_of(header.cluster_size() / size_of::<L1Entry>());
1206
1207 if new_entry_count > <Self as Table>::MAX_ENTRIES {
1208 return Err(io::Error::other(
1209 "Cannot grow the image to this size; L1 table would become too big",
1210 ));
1211 }
1212
1213 let mut new_data = vec![L1Entry::default(); new_entry_count];
1214 new_data[..self.data.len()].copy_from_slice(&self.data);
1215
1216 Ok(Self {
1217 cluster: None,
1218 data: new_data.into_boxed_slice(),
1219 cluster_bits: header.cluster_bits(),
1220 modified: true.into(),
1221 })
1222 }
1223
1224 pub fn in_bounds(&self, index: usize) -> bool {
1226 index < self.data.len()
1227 }
1228
1229 pub fn enter_l2_table(
1234 &mut self,
1235 index: usize,
1236 l2: &L2Table,
1237 new_allocation: Option<PendingClusters>,
1238 ) -> io::Result<()> {
1239 if let Some(new_allocation) = new_allocation.as_ref() {
1240 debug_assert_eq!(Some(new_allocation.cluster()), l2.get_cluster());
1241 }
1242
1243 let l2_offset = l2.get_offset().ok_or_else(|| {
1244 io::Error::new(
1245 io::ErrorKind::InvalidInput,
1246 "L2 table has no assigned offset",
1247 )
1248 })?;
1249
1250 let l1entry = L1Entry((1 << 63) | l2_offset.0);
1251 debug_assert!(l1entry.reserved_bits() == 0);
1252 self.data[index] = l1entry;
1253 self.modified.store(true, Ordering::Relaxed);
1254 if let Some(new_allocation) = new_allocation {
1255 new_allocation.make_persistent();
1256 }
1257
1258 Ok(())
1259 }
1260}
1261
1262impl Table for L1Table {
1263 type InternalEntry = L1Entry;
1264 type Entry = L1Entry;
1265 const NAME: &'static str = "L1 table";
1266
1267 const MAX_ENTRIES: usize = 4 * 1024 * 1024;
1271
1272 fn from_data(data: Box<[L1Entry]>, header: &Header) -> Self {
1273 Self {
1274 cluster: None,
1275 data,
1276 cluster_bits: header.cluster_bits(),
1277 modified: true.into(),
1278 }
1279 }
1280
1281 fn entries(&self) -> usize {
1282 self.data.len()
1283 }
1284
1285 fn get_ref(&self, index: usize) -> Option<&L1Entry> {
1286 self.data.get(index)
1287 }
1288
1289 fn get(&self, index: usize) -> L1Entry {
1290 self.data.get(index).copied().unwrap_or(L1Entry(0))
1291 }
1292
1293 fn get_cluster(&self) -> Option<HostCluster> {
1294 self.cluster
1295 }
1296
1297 fn get_offset(&self) -> Option<HostOffset> {
1298 self.cluster.map(|index| index.offset(self.cluster_bits))
1299 }
1300
1301 fn set_cluster(&mut self, cluster: HostCluster) {
1302 self.cluster = Some(cluster);
1303 self.modified.store(true, Ordering::Relaxed);
1304 }
1305
1306 fn unset_cluster(&mut self) {
1307 self.cluster = None;
1308 }
1309
1310 fn is_modified(&self) -> bool {
1311 self.modified.load(Ordering::Relaxed)
1312 }
1313
1314 fn clear_modified(&self) {
1315 self.modified.store(false, Ordering::Relaxed);
1316 }
1317
1318 fn set_modified(&self) {
1319 self.modified.store(true, Ordering::Relaxed);
1320 }
1321
1322 fn cluster_bits(&self) -> u32 {
1323 self.cluster_bits
1324 }
1325}
1326
1327#[derive(Copy, Clone, Default, Debug)]
1359pub(super) struct L2Entry(u64);
1360
1361#[derive(Default, Debug)]
1365pub(super) struct AtomicL2Entry(AtomicU64);
1366
1367#[derive(Debug, Clone)]
1369pub(super) enum L2Mapping {
1370 DataFile {
1372 host_cluster: HostCluster,
1374
1375 copied: bool,
1377 },
1378
1379 Backing {
1381 backing_offset: u64,
1383 },
1384
1385 Zero {
1387 host_cluster: Option<HostCluster>,
1389
1390 copied: bool,
1392 },
1393
1394 Compressed {
1396 host_offset: HostOffset,
1398
1399 length: NonZero<u64>,
1401 },
1402}
1403
1404impl L2Entry {
1405 pub fn cluster_offset(&self, external_data_file: bool) -> Option<HostOffset> {
1413 let ofs = self.0 & 0x00ff_ffff_ffff_fe00u64;
1414 if ofs != 0 || (external_data_file && self.is_copied()) {
1415 Some(HostOffset(ofs))
1416 } else {
1417 None
1418 }
1419 }
1420
1421 pub fn is_compressed(&self) -> bool {
1423 self.0 & (1u64 << 62) != 0
1424 }
1425
1426 pub fn is_copied(&self) -> bool {
1430 self.0 & (1u64 << 63) != 0
1431 }
1432
1433 #[must_use]
1435 pub fn without_copied(self) -> Self {
1436 L2Entry(self.0 & !(1u64 << 63))
1437 }
1438
1439 pub fn is_zero(&self) -> bool {
1443 self.0 & (1u64 << 0) != 0
1444 }
1445
1446 pub fn reserved_bits(&self) -> u64 {
1448 if self.is_compressed() {
1449 self.0 & 0x8000_0000_0000_0000u64
1450 } else {
1451 self.0 & 0x3f00_0000_0000_01feu64
1452 }
1453 }
1454
1455 pub fn compressed_descriptor(&self) -> u64 {
1457 self.0 & 0x3fff_ffff_ffff_ffffu64
1458 }
1459
1460 pub fn compressed_range(&self, cluster_bits: u32) -> Option<(HostOffset, NonZero<u64>)> {
1463 if self.is_compressed() {
1464 let desc = self.compressed_descriptor();
1465 let compressed_offset_bits = 62 - (cluster_bits - 8);
1466 let offset = desc & ((1 << compressed_offset_bits) - 1) & 0x00ff_ffff_ffff_ffffu64;
1467 let sectors: u64 = desc >> compressed_offset_bits;
1468 let length = NonZero::new((sectors + 1) * 512 - (offset & 511)).unwrap();
1472
1473 Some((HostOffset(offset), length))
1474 } else {
1475 None
1476 }
1477 }
1478
1479 fn allocation(
1484 &self,
1485 cluster_bits: u32,
1486 external_data_file: bool,
1487 ) -> Option<(HostCluster, ClusterCount)> {
1488 if let Some((offset, length)) = self.compressed_range(cluster_bits) {
1489 let first_cluster = offset.cluster(cluster_bits);
1491 let cluster_count = ClusterCount::from_byte_size(
1492 offset + length.get() - first_cluster.offset(cluster_bits),
1493 cluster_bits,
1494 );
1495 Some((first_cluster, cluster_count))
1496 } else {
1497 self.cluster_offset(external_data_file)
1498 .map(|ofs| (ofs.cluster(cluster_bits), ClusterCount(1)))
1499 }
1500 }
1501
1502 fn into_mapping(
1507 self,
1508 guest_cluster: GuestCluster,
1509 cluster_bits: u32,
1510 external_data_file: bool,
1511 ) -> io::Result<L2Mapping> {
1512 let mapping = if let Some((offset, length)) = self.compressed_range(cluster_bits) {
1513 L2Mapping::Compressed {
1514 host_offset: offset,
1515 length,
1516 }
1517 } else if self.is_zero() {
1518 let host_cluster = self
1519 .cluster_offset(external_data_file)
1520 .map(|ofs| {
1521 ofs.checked_cluster(cluster_bits).ok_or_else(|| {
1522 let offset = guest_cluster.offset(cluster_bits);
1523 io::Error::other(format!(
1524 "Unaligned pre-allocated zero cluster at {offset}; L2 entry: {self:?}"
1525 ))
1526 })
1527 })
1528 .transpose()?;
1529
1530 L2Mapping::Zero {
1531 host_cluster,
1532 copied: host_cluster.is_some() && self.is_copied(),
1533 }
1534 } else if let Some(host_offset) = self.cluster_offset(external_data_file) {
1535 let host_cluster = host_offset.checked_cluster(cluster_bits).ok_or_else(|| {
1536 let offset = guest_cluster.offset(cluster_bits);
1537 io::Error::other(format!(
1538 "Unaligned data cluster at {offset}; L2 entry: {self:?}"
1539 ))
1540 })?;
1541
1542 L2Mapping::DataFile {
1543 host_cluster,
1544 copied: self.is_copied(),
1545 }
1546 } else {
1547 L2Mapping::Backing {
1548 backing_offset: guest_cluster.offset(cluster_bits).0,
1549 }
1550 };
1551
1552 Ok(mapping)
1553 }
1554
1555 fn from_mapping(value: L2Mapping, cluster_bits: u32) -> Self {
1557 let num_val: u64 = match value {
1558 L2Mapping::DataFile {
1559 host_cluster,
1560 copied,
1561 } => {
1562 debug_assert!(host_cluster.offset(cluster_bits) <= MAX_OFFSET);
1563 if copied {
1564 (1 << 63) | host_cluster.offset(cluster_bits).0
1565 } else {
1566 host_cluster.offset(cluster_bits).0
1567 }
1568 }
1569
1570 L2Mapping::Backing { backing_offset: _ } => 0,
1571
1572 L2Mapping::Zero {
1573 host_cluster,
1574 copied,
1575 } => {
1576 let host_offset = host_cluster.map(|hc| hc.offset(cluster_bits));
1577 debug_assert!(host_offset.unwrap_or(HostOffset(0)) <= MAX_OFFSET);
1578 if copied {
1579 (1 << 63) | host_offset.unwrap().0 | 0x1
1580 } else {
1581 host_offset.unwrap_or(HostOffset(0)).0 | 0x1
1582 }
1583 }
1584
1585 L2Mapping::Compressed {
1586 host_offset,
1587 length,
1588 } => {
1589 let compressed_offset_bits = 62 - (cluster_bits - 8);
1590 let length = length.get();
1591
1592 assert!(length < 1 << cluster_bits);
1593 assert!(host_offset.0 < 1 << compressed_offset_bits);
1594
1595 let sectors = (length - 1 + (host_offset.0 & 511)) / 512;
1600
1601 (1 << 62) | (sectors << compressed_offset_bits) | host_offset.0
1602 }
1603 };
1604
1605 let entry = L2Entry(num_val);
1606 debug_assert!(entry.reserved_bits() == 0);
1607 entry
1608 }
1609}
1610
1611impl AtomicL2Entry {
1612 fn get(&self) -> L2Entry {
1614 L2Entry(self.0.load(Ordering::Relaxed))
1615 }
1616
1617 unsafe fn swap(&self, l2e: L2Entry) -> L2Entry {
1625 L2Entry(self.0.swap(l2e.0, Ordering::Relaxed))
1626 }
1627}
1628
1629impl TableEntry for AtomicL2Entry {
1630 fn try_from_plain(value: u64, header: &Header) -> io::Result<Self> {
1631 let entry = L2Entry(value);
1632
1633 if entry.reserved_bits() != 0 {
1634 return Err(invalid_data(format!(
1635 "Invalid L2 entry 0x{value:x}, reserved bits set (0x{:x})",
1636 entry.reserved_bits(),
1637 )));
1638 }
1639
1640 if let Some(offset) = entry.cluster_offset(header.external_data_file()) {
1641 if !entry.is_compressed() && offset.in_cluster_offset(header.cluster_bits()) != 0 {
1642 return Err(invalid_data(format!(
1643 "Invalid L2 entry 0x{value:x}, offset ({offset}) is not aligned to cluster size (0x{:x})",
1644 header.cluster_size(),
1645 )));
1646 }
1647 }
1648
1649 Ok(AtomicL2Entry(AtomicU64::new(entry.0)))
1650 }
1651
1652 fn to_plain(&self) -> u64 {
1653 self.get().0
1654 }
1655}
1656
1657impl L2Mapping {
1658 pub fn is_consecutive(&self, preceding: &L2Mapping, cluster_bits: u32) -> bool {
1663 match preceding {
1664 L2Mapping::DataFile {
1665 host_cluster: prior_cluster,
1666 copied,
1667 } => {
1668 if let L2Mapping::DataFile {
1669 host_cluster: next_cluster,
1670 copied: next_copied,
1671 } = self
1672 {
1673 *next_cluster == *prior_cluster + ClusterCount(1) && *next_copied == *copied
1674 } else {
1675 false
1676 }
1677 }
1678
1679 L2Mapping::Backing {
1680 backing_offset: prior_backing_offset,
1681 } => {
1682 let Some(expected_next) = prior_backing_offset.checked_add(1 << cluster_bits)
1683 else {
1684 return false;
1685 };
1686
1687 if let L2Mapping::Backing {
1688 backing_offset: next_offset,
1689 } = self
1690 {
1691 *next_offset == expected_next
1692 } else {
1693 false
1694 }
1695 }
1696
1697 L2Mapping::Zero {
1698 host_cluster: _,
1699 copied: _,
1700 } => {
1701 matches!(
1704 self,
1705 L2Mapping::Zero {
1706 host_cluster: _,
1707 copied: _,
1708 }
1709 )
1710 }
1711
1712 L2Mapping::Compressed {
1713 host_offset: _,
1714 length: _,
1715 } => {
1716 matches!(
1719 self,
1720 L2Mapping::Compressed {
1721 host_offset: _,
1722 length: _,
1723 }
1724 )
1725 }
1726 }
1727 }
1728}
1729
1730#[derive(Debug)]
1732pub(super) struct L2Table {
1733 cluster: Option<HostCluster>,
1735
1736 data: Box<[AtomicL2Entry]>,
1738
1739 cluster_bits: u32,
1741
1742 external_data_file: bool,
1744
1745 modified: AtomicBool,
1747
1748 writer_lock: OwnedRwLock<()>,
1759
1760 writeback_lock: Mutex<()>,
1762}
1763
1764#[derive(Debug)]
1768pub(super) struct L2TableWriteGuard {
1769 table: Arc<L2Table>,
1771
1772 lock: OwnedRwLockWriteGuard<()>,
1774}
1775
1776#[maybe_async]
1777impl L2Table {
1778 pub fn new_cleared(header: &Header) -> Self {
1780 let mut data = Vec::with_capacity(header.l2_entries());
1781 data.resize_with(header.l2_entries(), Default::default);
1782
1783 L2Table {
1784 cluster: None,
1785 data: data.into_boxed_slice(),
1786 cluster_bits: header.cluster_bits(),
1787 external_data_file: header.external_data_file(),
1788 modified: true.into(),
1789 writer_lock: Default::default(),
1790 writeback_lock: Default::default(),
1791 }
1792 }
1793
1794 pub fn get_mapping(&self, lookup_cluster: GuestCluster) -> io::Result<L2Mapping> {
1796 self.get(lookup_cluster.l2_index(self.cluster_bits))
1797 .into_mapping(lookup_cluster, self.cluster_bits, self.external_data_file)
1798 }
1799
1800 pub async fn lock_write(self: &Arc<Self>) -> L2TableWriteGuard {
1807 L2TableWriteGuard {
1808 table: Arc::clone(self),
1809 lock: self.writer_lock.write().await,
1810 }
1811 }
1812
1813 pub async fn lock_compressed_read(
1819 &self,
1820 cluster: GuestCluster,
1821 ) -> io::Result<Option<CompressedClusterReadGuard<'_>>> {
1822 let lock = self.writer_lock.read().await;
1823 CompressedClusterReadGuard::new(self, cluster, lock.into())
1824 }
1825
1826 pub async fn write_if_modified<S: Storage>(
1839 &self,
1840 image: &S,
1841 cluster: HostCluster,
1842 ) -> io::Result<()> {
1843 let _lock = self.writeback_lock.lock().await;
1844
1845 if !self.is_modified() {
1846 return Ok(());
1847 }
1848
1849 assert!(self.get_cluster().unwrap() == cluster);
1850 self.write(image).await
1851 }
1852}
1853
1854impl L2TableWriteGuard {
1855 pub fn get_mapping(&self, lookup_cluster: GuestCluster) -> io::Result<L2Mapping> {
1857 self.table.get_mapping(lookup_cluster)
1858 }
1859
1860 pub fn compressed_read_guard(
1867 &self,
1868 cluster: GuestCluster,
1869 ) -> io::Result<Option<CompressedClusterReadGuard<'_>>> {
1870 CompressedClusterReadGuard::new(&self.table, cluster, (&self.lock).into())
1871 }
1872
1873 #[must_use = "Leaked allocation must be freed"]
1884 pub fn map_cluster(
1885 &mut self,
1886 index: usize,
1887 host_cluster: HostCluster,
1888 new_allocation: Option<PendingClusters>,
1889 ) -> Option<ClustersToFreeEntry> {
1890 if let Some(new_allocation) = new_allocation.as_ref() {
1891 debug_assert_eq!(new_allocation.cluster(), host_cluster);
1892 }
1893
1894 let new = L2Entry::from_mapping(
1895 L2Mapping::DataFile {
1896 host_cluster,
1897 copied: true,
1898 },
1899 self.table.cluster_bits,
1900 );
1901 let l2e = unsafe { self.table.data[index].swap(new) };
1904 self.table.modified.store(true, Ordering::Relaxed);
1905 if let Some(new_allocation) = new_allocation {
1906 new_allocation.make_persistent();
1907 }
1908
1909 let allocation = l2e.allocation(self.table.cluster_bits, self.table.external_data_file);
1910 if let Some((a_cluster, a_count)) = allocation {
1911 if a_cluster == host_cluster && a_count == ClusterCount(1) {
1912 None
1913 } else {
1914 Some(ClustersToFreeEntry::data(a_cluster, a_count))
1915 }
1916 } else {
1917 None
1918 }
1919 }
1920
1921 #[must_use = "Leaked allocation must be freed"]
1930 pub fn zero_cluster(
1931 &mut self,
1932 index: usize,
1933 keep_allocation: bool,
1934 ) -> io::Result<Option<ClustersToFreeEntry>> {
1935 let cluster_copied = if keep_allocation {
1936 match self.table.data[index].get().into_mapping(
1937 GuestCluster(0), self.table.cluster_bits,
1939 self.table.external_data_file,
1940 )? {
1941 L2Mapping::DataFile {
1942 host_cluster,
1943 copied,
1944 } => Some((host_cluster, copied)),
1945 L2Mapping::Backing { backing_offset: _ } => None,
1946 L2Mapping::Zero {
1947 host_cluster: Some(host_cluster),
1948 copied,
1949 } => Some((host_cluster, copied)),
1950 L2Mapping::Zero {
1951 host_cluster: None,
1952 copied: _,
1953 } => None,
1954 L2Mapping::Compressed {
1955 host_offset: _,
1956 length: _,
1957 } => None,
1958 }
1959 } else {
1960 None
1961 };
1962
1963 let retained = cluster_copied.is_some();
1964 let new = if let Some((cluster, copied)) = cluster_copied {
1965 L2Mapping::Zero {
1966 host_cluster: Some(cluster),
1967 copied,
1968 }
1969 } else {
1970 L2Mapping::Zero {
1971 host_cluster: None,
1972 copied: false,
1973 }
1974 };
1975 let new = L2Entry::from_mapping(new, self.table.cluster_bits);
1976
1977 let old = unsafe { self.table.data[index].swap(new) };
1980 self.table.modified.store(true, Ordering::Relaxed);
1981
1982 let leaked = if !retained {
1983 old.allocation(self.table.cluster_bits, self.table.external_data_file)
1984 .map(|(first_cluster, count)| ClustersToFreeEntry::data(first_cluster, count))
1985 } else {
1986 None
1987 };
1988 Ok(leaked)
1989 }
1990
1991 #[must_use = "Leaked allocation must be freed"]
1996 pub fn discard_cluster(&mut self, index: usize) -> Option<ClustersToFreeEntry> {
1997 let new = L2Entry(0);
1998
1999 let old = unsafe { self.table.data[index].swap(new) };
2002 self.table.modified.store(true, Ordering::Relaxed);
2003
2004 old.allocation(self.table.cluster_bits, self.table.external_data_file)
2005 .map(|(first_cluster, count)| ClustersToFreeEntry::data(first_cluster, count))
2006 }
2007}
2008
2009impl Table for L2Table {
2010 type InternalEntry = AtomicL2Entry;
2011 type Entry = L2Entry;
2012 const NAME: &'static str = "L2 table";
2013 const MAX_ENTRIES: usize = MAX_CLUSTER_SIZE / 8;
2014
2015 fn from_data(data: Box<[AtomicL2Entry]>, header: &Header) -> Self {
2016 assert!(data.len() == header.l2_entries());
2017
2018 Self {
2019 cluster: None,
2020 data,
2021 cluster_bits: header.cluster_bits(),
2022 external_data_file: header.external_data_file(),
2023 modified: true.into(),
2024 writer_lock: Default::default(),
2025 writeback_lock: Default::default(),
2026 }
2027 }
2028
2029 fn entries(&self) -> usize {
2030 self.data.len()
2031 }
2032
2033 fn get_ref(&self, index: usize) -> Option<&AtomicL2Entry> {
2034 self.data.get(index)
2035 }
2036
2037 fn get(&self, index: usize) -> L2Entry {
2038 self.data
2039 .get(index)
2040 .map(|l2e| l2e.get())
2041 .unwrap_or(L2Entry(0))
2042 }
2043
2044 fn get_cluster(&self) -> Option<HostCluster> {
2045 self.cluster
2046 }
2047
2048 fn get_offset(&self) -> Option<HostOffset> {
2049 self.cluster.map(|index| index.offset(self.cluster_bits))
2050 }
2051
2052 fn set_cluster(&mut self, cluster: HostCluster) {
2053 self.cluster = Some(cluster);
2054 self.modified.store(true, Ordering::Relaxed);
2055 }
2056
2057 fn unset_cluster(&mut self) {
2058 self.cluster = None;
2059 }
2060
2061 fn is_modified(&self) -> bool {
2062 self.modified.load(Ordering::Relaxed)
2063 }
2064
2065 fn clear_modified(&self) {
2066 self.modified.store(false, Ordering::Relaxed);
2067 }
2068
2069 fn set_modified(&self) {
2070 self.modified.store(true, Ordering::Relaxed);
2071 }
2072
2073 fn cluster_bits(&self) -> u32 {
2074 self.cluster_bits
2075 }
2076}
2077
2078impl Clone for L2Table {
2079 fn clone(&self) -> Self {
2080 let mut data = Vec::with_capacity(self.data.len());
2081 for entry in &self.data {
2082 let entry = entry.get().without_copied();
2084 data.push(AtomicL2Entry(AtomicU64::new(entry.0)));
2085 }
2086
2087 let modified = AtomicBool::new(self.is_modified());
2088
2089 L2Table {
2090 cluster: None,
2091 data: data.into_boxed_slice(),
2092 cluster_bits: self.cluster_bits,
2093 external_data_file: self.external_data_file,
2094 modified,
2095 writer_lock: Default::default(),
2096 writeback_lock: Default::default(),
2097 }
2098 }
2099}
2100
2101impl Drop for L2Table {
2102 fn drop(&mut self) {
2103 if self.is_modified() {
2104 error!("L2 table dropped while modified; was the image closed before being flushed?");
2105 }
2106 }
2107}
2108
2109#[derive(Copy, Clone, Default, Debug)]
2111pub(super) struct RefTableEntry(u64);
2112
2113impl RefTableEntry {
2114 pub fn refblock_offset(&self) -> Option<HostOffset> {
2116 let ofs = self.0 & 0xffff_ffff_ffff_fe00u64;
2117 if ofs == 0 {
2118 None
2119 } else {
2120 Some(HostOffset(ofs))
2121 }
2122 }
2123
2124 pub fn reserved_bits(&self) -> u64 {
2126 self.0 & 0x0000_0000_0000_01ffu64
2127 }
2128}
2129
2130impl TableEntry for RefTableEntry {
2131 fn try_from_plain(value: u64, header: &Header) -> io::Result<Self> {
2132 let entry = RefTableEntry(value);
2133
2134 if entry.reserved_bits() != 0 {
2135 return Err(invalid_data(format!(
2136 "Invalid reftable entry 0x{value:x}, reserved bits set (0x{:x})",
2137 entry.reserved_bits(),
2138 )));
2139 }
2140
2141 if let Some(rb_ofs) = entry.refblock_offset() {
2142 if rb_ofs.in_cluster_offset(header.cluster_bits()) != 0 {
2143 return Err(invalid_data(
2144 format!(
2145 "Invalid reftable entry 0x{value:x}, offset ({rb_ofs}) is not aligned to cluster size (0x{:x})",
2146 header.cluster_size(),
2147 ),
2148 ));
2149 }
2150 }
2151
2152 Ok(entry)
2153 }
2154
2155 fn to_plain(&self) -> u64 {
2156 self.0
2157 }
2158}
2159
2160#[derive(Debug)]
2162pub(super) struct RefTable {
2163 cluster: Option<HostCluster>,
2165
2166 data: Box<[RefTableEntry]>,
2168
2169 cluster_bits: u32,
2171
2172 modified: AtomicBool,
2174}
2175
2176impl RefTable {
2177 pub fn clone_and_grow(&self, header: &Header, at_least_index: usize) -> io::Result<Self> {
2182 let cluster_size = header.cluster_size();
2183 let rb_entries = header.rb_entries();
2184
2185 let mut extra_rbs = 1;
2188 let new_entry_count = loop {
2189 let entry_count = cmp::max(at_least_index + 1 + extra_rbs, self.data.len());
2190 let entry_count = entry_count.next_multiple_of(cluster_size / size_of::<u64>());
2191 let size = entry_count * size_of::<u64>();
2192 let refcount_clusters = size / cluster_size + extra_rbs;
2194 let rbs_needed = refcount_clusters.div_ceil(rb_entries);
2195 if extra_rbs == rbs_needed {
2196 break entry_count;
2197 }
2198 extra_rbs = rbs_needed;
2199 };
2200
2201 if new_entry_count > <Self as Table>::MAX_ENTRIES {
2202 return Err(io::Error::other(
2203 "Cannot grow the image to this size; refcount table would become too big",
2204 ));
2205 }
2206
2207 let mut new_data = vec![RefTableEntry::default(); new_entry_count];
2208 new_data[..self.data.len()].copy_from_slice(&self.data);
2209
2210 Ok(Self {
2211 cluster: None,
2212 data: new_data.into_boxed_slice(),
2213 cluster_bits: header.cluster_bits(),
2214 modified: true.into(),
2215 })
2216 }
2217
2218 pub fn in_bounds(&self, index: usize) -> bool {
2220 index < self.data.len()
2221 }
2222
2223 pub fn enter_refblock(
2228 &mut self,
2229 index: usize,
2230 rb: &RefBlock,
2231 new_allocation: Option<PendingClusters>,
2232 ) -> io::Result<()> {
2233 if let Some(new_allocation) = new_allocation.as_ref() {
2234 debug_assert_eq!(Some(new_allocation.cluster()), rb.get_cluster());
2235 }
2236
2237 let rb_offset = rb.get_offset().ok_or_else(|| {
2238 io::Error::new(
2239 io::ErrorKind::InvalidInput,
2240 "Refcount block as no assigned offset",
2241 )
2242 })?;
2243
2244 let rt_entry = RefTableEntry(rb_offset.0);
2245 debug_assert!(rt_entry.reserved_bits() == 0);
2246 self.data[index] = rt_entry;
2247 self.modified.store(true, Ordering::Relaxed);
2248 if let Some(new_allocation) = new_allocation {
2249 new_allocation.make_persistent();
2250 }
2251
2252 Ok(())
2253 }
2254}
2255
2256impl Table for RefTable {
2257 type InternalEntry = RefTableEntry;
2258 type Entry = RefTableEntry;
2259 const NAME: &'static str = "Refcount table";
2260
2261 const MAX_ENTRIES: usize = <L1Table as Table>::MAX_ENTRIES;
2268
2269 fn from_data(data: Box<[RefTableEntry]>, header: &Header) -> Self {
2270 Self {
2271 cluster: None,
2272 data,
2273 cluster_bits: header.cluster_bits(),
2274 modified: true.into(),
2275 }
2276 }
2277
2278 fn entries(&self) -> usize {
2279 self.data.len()
2280 }
2281
2282 fn get_ref(&self, index: usize) -> Option<&RefTableEntry> {
2283 self.data.get(index)
2284 }
2285
2286 fn get(&self, index: usize) -> RefTableEntry {
2287 self.data.get(index).copied().unwrap_or(RefTableEntry(0))
2288 }
2289
2290 fn get_cluster(&self) -> Option<HostCluster> {
2291 self.cluster
2292 }
2293
2294 fn get_offset(&self) -> Option<HostOffset> {
2295 self.cluster.map(|index| index.offset(self.cluster_bits))
2296 }
2297
2298 fn set_cluster(&mut self, cluster: HostCluster) {
2299 self.cluster = Some(cluster);
2300 self.modified.store(true, Ordering::Relaxed);
2301 }
2302
2303 fn unset_cluster(&mut self) {
2304 self.cluster = None;
2305 }
2306
2307 fn is_modified(&self) -> bool {
2308 self.modified.load(Ordering::Relaxed)
2309 }
2310
2311 fn clear_modified(&self) {
2312 self.modified.store(false, Ordering::Relaxed);
2313 }
2314
2315 fn set_modified(&self) {
2316 self.modified.store(true, Ordering::Relaxed);
2317 }
2318
2319 fn cluster_bits(&self) -> u32 {
2320 self.cluster_bits
2321 }
2322}
2323
2324pub(super) struct RefBlock {
2326 cluster: Option<HostCluster>,
2328
2329 raw_data: IoBuffer,
2331
2332 refcount_order: u32,
2334
2335 cluster_bits: u32,
2337
2338 modified: AtomicBool,
2340
2341 writer_lock: Mutex<()>,
2343
2344 writeback_lock: Mutex<()>,
2346}
2347
2348pub(super) struct RefBlockWriteGuard<'a> {
2350 rb: &'a RefBlock,
2352
2353 _lock: MutexGuard<'a, ()>,
2355}
2356
2357#[maybe_async]
2358impl RefBlock {
2359 pub fn new_cleared<S: Storage>(for_image: &S, header: &Header) -> io::Result<Self> {
2361 let mut raw_data = IoBuffer::new(header.cluster_size(), for_image.mem_align())?;
2362 raw_data.as_mut().into_slice().fill(0);
2363
2364 Ok(RefBlock {
2365 cluster: None,
2366 raw_data,
2367 refcount_order: header.refcount_order(),
2368 cluster_bits: header.cluster_bits(),
2369 modified: true.into(),
2370 writer_lock: Default::default(),
2371 writeback_lock: Default::default(),
2372 })
2373 }
2374
2375 pub async fn load<S: Storage>(
2377 image: &S,
2378 header: &Header,
2379 cluster: HostCluster,
2380 ) -> io::Result<Self> {
2381 let cluster_bits = header.cluster_bits();
2382 let cluster_size = 1 << cluster_bits;
2383 let refcount_order = header.refcount_order();
2384 let offset = cluster.offset(cluster_bits);
2385
2386 check_table(
2387 "Refcount block",
2388 offset.0,
2389 cluster_size,
2390 1,
2391 MAX_CLUSTER_SIZE,
2392 cluster_size,
2393 )?;
2394
2395 let mut raw_data =
2396 IoBuffer::new(cluster_size, cmp::max(image.mem_align(), size_of::<u64>()))?;
2397 image.read(&mut raw_data, offset.0).await?;
2398
2399 Ok(RefBlock {
2400 cluster: Some(cluster),
2401 raw_data,
2402 refcount_order,
2403 cluster_bits,
2404 modified: false.into(),
2405 writer_lock: Default::default(),
2406 writeback_lock: Default::default(),
2407 })
2408 }
2409
2410 fn copy_raw_data<T: Copy + Sized, F: Fn(*const T) -> T>(
2414 &self,
2415 mem_align: usize,
2416 get: F,
2417 ) -> io::Result<IoBuffer> {
2418 assert!(cmp::max((1 << self.refcount_order) / 8, 1) == size_of::<T>());
2420
2421 let byte_size = 1 << self.cluster_bits;
2422 let mut buffer = IoBuffer::new(byte_size, cmp::max(mem_align, size_of::<T>()))?;
2423
2424 let raw_in = unsafe { self.raw_data.as_ref().into_typed_slice::<T>() };
2426 let raw_out = unsafe { buffer.as_mut().into_typed_slice::<T>() };
2428
2429 for (i, value) in raw_in.iter().enumerate() {
2430 raw_out[i] = get(value as *const T);
2431 }
2432
2433 Ok(buffer)
2434 }
2435
2436 pub async fn write<S: Storage>(&self, image: &S) -> io::Result<()> {
2438 let offset = self
2439 .get_offset()
2440 .ok_or_else(|| io::Error::other("Cannot write qcow2 refcount block, no offset set"))?;
2441
2442 self.clear_modified();
2443 let mut modified_guard = DropGuard::new(|| self.set_modified());
2445
2446 let buffer = match self.refcount_order {
2447 0..=3 => self.copy_raw_data::<u8, _>(image.mem_align(), |ptr| {
2449 unsafe { AtomicU8::from_ptr(ptr as *mut u8) }.load(Ordering::Relaxed)
2451 })?,
2452
2453 4 => self.copy_raw_data::<u16, _>(image.mem_align(), |ptr| {
2455 unsafe { AtomicU16::from_ptr(ptr as *mut u16) }.load(Ordering::Relaxed)
2457 })?,
2458
2459 5 => self.copy_raw_data::<u32, _>(image.mem_align(), |ptr| {
2461 unsafe { AtomicU32::from_ptr(ptr as *mut u32) }.load(Ordering::Relaxed)
2463 })?,
2464
2465 6 => self.copy_raw_data::<u64, _>(image.mem_align(), |ptr| {
2467 unsafe { AtomicU64::from_ptr(ptr as *mut u64) }.load(Ordering::Relaxed)
2469 })?,
2470
2471 _ => unreachable!(),
2472 };
2473
2474 image.write(&buffer, offset.0).await?;
2475 modified_guard.disarm();
2477
2478 Ok(())
2479 }
2480
2481 pub fn get_cluster(&self) -> Option<HostCluster> {
2483 self.cluster
2484 }
2485
2486 pub fn get_offset(&self) -> Option<HostOffset> {
2488 self.cluster.map(|index| index.offset(self.cluster_bits))
2489 }
2490
2491 pub fn set_cluster(&mut self, cluster: HostCluster) {
2493 self.cluster = Some(cluster);
2494 self.set_modified();
2495 }
2496
2497 fn sub_byte_refcount_access(&self, index: usize) -> (usize, u8, usize) {
2504 let order = self.refcount_order;
2505 debug_assert!(order < 3);
2506
2507 let byte_index = index >> (3 - order);
2511 let mask = (1 << (1 << order)) - 1;
2514 let shift = (index << order) % 8;
2517
2518 (byte_index, mask, shift)
2519 }
2520
2521 pub fn get(&self, index: usize) -> u64 {
2523 match self.refcount_order {
2524 0..=2 => {
2526 let (index, mask, shift) = self.sub_byte_refcount_access(index);
2527 let raw_data_slice = unsafe { self.raw_data.as_ref().into_typed_slice::<u8>() };
2528 let atomic =
2529 unsafe { AtomicU8::from_ptr(&raw_data_slice[index] as *const u8 as *mut u8) };
2530 ((atomic.load(Ordering::Relaxed) >> shift) & mask) as u64
2531 }
2532
2533 3 => {
2535 let raw_data_slice = unsafe { self.raw_data.as_ref().into_typed_slice::<u8>() };
2536 let atomic =
2537 unsafe { AtomicU8::from_ptr(&raw_data_slice[index] as *const u8 as *mut u8) };
2538 atomic.load(Ordering::Relaxed) as u64
2539 }
2540
2541 4 => {
2543 let raw_data_slice = unsafe { self.raw_data.as_ref().into_typed_slice::<u16>() };
2544 let atomic = unsafe {
2545 AtomicU16::from_ptr(&raw_data_slice[index] as *const u16 as *mut u16)
2546 };
2547 u16::from_be(atomic.load(Ordering::Relaxed)) as u64
2548 }
2549
2550 5 => {
2552 let raw_data_slice = unsafe { self.raw_data.as_ref().into_typed_slice::<u32>() };
2553 let atomic = unsafe {
2554 AtomicU32::from_ptr(&raw_data_slice[index] as *const u32 as *mut u32)
2555 };
2556 u32::from_be(atomic.load(Ordering::Relaxed)) as u64
2557 }
2558
2559 6 => {
2561 let raw_data_slice = unsafe { self.raw_data.as_ref().into_typed_slice::<u64>() };
2562 let atomic = unsafe {
2563 AtomicU64::from_ptr(&raw_data_slice[index] as *const u64 as *mut u64)
2564 };
2565 u64::from_be(atomic.load(Ordering::Relaxed))
2566 }
2567
2568 _ => unreachable!(),
2569 }
2570 }
2571
2572 pub async fn lock_write(&self) -> RefBlockWriteGuard<'_> {
2576 RefBlockWriteGuard {
2577 rb: self,
2578 _lock: self.writer_lock.lock().await,
2579 }
2580 }
2581
2582 pub async fn write_if_modified<S: Storage>(
2595 &self,
2596 image: &S,
2597 cluster: HostCluster,
2598 ) -> io::Result<()> {
2599 let _lock = self.writeback_lock.lock().await;
2600
2601 if !self.is_modified() {
2602 return Ok(());
2603 }
2604
2605 assert!(self.get_cluster().unwrap() == cluster);
2606 self.write(image).await
2607 }
2608
2609 pub fn is_modified(&self) -> bool {
2611 self.modified.load(Ordering::Relaxed)
2612 }
2613
2614 pub fn clear_modified(&self) {
2616 self.modified.store(false, Ordering::Relaxed);
2617 }
2618
2619 pub fn set_modified(&self) {
2621 self.modified.store(true, Ordering::Relaxed);
2622 }
2623
2624 pub fn is_zero(&self, index: usize) -> bool {
2626 self.get(index) == 0
2627 }
2628}
2629
2630impl RefBlockWriteGuard<'_> {
2631 unsafe fn fetch_update_bitset(
2634 bitset: &AtomicU8,
2635 change: i64,
2636 base_mask: u8,
2637 shift: usize,
2638 ) -> io::Result<u64> {
2639 let mask = base_mask << shift;
2640
2641 let full = bitset.load(Ordering::Relaxed);
2643 let old = (full & mask) >> shift;
2644 let new = if change > 0 {
2645 let change = change.try_into().map_err(|_| {
2646 io::Error::new(
2647 io::ErrorKind::InvalidInput,
2648 format!("Requested refcount change of {change} is too big for the image’s refcount width"),
2649 )
2650 })?;
2651 old.checked_add(change)
2652 } else {
2653 let change = (-change).try_into().map_err(|_| {
2654 io::Error::new(
2655 io::ErrorKind::InvalidInput,
2656 format!("Requested refcount change of {change} is too big for the image’s refcount width"),
2657 )
2658 })?;
2659 old.checked_sub(change)
2660 };
2661 let new = new.ok_or_else(|| {
2662 invalid_data(format!(
2663 "Changing refcount from {old} by {change} would overflow"
2664 ))
2665 })?;
2666 if new > base_mask {
2667 return Err(invalid_data(format!(
2668 "Changing refcount from {old} to {new} (by {change}) would overflow"
2669 )));
2670 }
2671
2672 let full = (full & !mask) | (new << shift);
2673 bitset.store(full, Ordering::Relaxed);
2674 Ok(old as u64)
2675 }
2676
2677 unsafe fn fetch_update_full<
2680 T,
2681 L: FnOnce(&T) -> u64,
2682 S: FnOnce(&T, u64) -> Result<(), TryFromIntError>,
2683 >(
2684 atomic: &T,
2685 change: i64,
2686 load: L,
2687 store: S,
2688 ) -> io::Result<u64> {
2689 let old = load(atomic);
2691
2692 let new = if change > 0 {
2693 old.checked_add(change as u64)
2694 } else {
2695 old.checked_sub(-change as u64)
2696 };
2697 let new = new.ok_or_else(|| {
2698 invalid_data(format!(
2699 "Changing refcount from {old} by {change} would overflow"
2700 ))
2701 })?;
2702
2703 store(atomic, new).map_err(|_| {
2704 invalid_data(format!(
2705 "Changing refcount from {old} to {new} (by {change}) would overflow"
2706 ))
2707 })?;
2708
2709 Ok(old)
2710 }
2711
2712 fn modify(&mut self, index: usize, change: i64) -> io::Result<u64> {
2714 let result = match self.rb.refcount_order {
2715 0..=2 => {
2717 let (index, mask, shift) = self.rb.sub_byte_refcount_access(index);
2718 let raw_data_slice = unsafe { self.rb.raw_data.as_ref().into_typed_slice::<u8>() };
2719 let atomic =
2720 unsafe { AtomicU8::from_ptr(&raw_data_slice[index] as *const u8 as *mut u8) };
2721 unsafe { Self::fetch_update_bitset(atomic, change, mask, shift) }
2723 }
2724
2725 3 => {
2727 let raw_data_slice = unsafe { self.rb.raw_data.as_ref().into_typed_slice::<u8>() };
2728 let atomic =
2729 unsafe { AtomicU8::from_ptr(&raw_data_slice[index] as *const u8 as *mut u8) };
2730 unsafe {
2732 Self::fetch_update_full(
2733 atomic,
2734 change,
2735 |a| a.load(Ordering::Relaxed) as u64,
2736 |a, v| {
2737 a.store(v.try_into()?, Ordering::Relaxed);
2738 Ok(())
2739 },
2740 )
2741 }
2742 }
2743
2744 4 => {
2746 let raw_data_slice = unsafe { self.rb.raw_data.as_ref().into_typed_slice::<u16>() };
2747 let atomic = unsafe {
2748 AtomicU16::from_ptr(&raw_data_slice[index] as *const u16 as *mut u16)
2749 };
2750 unsafe {
2751 Self::fetch_update_full(
2752 atomic,
2753 change,
2754 |a| u16::from_be(a.load(Ordering::Relaxed)) as u64,
2755 |a, v| {
2756 a.store(u16::try_from(v)?.to_be(), Ordering::Relaxed);
2757 Ok(())
2758 },
2759 )
2760 }
2761 }
2762
2763 5 => {
2765 let raw_data_slice = unsafe { self.rb.raw_data.as_ref().into_typed_slice::<u32>() };
2766 let atomic = unsafe {
2767 AtomicU32::from_ptr(&raw_data_slice[index] as *const u32 as *mut u32)
2768 };
2769 unsafe {
2770 Self::fetch_update_full(
2771 atomic,
2772 change,
2773 |a| u32::from_be(a.load(Ordering::Relaxed)) as u64,
2774 |a, v| {
2775 a.store(u32::try_from(v)?.to_be(), Ordering::Relaxed);
2776 Ok(())
2777 },
2778 )
2779 }
2780 }
2781
2782 6 => {
2784 let raw_data_slice = unsafe { self.rb.raw_data.as_ref().into_typed_slice::<u64>() };
2785 let atomic = unsafe {
2786 AtomicU64::from_ptr(&raw_data_slice[index] as *const u64 as *mut u64)
2787 };
2788 unsafe {
2789 Self::fetch_update_full(
2790 atomic,
2791 change,
2792 |a| u64::from_be(a.load(Ordering::Relaxed)),
2793 |a, v| {
2794 a.store(v.to_be(), Ordering::Relaxed);
2795 Ok(())
2796 },
2797 )
2798 }
2799 }
2800
2801 _ => unreachable!(),
2802 };
2803
2804 let result = result?;
2805 self.rb.modified.store(true, Ordering::Relaxed);
2806 Ok(result)
2807 }
2808
2809 pub fn increment(&mut self, index: usize) -> io::Result<u64> {
2813 self.modify(index, 1)
2814 }
2815
2816 pub fn decrement(&mut self, index: usize) -> io::Result<u64> {
2820 self.modify(index, -1)
2821 }
2822
2823 pub fn is_zero(&self, index: usize) -> bool {
2825 self.rb.is_zero(index)
2826 }
2827}
2828
2829impl Drop for RefBlock {
2830 fn drop(&mut self) {
2831 if self.is_modified() {
2832 error!(
2833 "Refcount block dropped while modified; was the image closed before being flushed?"
2834 );
2835 }
2836 }
2837}
2838
2839pub trait TableEntry
2841where
2842 Self: Sized,
2843{
2844 fn try_from_plain(value: u64, header: &Header) -> io::Result<Self>;
2846
2847 fn to_plain(&self) -> u64;
2849}
2850
2851#[maybe_async(AFIT)]
2853pub trait Table: Sized {
2854 type InternalEntry: TableEntry;
2856 type Entry: Copy;
2858 const NAME: &'static str;
2860 const MAX_ENTRIES: usize;
2862
2863 fn from_data(data: Box<[Self::InternalEntry]>, header: &Header) -> Self;
2865
2866 fn entries(&self) -> usize;
2868 fn get_ref(&self, index: usize) -> Option<&Self::InternalEntry>;
2870 fn get(&self, index: usize) -> Self::Entry;
2872 fn get_cluster(&self) -> Option<HostCluster>;
2874 fn get_offset(&self) -> Option<HostOffset>;
2876 fn set_cluster(&mut self, cluster: HostCluster);
2878 fn unset_cluster(&mut self);
2880
2881 fn cluster_bits(&self) -> u32;
2885
2886 fn is_modified(&self) -> bool;
2888 fn clear_modified(&self);
2890 fn set_modified(&self);
2892
2893 fn byte_size(&self) -> usize {
2895 self.entries() * size_of::<u64>()
2896 }
2897
2898 fn cluster_count(&self) -> ClusterCount {
2900 ClusterCount::from_byte_size(self.byte_size() as u64, self.cluster_bits())
2901 }
2902
2903 async fn load<S: Storage>(
2905 image: &S,
2906 header: &Header,
2907 cluster: HostCluster,
2908 entries: usize,
2909 ) -> io::Result<Self> {
2910 let offset = cluster.offset(header.cluster_bits());
2911
2912 check_table(
2913 Self::NAME,
2914 offset.0,
2915 entries,
2916 size_of::<u64>(),
2917 Self::MAX_ENTRIES,
2918 header.cluster_size(),
2919 )?;
2920
2921 let byte_size = entries * size_of::<u64>();
2922 let mut buffer = IoBuffer::new(byte_size, cmp::max(image.mem_align(), size_of::<u64>()))?;
2923
2924 image.read(&mut buffer, offset.0).await?;
2925
2926 let raw_table = unsafe { buffer.as_ref().into_typed_slice::<u64>() };
2928
2929 let mut table = Vec::<Self::InternalEntry>::with_capacity(entries);
2930 for be_value in raw_table {
2931 table.push(Self::InternalEntry::try_from_plain(
2932 u64::from_be(*be_value),
2933 header,
2934 )?)
2935 }
2936
2937 let mut table = Self::from_data(table.into_boxed_slice(), header);
2938 table.set_cluster(cluster);
2939 table.clear_modified();
2940 Ok(table)
2941 }
2942
2943 async fn write<S: Storage>(&self, image: &S) -> io::Result<()> {
2947 let offset = self
2948 .get_offset()
2949 .ok_or_else(|| io::Error::other("Cannot write qcow2 metadata table, no offset set"))?;
2950
2951 check_table(
2952 Self::NAME,
2953 offset.0,
2954 self.entries(),
2955 size_of::<u64>(),
2956 Self::MAX_ENTRIES,
2957 1 << self.cluster_bits(),
2958 )?;
2959
2960 let byte_size = self.byte_size();
2961 let mut buffer = IoBuffer::new(byte_size, cmp::max(image.mem_align(), size_of::<u64>()))?;
2962
2963 self.clear_modified();
2964 let mut modified_guard = DropGuard::new(|| self.set_modified());
2966
2967 let raw_table = unsafe { buffer.as_mut().into_typed_slice::<u64>() };
2969 for (i, be_value) in raw_table.iter_mut().enumerate() {
2970 *be_value = self.get_ref(i).map(|e| e.to_plain()).unwrap_or(0).to_be();
2972 }
2973
2974 image.write(&buffer, offset.0).await?;
2975 modified_guard.disarm();
2977
2978 Ok(())
2979 }
2980
2981 async fn write_entry<S: Storage>(&self, image: &S, index: usize) -> io::Result<()> {
2985 let alignment = image
2993 .mem_align()
2994 .max(image.req_align())
2995 .max(size_of::<u64>());
2996 let cluster_size = 1 << self.cluster_bits();
2997 let alignment = if alignment <= cluster_size {
2998 alignment
2999 } else {
3000 size_of::<u64>()
3001 };
3002 let entries_to_write = alignment / size_of::<u64>();
3003
3004 let offset = self
3005 .get_offset()
3006 .ok_or_else(|| io::Error::other("Cannot write qcow2 metadata table, no offset set"))?;
3007
3008 check_table(
3009 Self::NAME,
3010 offset.0,
3011 self.entries(),
3012 size_of::<u64>(),
3013 Self::MAX_ENTRIES,
3014 cluster_size,
3015 )?;
3016
3017 let mut buffer = IoBuffer::new(alignment, cmp::max(image.mem_align(), size_of::<u64>()))?;
3018
3019 let raw_entries = unsafe { buffer.as_mut().into_typed_slice::<u64>() };
3021 let first_index = (index / entries_to_write) * entries_to_write;
3022 #[allow(clippy::needless_range_loop)]
3023 for i in 0..entries_to_write {
3024 raw_entries[i] = self
3026 .get_ref(first_index + i)
3027 .map(|e| e.to_plain())
3028 .unwrap_or(0)
3029 .to_be();
3030 }
3031
3032 image
3033 .write(&buffer, offset.0 + (first_index * size_of::<u64>()) as u64)
3034 .await
3035 }
3036}
3037
3038fn check_table(
3043 name: &str,
3044 offset: u64,
3045 entries: usize,
3046 entry_size: usize,
3047 max_entries: usize,
3048 cluster_size: usize,
3049) -> io::Result<()> {
3050 if entries > max_entries {
3051 return Err(invalid_data(format!(
3052 "{name} too big: {entries} > {max_entries}",
3053 )));
3054 }
3055
3056 if !offset.is_multiple_of(cluster_size as u64) {
3057 return Err(invalid_data(format!("{name}: Unaligned offset: {offset}")));
3058 }
3059
3060 let byte_size = entries
3061 .checked_mul(entry_size)
3062 .ok_or_else(|| invalid_data(format!("{name} size overflow: {entries} * {entry_size}")))?;
3063 let end_offset = offset
3064 .checked_add(byte_size as u64)
3065 .ok_or_else(|| invalid_data(format!("{name} offset overflow: {offset} + {byte_size}")))?;
3066 if end_offset > MAX_FILE_LENGTH {
3067 return Err(invalid_data(format!(
3068 "{name}: Invalid end offset: {end_offset} > {MAX_FILE_LENGTH}"
3069 )));
3070 }
3071
3072 Ok(())
3073}
3074
3075fn encode_binary<T: OnDiskStruct>(val: &T) -> io::Result<Vec<u8>> {
3077 let mut vec = vec![0; T::ON_DISK_SIZE];
3078 val.store_to(&mut vec)?;
3079 Ok(vec)
3080}
3081
3082fn decode_binary<T: OnDiskStruct>(slice: &[u8]) -> io::Result<T> {
3084 T::load_from(slice)
3085}
3086
3087#[cfg(test)]
3088mod tests {
3089 use super::*;
3090 use crate::test::mem_storage::{MemStorage, MemStorageState};
3091 use parking_lot::Mutex;
3092 use std::sync::Arc;
3093
3094 #[maybe_async::test(feature = "sync", async(feature = "async", tokio::test))]
3111 async fn l1_write_entry_beyond_table_end() {
3112 let uninitialized: u8 = 0xa5;
3113
3114 let header = Header::new(9, 4, None, None, None);
3115 let state = Arc::new(MemStorageState {
3116 data: Mutex::new(vec![uninitialized; 16384]),
3117 ..Default::default()
3118 });
3119 let mem = MemStorage::new(Arc::clone(&state), true).with_align(4096);
3120
3121 let l1_cluster_start = 8;
3122 let l1_offset = l1_cluster_start * 512;
3123 let l1_entries = 320;
3124 let l1_byte_size = l1_entries * size_of::<u64>();
3125
3126 let test_index = 300;
3128 let test_entry = (1 << 63) | 0x10000;
3129
3130 let mut data = vec![L1Entry::default(); l1_entries];
3131 data[test_index] = L1Entry::try_from_plain(test_entry, &header).unwrap();
3132 let mut l1 = L1Table::from_data(data.into_boxed_slice(), &header);
3133 l1.set_cluster(HostCluster(l1_cluster_start as u64));
3134
3135 l1.write_entry(&mem, test_index).await.unwrap();
3136
3137 let data = state.data.lock();
3139 let offset = l1_offset + test_index * size_of::<u64>();
3140 let entry = u64::from_be_bytes(
3141 data[offset..(offset + size_of::<u64>())]
3142 .try_into()
3143 .unwrap(),
3144 );
3145 assert_eq!(entry, test_entry);
3146
3147 let offset_past = l1_offset + l1_byte_size;
3149 let next_alignment_boundary = offset_past.next_multiple_of(4096);
3150 let clobbered = data[offset_past..next_alignment_boundary]
3151 .iter()
3152 .filter(|b| **b != uninitialized)
3153 .count();
3154 assert_eq!(clobbered, 0, "bytes after the L1 table were overwritten");
3155 }
3156}