block: qcow: Test async batch mixed requests

Add a QcowAsync unit test that submits a batch of interleaved
write and read requests via submit_batch_requests. Verifies that
all completions arrive with the correct user_data and that the
read back data matches the written data.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-03-30 23:04:56 +02:00
committed by Rob Bradford
parent 093922ff24
commit 34a9f7246d

View File

@@ -582,6 +582,7 @@ mod unit_tests {
use super::*;
use crate::disk_file::AsyncDiskFile;
use crate::qcow::{QcowFile, RawFile};
use crate::{BatchRequest, RequestType};
fn create_disk_with_data(
file_size: u64,
@@ -742,4 +743,100 @@ mod unit_tests {
"second half should come from cluster 1"
);
}
#[test]
fn test_qcow_async_batch_mixed_requests() {
let file_size = 100 * 1024 * 1024;
let temp_file = TempFile::new().unwrap();
{
let raw_file = RawFile::new(temp_file.as_file().try_clone().unwrap(), false);
QcowFile::new(raw_file, 3, file_size, true).unwrap();
}
let disk = QcowDiskAsync::new(temp_file.as_file().try_clone().unwrap(), false, false, true)
.unwrap();
let mut async_io = disk.new_async_io(8).unwrap();
// Prepare write data for two regions.
let write_a = vec![0xAA; 4096];
let write_b = vec![0xBB; 4096];
let offset_a: u64 = 0;
let offset_b: u64 = 65536;
let iov_a = libc::iovec {
iov_base: write_a.as_ptr() as *mut libc::c_void,
iov_len: write_a.len(),
};
let iov_b = libc::iovec {
iov_base: write_b.as_ptr() as *mut libc::c_void,
iov_len: write_b.len(),
};
let batch = vec![
BatchRequest {
offset: offset_a as libc::off_t,
iovecs: smallvec::smallvec![iov_a],
user_data: 10,
request_type: RequestType::Out,
},
BatchRequest {
offset: offset_b as libc::off_t,
iovecs: smallvec::smallvec![iov_b],
user_data: 20,
request_type: RequestType::Out,
},
];
async_io.submit_batch_requests(&batch).unwrap();
let mut completions = [
wait_for_completion(async_io.as_mut()),
wait_for_completion(async_io.as_mut()),
];
completions.sort_by_key(|c| c.0);
assert_eq!(completions[0], (10, 4096));
assert_eq!(completions[1], (20, 4096));
drop(async_io);
// Batch read both regions back.
let mut read_a = vec![0u8; 4096];
let mut read_b = vec![0u8; 4096];
let riov_a = libc::iovec {
iov_base: read_a.as_mut_ptr() as *mut libc::c_void,
iov_len: read_a.len(),
};
let riov_b = libc::iovec {
iov_base: read_b.as_mut_ptr() as *mut libc::c_void,
iov_len: read_b.len(),
};
let mut async_io = disk.new_async_io(8).unwrap();
let read_batch = vec![
BatchRequest {
offset: offset_a as libc::off_t,
iovecs: smallvec::smallvec![riov_a],
user_data: 30,
request_type: RequestType::In,
},
BatchRequest {
offset: offset_b as libc::off_t,
iovecs: smallvec::smallvec![riov_b],
user_data: 40,
request_type: RequestType::In,
},
];
async_io.submit_batch_requests(&read_batch).unwrap();
let mut completions = [
wait_for_completion(async_io.as_mut()),
wait_for_completion(async_io.as_mut()),
];
completions.sort_by_key(|c| c.0);
assert_eq!(completions[0], (30, 4096));
assert_eq!(completions[1], (40, 4096));
assert_eq!(read_a, write_a, "batch read A should match written data");
assert_eq!(read_b, write_b, "batch read B should match written data");
}
}