From 13198777dde74fdac9944c43d7e02ae5be168826 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Wed, 21 Jan 2026 19:43:57 +0100 Subject: [PATCH] block: qcow: Add support for zero bit in standard L2 clusters Implement read support for bit 0 in QCOW2 L2 table entries. When this flag is set, the cluster reads as zeros without accessing disk. This improves compatibility with QCOW2 images that use this optimization. According to the QCOW2 specification, bit 0 of the standard cluster descriptor indicates that the cluster reads as zeros. Unlike l2_entry == 0 indicating a completely unallocated entry, bit 0 can be set on an allocated cluster. Signed-off-by: Anatol Belski --- block/src/qcow/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/block/src/qcow/mod.rs b/block/src/qcow/mod.rs index ca0262924..732c10e4b 100644 --- a/block/src/qcow/mod.rs +++ b/block/src/qcow/mod.rs @@ -193,6 +193,7 @@ const V3_BARE_HEADER_SIZE: u32 = 104; const L1_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00; const L2_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00; // Flags +const ZERO_FLAG: u64 = 1 << 0; const COMPRESSED_FLAG: u64 = 1 << 62; const COMPRESSED_SECTOR_SIZE: u64 = 512; const CLUSTER_USED_FLAG: u64 = 1 << 63; @@ -217,6 +218,11 @@ fn l2_entry_is_empty(l2_entry: u64) -> bool { l2_entry == 0 } +// Check bit 0 - only valid for standard clusters. +fn l2_entry_is_zero(l2_entry: u64) -> bool { + l2_entry & ZERO_FLAG != 0 +} + fn l2_entry_is_compressed(l2_entry: u64) -> bool { l2_entry & COMPRESSED_FLAG != 0 } @@ -1333,6 +1339,9 @@ impl QcowFile { return Err(err_inval); } buf[..count].copy_from_slice(&decompressed_cluster[start..end.unwrap()]); + } else if l2_entry_is_zero(l2_entry) { + // Cluster with zero flag reads as zeros without accessing disk. + return Ok(None); } else { let start = l2_entry_std_cluster_addr(l2_entry) + self.raw_file.cluster_offset(address); let raw_file = self.raw_file.file_mut();