From a541baa9e42a97a6d117ff6017f46513e75c4d69 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Tue, 19 May 2026 14:36:58 -0700 Subject: [PATCH] block: Add owned fixed VHD io_uring I/O path Add the new AsyncIo apis to fixed_vhd_async. Later commits update callers to use them and remove their unsound counterparts that take iovecs. While doing this, make the owned path validate offset plus length instead of only the starting offset, so requests that extend past the VHD size are rejected. Signed-off-by: Dylan Reid --- block/src/fixed_vhd_async.rs | 55 ++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/block/src/fixed_vhd_async.rs b/block/src/fixed_vhd_async.rs index 58dbc9a93..975ac6be4 100644 --- a/block/src/fixed_vhd_async.rs +++ b/block/src/fixed_vhd_async.rs @@ -1,5 +1,7 @@ // Copyright © 2021 Intel Corporation // +// Copyright (c) Meta Platforms, Inc. and affiliates. +// // SPDX-License-Identifier: Apache-2.0 use std::os::unix::io::RawFd; @@ -7,7 +9,7 @@ use std::os::unix::io::RawFd; use vmm_sys_util::eventfd::EventFd; use crate::BatchRequest; -use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; +use crate::async_io::{AsyncIo, AsyncIoCompletion, AsyncIoError, AsyncIoOperation, AsyncIoResult}; use crate::error::BlockResult; use crate::raw_async::RawFileAsync; @@ -25,6 +27,37 @@ impl FixedVhdAsync { size, }) } + + fn validate_operation_bounds(&self, op: &AsyncIoOperation) -> AsyncIoResult<()> { + let offset = u64::try_from(op.offset()).map_err(|_| self.bounds_error(op))?; + let len = u64::try_from(op.total_len()).map_err(|_| self.bounds_error(op))?; + let end = offset + .checked_add(len) + .ok_or_else(|| self.bounds_error(op))?; + + if end > self.size { + return Err(self.bounds_error(op)); + } + + Ok(()) + } + + fn bounds_error(&self, op: &AsyncIoOperation) -> AsyncIoError { + let error = std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!( + "Invalid request offset {} and length {}, can't exceed file size {}", + op.offset(), + op.total_len(), + self.size + ), + ); + if op.is_read() { + AsyncIoError::ReadVectored(error) + } else { + AsyncIoError::WriteVectored(error) + } + } } impl AsyncIo for FixedVhdAsync { @@ -71,12 +104,17 @@ impl AsyncIo for FixedVhdAsync { .write_vectored(offset, iovecs, user_data) } + fn submit_data_operation(&mut self, op: AsyncIoOperation) -> AsyncIoResult<()> { + self.validate_operation_bounds(&op)?; + self.raw_file_async.submit_data_operation(op) + } + fn fsync(&mut self, user_data: Option) -> AsyncIoResult<()> { self.raw_file_async.fsync(user_data) } - fn next_completed_request(&mut self) -> Option<(u64, i32)> { - self.raw_file_async.next_completed_request() + fn next_completion(&mut self) -> Option { + self.raw_file_async.next_completion() } fn punch_hole(&mut self, _offset: u64, _length: u64, _user_data: u64) -> AsyncIoResult<()> { @@ -98,4 +136,15 @@ impl AsyncIo for FixedVhdAsync { fn submit_batch_requests(&mut self, batch_request: &[BatchRequest]) -> AsyncIoResult<()> { self.raw_file_async.submit_batch_requests(batch_request) } + + fn submit_batch_operations( + &mut self, + batch_request: Vec, + ) -> AsyncIoResult<()> { + for op in &batch_request { + self.validate_operation_bounds(op)?; + } + + self.raw_file_async.submit_batch_operations(batch_request) + } }