From 1e66c144f4950e7f3c1999f42cd49c8f7b649414 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 30 Mar 2026 22:55:45 +0200 Subject: [PATCH] block: qcow: Test async write and read roundtrip Add a QcowAsync unit test that writes a byte pattern through write_vectored, reads it back through read_vectored, and verifies the data matches. This exercises the core async write and read paths end to end. Also add an async_write helper for future tests. Signed-off-by: Anatol Belski --- block/src/qcow_async.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/block/src/qcow_async.rs b/block/src/qcow_async.rs index a01acf604..31ad2584d 100644 --- a/block/src/qcow_async.rs +++ b/block/src/qcow_async.rs @@ -612,6 +612,7 @@ mod unit_tests { if let Some(c) = async_io.next_completed_request() { return c; } + // Block until the eventfd is signaled (io_uring or synthetic). let fd = async_io.notifier().as_raw_fd(); let mut val = 0u64; // SAFETY: reading 8 bytes from a valid eventfd. @@ -621,6 +622,24 @@ mod unit_tests { } } + fn async_write(disk: &QcowDiskAsync, offset: u64, data: &[u8]) { + let mut async_io = disk.new_async_io(1).unwrap(); + let iovec = libc::iovec { + iov_base: data.as_ptr() as *mut libc::c_void, + iov_len: data.len(), + }; + async_io + .write_vectored(offset as libc::off_t, &[iovec], 2) + .unwrap(); + let (user_data, result) = wait_for_completion(async_io.as_mut()); + assert_eq!(user_data, 2); + assert_eq!( + result as usize, + data.len(), + "write should return requested length" + ); + } + fn async_read(disk: &QcowDiskAsync, offset: u64, len: usize) -> Vec { let mut async_io = disk.new_async_io(1).unwrap(); let mut buf = vec![0xFFu8; len]; @@ -678,4 +697,23 @@ mod unit_tests { "Write zeroes region should read as zeros" ); } + + #[test] + fn test_qcow_async_write_read_roundtrip() { + 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 pattern: Vec = (0..128 * 1024).map(|i| (i % 251) as u8).collect(); + let offset = 64 * 1024; + + async_write(&disk, offset, &pattern); + let read_buf = async_read(&disk, offset, pattern.len()); + assert_eq!(read_buf, pattern, "read should match written data"); + } }