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 <dgreid@fb.com>
This commit is contained in:
Dylan Reid
2026-05-19 14:36:58 -07:00
committed by Rob Bradford
parent 849dace891
commit a541baa9e4

View File

@@ -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<u64>) -> 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<AsyncIoCompletion> {
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<AsyncIoOperation>,
) -> AsyncIoResult<()> {
for op in &batch_request {
self.validate_operation_bounds(op)?;
}
self.raw_file_async.submit_batch_operations(batch_request)
}
}