block: qcow: Add direct_io test coverage for QcowSync

Add direct_io variants for suitable tests by extracting
test bodies into _impl(direct_io: bool) functions. Each
original test calls _impl(false) and a new _direct_io test
calls _impl(true).

When direct_io is true, RawFile probes alignment and QcowSync
exercises the AlignedBuf and bounce buffer paths in
read_vectored and write_vectored.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-04-13 22:15:56 +02:00
committed by Rob Bradford
parent cfa60a95b9
commit b62525f792
+186 -41
View File
@@ -432,6 +432,7 @@ mod unit_tests {
data: &[u8], data: &[u8],
offset: u64, offset: u64,
sparse: bool, sparse: bool,
direct_io: bool,
) -> (TempFile, QcowDiskSync) { ) -> (TempFile, QcowDiskSync) {
let temp_file = TempFile::new().unwrap(); let temp_file = TempFile::new().unwrap();
{ {
@@ -443,7 +444,7 @@ mod unit_tests {
} }
let disk = QcowDiskSync::new( let disk = QcowDiskSync::new(
temp_file.as_file().try_clone().unwrap(), temp_file.as_file().try_clone().unwrap(),
false, direct_io,
false, false,
sparse, sparse,
) )
@@ -485,7 +486,7 @@ mod unit_tests {
fn test_qcow_async_punch_hole_completion() { fn test_qcow_async_punch_hole_completion() {
let data = vec![0xDD; 128 * 1024]; let data = vec![0xDD; 128 * 1024];
let offset = 0u64; let offset = 0u64;
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true); let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true, false);
let mut async_io = disk.new_async_io(1).unwrap(); let mut async_io = disk.new_async_io(1).unwrap();
async_io.punch_hole(offset, data.len() as u64, 100).unwrap(); async_io.punch_hole(offset, data.len() as u64, 100).unwrap();
@@ -505,7 +506,7 @@ mod unit_tests {
fn test_qcow_async_write_zeroes_completion() { fn test_qcow_async_write_zeroes_completion() {
let data = vec![0xEE; 256 * 1024]; let data = vec![0xEE; 256 * 1024];
let offset = 64 * 1024u64; let offset = 64 * 1024u64;
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true); let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true, false);
let mut async_io = disk.new_async_io(1).unwrap(); let mut async_io = disk.new_async_io(1).unwrap();
async_io async_io
@@ -526,7 +527,7 @@ mod unit_tests {
#[test] #[test]
fn test_qcow_async_multiple_operations() { fn test_qcow_async_multiple_operations() {
let data = vec![0xFF; 64 * 1024]; let data = vec![0xFF; 64 * 1024];
let (_temp, _) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true); let (_temp, _) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true, false);
// Write data at multiple offsets via QcowFile first, then punch // Write data at multiple offsets via QcowFile first, then punch
{ {
@@ -567,7 +568,7 @@ mod unit_tests {
// Verify that after punch_hole, a second async_io sees zeros. // Verify that after punch_hole, a second async_io sees zeros.
let data = vec![0xAB; 128 * 1024]; let data = vec![0xAB; 128 * 1024];
let offset = 0u64; let offset = 0u64;
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true); let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true, false);
let mut async_io1 = disk.new_async_io(1).unwrap(); let mut async_io1 = disk.new_async_io(1).unwrap();
async_io1 async_io1
@@ -591,7 +592,7 @@ mod unit_tests {
// Simulates the real usage pattern of write data, punch hole, then read back. // Simulates the real usage pattern of write data, punch hole, then read back.
let data = vec![0xCD; 64 * 1024]; // one cluster let data = vec![0xCD; 64 * 1024]; // one cluster
let offset = 1024 * 1024u64; // 1MB offset let offset = 1024 * 1024u64; // 1MB offset
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true); let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &data, offset, true, false);
// Punch hole to simulate DISCARD // Punch hole to simulate DISCARD
let mut async_io1 = disk.new_async_io(1).unwrap(); let mut async_io1 = disk.new_async_io(1).unwrap();
@@ -609,9 +610,8 @@ mod unit_tests {
); );
} }
#[test] fn test_qcow_async_read_write_roundtrip_impl(direct_io: bool) {
fn test_qcow_async_read_write_roundtrip() { let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true, direct_io);
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true);
let data = vec![0x42u8; 64 * 1024]; let data = vec![0x42u8; 64 * 1024];
let offset = 0u64; let offset = 0u64;
@@ -630,9 +630,18 @@ mod unit_tests {
} }
#[test] #[test]
fn test_qcow_async_read_unallocated() { fn test_qcow_async_read_write_roundtrip() {
test_qcow_async_read_write_roundtrip_impl(false);
}
#[test]
fn test_qcow_async_read_write_roundtrip_direct_io() {
test_qcow_async_read_write_roundtrip_impl(true);
}
fn test_qcow_async_read_unallocated_impl(direct_io: bool) {
// Reading from an unallocated region should return zeros. // Reading from an unallocated region should return zeros.
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true); let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true, direct_io);
let read_buf = async_read(&disk, 0, 64 * 1024); let read_buf = async_read(&disk, 0, 64 * 1024);
assert!( assert!(
read_buf.iter().all(|&b| b == 0), read_buf.iter().all(|&b| b == 0),
@@ -641,8 +650,17 @@ mod unit_tests {
} }
#[test] #[test]
fn test_qcow_async_cross_cluster_read_write() { fn test_qcow_async_read_unallocated() {
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true); test_qcow_async_read_unallocated_impl(false);
}
#[test]
fn test_qcow_async_read_unallocated_direct_io() {
test_qcow_async_read_unallocated_impl(true);
}
fn test_qcow_async_cross_cluster_read_write_impl(direct_io: bool) {
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true, direct_io);
// Default cluster size is 64KB. Write 96KB starting at 32KB to cross the boundary. // Default cluster size is 64KB. Write 96KB starting at 32KB to cross the boundary.
let data: Vec<u8> = (0..96 * 1024).map(|i| (i % 251) as u8).collect(); let data: Vec<u8> = (0..96 * 1024).map(|i| (i % 251) as u8).collect();
@@ -662,7 +680,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_backing_file_read() { fn test_qcow_async_cross_cluster_read_write() {
test_qcow_async_cross_cluster_read_write_impl(false);
}
#[test]
fn test_qcow_async_cross_cluster_read_write_direct_io() {
test_qcow_async_cross_cluster_read_write_impl(true);
}
fn test_backing_file_read_impl(direct_io: bool) {
let backing_temp = TempFile::new().unwrap(); let backing_temp = TempFile::new().unwrap();
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let file_size = cluster_size * 4; let file_size = cluster_size * 4;
@@ -683,7 +710,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Read first cluster - should come from backing file // Read first cluster - should come from backing file
let buf = async_read(&disk, 0, cluster_size as usize); let buf = async_read(&disk, 0, cluster_size as usize);
@@ -719,7 +746,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_backing_file_read_qcow2_backing() { fn test_backing_file_read() {
test_backing_file_read_impl(false);
}
#[test]
fn test_backing_file_read_direct_io() {
test_backing_file_read_impl(true);
}
fn test_backing_file_read_qcow2_backing_impl(direct_io: bool) {
let backing_temp = TempFile::new().unwrap(); let backing_temp = TempFile::new().unwrap();
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let file_size = cluster_size * 4; let file_size = cluster_size * 4;
@@ -745,7 +781,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Read first cluster - should come from QCOW2 backing // Read first cluster - should come from QCOW2 backing
let buf = async_read(&disk, 0, cluster_size as usize); let buf = async_read(&disk, 0, cluster_size as usize);
@@ -786,14 +822,23 @@ mod unit_tests {
} }
#[test] #[test]
fn test_multi_queue_concurrent_reads() { fn test_backing_file_read_qcow2_backing() {
test_backing_file_read_qcow2_backing_impl(false);
}
#[test]
fn test_backing_file_read_qcow2_backing_direct_io() {
test_backing_file_read_qcow2_backing_impl(true);
}
fn test_multi_queue_concurrent_reads_impl(direct_io: bool) {
// Verify that multiple queues (threads) can read simultaneously. // Verify that multiple queues (threads) can read simultaneously.
// This exercises the RwLock + pread64 design: concurrent L2 cache hits // This exercises the RwLock + pread64 design: concurrent L2 cache hits
// proceed in parallel and data reads are position independent. // proceed in parallel and data reads are position independent.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let file_size = cluster_size * 16; let file_size = cluster_size * 16;
let pattern: Vec<u8> = (0..file_size as usize).map(|i| (i % 251) as u8).collect(); let pattern: Vec<u8> = (0..file_size as usize).map(|i| (i % 251) as u8).collect();
let (_temp, disk) = create_disk_with_data(file_size, &pattern, 0, true); let (_temp, disk) = create_disk_with_data(file_size, &pattern, 0, true, direct_io);
let disk = Arc::new(disk); let disk = Arc::new(disk);
let threads: Vec<_> = (0..8) let threads: Vec<_> = (0..8)
@@ -822,7 +867,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_multi_queue_concurrent_reads_qcow2_backing() { fn test_multi_queue_concurrent_reads() {
test_multi_queue_concurrent_reads_impl(false);
}
#[test]
fn test_multi_queue_concurrent_reads_direct_io() {
test_multi_queue_concurrent_reads_impl(true);
}
fn test_multi_queue_concurrent_reads_qcow2_backing_impl(direct_io: bool) {
// Same as above but reads go through a Qcow2Backing, // Same as above but reads go through a Qcow2Backing,
// exercising concurrent metadata resolution + pread64 in the backing. // exercising concurrent metadata resolution + pread64 in the backing.
let backing_temp = TempFile::new().unwrap(); let backing_temp = TempFile::new().unwrap();
@@ -850,7 +904,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = Arc::new(QcowDiskSync::new(file, false, true, true).unwrap()); let disk = Arc::new(QcowDiskSync::new(file, direct_io, true, true).unwrap());
let threads: Vec<_> = (0..8) let threads: Vec<_> = (0..8)
.map(|t| { .map(|t| {
@@ -877,7 +931,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_three_layer_backing_chain() { fn test_multi_queue_concurrent_reads_qcow2_backing() {
test_multi_queue_concurrent_reads_qcow2_backing_impl(false);
}
#[test]
fn test_multi_queue_concurrent_reads_qcow2_backing_direct_io() {
test_multi_queue_concurrent_reads_qcow2_backing_impl(true);
}
fn test_three_layer_backing_chain_impl(direct_io: bool) {
// raw base -> qcow2 mid -> qcow2 overlay // raw base -> qcow2 mid -> qcow2 overlay
// Tests recursive shared_backing_from() with nested backing. // Tests recursive shared_backing_from() with nested backing.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
@@ -924,7 +987,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Cluster 0: mid wrote 0xBB // Cluster 0: mid wrote 0xBB
let buf = async_read(&disk, 0, cluster_size as usize); let buf = async_read(&disk, 0, cluster_size as usize);
@@ -960,7 +1023,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_backing_cow_preserves_all_unwritten_clusters() { fn test_three_layer_backing_chain() {
test_three_layer_backing_chain_impl(false);
}
#[test]
fn test_three_layer_backing_chain_direct_io() {
test_three_layer_backing_chain_impl(true);
}
fn test_backing_cow_preserves_all_unwritten_clusters_impl(direct_io: bool) {
// Write to specific clusters in the overlay, verify all others still // Write to specific clusters in the overlay, verify all others still
// read from the qcow2 backing correctly. // read from the qcow2 backing correctly.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
@@ -990,7 +1062,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
let written = vec![0xFFu8; cluster_size as usize]; let written = vec![0xFFu8; cluster_size as usize];
for &idx in &[0u64, 3, 7] { for &idx in &[0u64, 3, 7] {
@@ -1025,7 +1097,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_qcow2_backing_read_beyond_virtual_size() { fn test_backing_cow_preserves_all_unwritten_clusters() {
test_backing_cow_preserves_all_unwritten_clusters_impl(false);
}
#[test]
fn test_backing_cow_preserves_all_unwritten_clusters_direct_io() {
test_backing_cow_preserves_all_unwritten_clusters_impl(true);
}
fn test_qcow2_backing_read_beyond_virtual_size_impl(direct_io: bool) {
// Read starting past the backing file virtual_size should return zeros. // Read starting past the backing file virtual_size should return zeros.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let backing_size = cluster_size * 2; let backing_size = cluster_size * 2;
@@ -1053,7 +1134,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Read cluster 2 (past backing virtual_size) - should be zeros // Read cluster 2 (past backing virtual_size) - should be zeros
let buf = async_read(&disk, backing_size, cluster_size as usize); let buf = async_read(&disk, backing_size, cluster_size as usize);
@@ -1064,7 +1145,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_qcow2_backing_read_spanning_virtual_size() { fn test_qcow2_backing_read_beyond_virtual_size() {
test_qcow2_backing_read_beyond_virtual_size_impl(false);
}
#[test]
fn test_qcow2_backing_read_beyond_virtual_size_direct_io() {
test_qcow2_backing_read_beyond_virtual_size_impl(true);
}
fn test_qcow2_backing_read_spanning_virtual_size_impl(direct_io: bool) {
// Read that starts within backing bounds but extends past virtual_size. // Read that starts within backing bounds but extends past virtual_size.
// First part should have backing data, remainder should be zeros. // First part should have backing data, remainder should be zeros.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
@@ -1094,7 +1184,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Read 2 clusters starting at cluster 1 (spans backing boundary) // Read 2 clusters starting at cluster 1 (spans backing boundary)
let read_len = cluster_size as usize * 2; let read_len = cluster_size as usize * 2;
@@ -1114,7 +1204,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_raw_backing_read_beyond_virtual_size() { fn test_qcow2_backing_read_spanning_virtual_size() {
test_qcow2_backing_read_spanning_virtual_size_impl(false);
}
#[test]
fn test_qcow2_backing_read_spanning_virtual_size_direct_io() {
test_qcow2_backing_read_spanning_virtual_size_impl(true);
}
fn test_raw_backing_read_beyond_virtual_size_impl(direct_io: bool) {
// Read past raw backing file virtual_size should return zeros. // Read past raw backing file virtual_size should return zeros.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let backing_size = cluster_size * 2; let backing_size = cluster_size * 2;
@@ -1138,7 +1237,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Read cluster 2 (past backing size) - should be zeros // Read cluster 2 (past backing size) - should be zeros
let buf = async_read(&disk, backing_size, cluster_size as usize); let buf = async_read(&disk, backing_size, cluster_size as usize);
@@ -1161,7 +1260,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_qcow2_backing_cross_cluster_read() { fn test_raw_backing_read_beyond_virtual_size() {
test_raw_backing_read_beyond_virtual_size_impl(false);
}
#[test]
fn test_raw_backing_read_beyond_virtual_size_direct_io() {
test_raw_backing_read_beyond_virtual_size_impl(true);
}
fn test_qcow2_backing_cross_cluster_read_impl(direct_io: bool) {
// Read spanning a cluster boundary through qcow2 backing. // Read spanning a cluster boundary through qcow2 backing.
// Exercises the read_clusters loop in Qcow2Backing. // Exercises the read_clusters loop in Qcow2Backing.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
@@ -1190,7 +1298,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Read spanning clusters 1-2 boundary: 512 bytes before + 512 after // Read spanning clusters 1-2 boundary: 512 bytes before + 512 after
let mid = cluster_size - 512; let mid = cluster_size - 512;
@@ -1214,7 +1322,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_punch_hole_with_backing_fallthrough() { fn test_qcow2_backing_cross_cluster_read() {
test_qcow2_backing_cross_cluster_read_impl(false);
}
#[test]
fn test_qcow2_backing_cross_cluster_read_direct_io() {
test_qcow2_backing_cross_cluster_read_impl(true);
}
fn test_punch_hole_with_backing_fallthrough_impl(direct_io: bool) {
// Write to overlay, then punch hole. After punch, the cluster should // Write to overlay, then punch hole. After punch, the cluster should
// fall through to backing data (not zeros). // fall through to backing data (not zeros).
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
@@ -1238,7 +1355,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
let written = vec![0xFFu8; cluster_size as usize]; let written = vec![0xFFu8; cluster_size as usize];
async_write(&disk, 0, &written); async_write(&disk, 0, &written);
@@ -1277,10 +1394,19 @@ mod unit_tests {
} }
#[test] #[test]
fn test_rewrite_allocated_cluster() { fn test_punch_hole_with_backing_fallthrough() {
test_punch_hole_with_backing_fallthrough_impl(false);
}
#[test]
fn test_punch_hole_with_backing_fallthrough_direct_io() {
test_punch_hole_with_backing_fallthrough_impl(true);
}
fn test_rewrite_allocated_cluster_impl(direct_io: bool) {
// Write to a cluster, then overwrite it. The second write should hit // Write to a cluster, then overwrite it. The second write should hit
// the already allocated path in map_write (no new cluster allocation). // the already allocated path in map_write (no new cluster allocation).
let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true); let (_temp, disk) = create_disk_with_data(100 * 1024 * 1024, &[], 0, true, direct_io);
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let data1 = vec![0xAAu8; cluster_size as usize]; let data1 = vec![0xAAu8; cluster_size as usize];
@@ -1306,7 +1432,16 @@ mod unit_tests {
} }
#[test] #[test]
fn test_partial_cluster_write_with_backing_cow() { fn test_rewrite_allocated_cluster() {
test_rewrite_allocated_cluster_impl(false);
}
#[test]
fn test_rewrite_allocated_cluster_direct_io() {
test_rewrite_allocated_cluster_impl(true);
}
fn test_partial_cluster_write_with_backing_cow_impl(direct_io: bool) {
// Partial cluster write to an overlay with a backing file triggers COW. // Partial cluster write to an overlay with a backing file triggers COW.
// The unwritten part of the cluster must be copied from backing. // The unwritten part of the cluster must be copied from backing.
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
@@ -1330,7 +1465,7 @@ mod unit_tests {
} }
let file = overlay_temp.as_file().try_clone().unwrap(); let file = overlay_temp.as_file().try_clone().unwrap();
let disk = QcowDiskSync::new(file, false, true, true).unwrap(); let disk = QcowDiskSync::new(file, direct_io, true, true).unwrap();
// Write 4KB at offset 4KB within cluster 0 (partial cluster) // Write 4KB at offset 4KB within cluster 0 (partial cluster)
let write_offset = 4096u64; let write_offset = 4096u64;
@@ -1366,6 +1501,16 @@ mod unit_tests {
); );
} }
#[test]
fn test_partial_cluster_write_with_backing_cow() {
test_partial_cluster_write_with_backing_cow_impl(false);
}
#[test]
fn test_partial_cluster_write_with_backing_cow_direct_io() {
test_partial_cluster_write_with_backing_cow_impl(true);
}
#[test] #[test]
fn test_partial_cluster_deallocate() { fn test_partial_cluster_deallocate() {
// Punch hole on a partial cluster range. The deallocate_bytes path // Punch hole on a partial cluster range. The deallocate_bytes path
@@ -1376,7 +1521,7 @@ mod unit_tests {
let data: Vec<u8> = (0..2 * cluster_size as usize) let data: Vec<u8> = (0..2 * cluster_size as usize)
.map(|i| (i % 251) as u8) .map(|i| (i % 251) as u8)
.collect(); .collect();
let (_temp, disk) = create_disk_with_data(file_size, &data, 0, true); let (_temp, disk) = create_disk_with_data(file_size, &data, 0, true, false);
// Punch a partial range: last 4KB of cluster 0 + first 4KB of cluster 1 // Punch a partial range: last 4KB of cluster 0 + first 4KB of cluster 1
let punch_offset = cluster_size - 4096; let punch_offset = cluster_size - 4096;
@@ -1420,7 +1565,7 @@ mod unit_tests {
let cluster_size = 1u64 << 16; let cluster_size = 1u64 << 16;
let initial_size = cluster_size * 4; let initial_size = cluster_size * 4;
let data = vec![0xAA; cluster_size as usize]; let data = vec![0xAA; cluster_size as usize];
let (_temp, mut disk) = create_disk_with_data(initial_size, &data, 0, true); let (_temp, mut disk) = create_disk_with_data(initial_size, &data, 0, true, false);
assert_eq!(disk.logical_size().unwrap(), initial_size); assert_eq!(disk.logical_size().unwrap(), initial_size);