Add capability query to DiskFile trait to check backend support for sparse operations (punch hole, write zeroes, discard). Only advertise VIRTIO_BLK_F_DISCARD and VIRTIO_BLK_F_WRITE_ZEROES when the backend supports these operations. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
142 lines
4.6 KiB
Rust
142 lines
4.6 KiB
Rust
// Copyright © 2021 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
|
|
|
use std::marker::PhantomData;
|
|
use std::os::fd::{AsRawFd, OwnedFd, RawFd};
|
|
|
|
use thiserror::Error;
|
|
use vmm_sys_util::eventfd::EventFd;
|
|
|
|
use crate::{BatchRequest, DiskTopology};
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum DiskFileError {
|
|
/// Failed getting disk file size.
|
|
#[error("Failed getting disk file size")]
|
|
Size(#[source] std::io::Error),
|
|
/// Failed creating a new AsyncIo.
|
|
#[error("Failed creating a new AsyncIo")]
|
|
NewAsyncIo(#[source] std::io::Error),
|
|
/// Unsupported operation.
|
|
#[error("Unsupported operation")]
|
|
Unsupported,
|
|
/// Resize failed
|
|
#[error("Resize failed")]
|
|
ResizeError(#[source] std::io::Error),
|
|
}
|
|
|
|
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
|
|
|
|
/// A wrapper for [`RawFd`] capturing the lifetime of a corresponding [`DiskFile`].
|
|
///
|
|
/// This fulfills the same role as [`BorrowedFd`] but is tailored to the limitations
|
|
/// by some implementations of [`DiskFile`], which wrap the effective [`File`]
|
|
/// in an `Arc<Mutex<T>>`, making the use of [`BorrowedFd`] impossible.
|
|
///
|
|
/// [`BorrowedFd`]: std::os::fd::BorrowedFd
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct BorrowedDiskFd<'fd> {
|
|
raw_fd: RawFd,
|
|
_lifetime: PhantomData<&'fd OwnedFd>,
|
|
}
|
|
|
|
impl BorrowedDiskFd<'_> {
|
|
pub(super) fn new(raw_fd: RawFd) -> Self {
|
|
Self {
|
|
raw_fd,
|
|
_lifetime: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AsRawFd for BorrowedDiskFd<'_> {
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
self.raw_fd
|
|
}
|
|
}
|
|
|
|
/// Abstraction over the effective [`File`] backing up a block device,
|
|
/// with support for synchronous and asynchronous I/O.
|
|
///
|
|
/// This allows abstracting over raw image formats as well as structured
|
|
/// image formats.
|
|
pub trait DiskFile: Send {
|
|
/// Returns the logical disk size a guest will see.
|
|
///
|
|
/// For raw formats, this is equal to [`Self::physical_size`]. For file formats
|
|
/// that wrap disk images in a container (e.g. QCOW2), this refers to the
|
|
/// effective size that the guest will see.
|
|
fn logical_size(&mut self) -> DiskFileResult<u64>;
|
|
/// Returns the physical size of the underlying file.
|
|
fn physical_size(&mut self) -> DiskFileResult<u64>;
|
|
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
|
|
fn topology(&mut self) -> DiskTopology {
|
|
DiskTopology::default()
|
|
}
|
|
fn resize(&mut self, _size: u64) -> DiskFileResult<()> {
|
|
Err(DiskFileError::Unsupported)
|
|
}
|
|
|
|
/// Indicates support for sparse operations (punch hole, write zeroes, discard).
|
|
/// Override to return true when supported.
|
|
fn supports_sparse_operations(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
/// Returns the file descriptor of the underlying disk image file.
|
|
///
|
|
/// The file descriptor is supposed to be used for `fcntl()` calls but no
|
|
/// other operation.
|
|
fn fd(&mut self) -> BorrowedDiskFd<'_>;
|
|
}
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum AsyncIoError {
|
|
/// Failed vectored reading from file.
|
|
#[error("Failed vectored reading from file")]
|
|
ReadVectored(#[source] std::io::Error),
|
|
/// Failed vectored writing to file.
|
|
#[error("Failed vectored writing to file")]
|
|
WriteVectored(#[source] std::io::Error),
|
|
/// Failed synchronizing file.
|
|
#[error("Failed synchronizing file")]
|
|
Fsync(#[source] std::io::Error),
|
|
/// Failed punching hole.
|
|
#[error("Failed punching hole")]
|
|
PunchHole(#[source] std::io::Error),
|
|
/// Failed writing zeroes.
|
|
#[error("Failed writing zeroes")]
|
|
WriteZeroes(#[source] std::io::Error),
|
|
/// Failed submitting batch requests.
|
|
#[error("Failed submitting batch requests")]
|
|
SubmitBatchRequests(#[source] std::io::Error),
|
|
}
|
|
|
|
pub type AsyncIoResult<T> = std::result::Result<T, AsyncIoError>;
|
|
|
|
pub trait AsyncIo: Send {
|
|
fn notifier(&self) -> &EventFd;
|
|
fn read_vectored(
|
|
&mut self,
|
|
offset: libc::off_t,
|
|
iovecs: &[libc::iovec],
|
|
user_data: u64,
|
|
) -> AsyncIoResult<()>;
|
|
fn write_vectored(
|
|
&mut self,
|
|
offset: libc::off_t,
|
|
iovecs: &[libc::iovec],
|
|
user_data: u64,
|
|
) -> AsyncIoResult<()>;
|
|
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()>;
|
|
fn punch_hole(&mut self, offset: u64, length: u64, user_data: u64) -> AsyncIoResult<()>;
|
|
fn write_zeroes(&mut self, offset: u64, length: u64, user_data: u64) -> AsyncIoResult<()>;
|
|
fn next_completed_request(&mut self) -> Option<(u64, i32)>;
|
|
fn batch_requests_enabled(&self) -> bool {
|
|
false
|
|
}
|
|
fn submit_batch_requests(&mut self, _batch_request: &[BatchRequest]) -> AsyncIoResult<()> {
|
|
Ok(())
|
|
}
|
|
}
|