Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions block/src/qcow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ fn l2_entry_make_std(cluster_addr: u64) -> u64 {
(cluster_addr & L2_TABLE_OFFSET_MASK) | CLUSTER_USED_FLAG
}

// Make L1 entry with optional flags
fn l1_entry_make(cluster_addr: u64, refcount_is_one: bool) -> u64 {
(cluster_addr & L1_TABLE_OFFSET_MASK) | (refcount_is_one as u64 * CLUSTER_USED_FLAG)
}

/// Contains the information from the header of a qcow file.
#[derive(Clone, Debug)]
pub struct QcowHeader {
Expand Down Expand Up @@ -1571,11 +1576,25 @@ impl QcowFile {
// Push L1 table and refcount table last as all the clusters they point to are now
// guaranteed to be valid.
let mut sync_required = if self.l1_table.dirty() {
self.raw_file.write_pointer_table(
self.header.l1_table_offset,
self.l1_table.get_values(),
0,
)?;
// Build L1 table with OFLAG_COPIED bits set correctly based on L2 cluster refcounts
let l1_active: Vec<u64> = self
.l1_table
.get_values()
.iter()
.map(|&l2_addr| {
if l2_addr == 0 {
Ok(0)
} else {
let refcount = self
.refcounts
.get_cluster_refcount(&mut self.raw_file, l2_addr)
.map_err(|e| std::io::Error::other(Error::GettingRefcount(e)))?;
Ok(l1_entry_make(l2_addr, refcount == 1))
}
})
.collect::<io::Result<Vec<u64>>>()?;
self.raw_file
.write_pointer_table(self.header.l1_table_offset, &l1_active, 0)?;
self.l1_table.mark_clean();
true
} else {
Expand Down
Loading