From e345299f4de1f5af7963aea7050f350d36fc9d68 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Fri, 20 Mar 2026 16:03:24 +0100 Subject: [PATCH] block: qcow: Move RawBacking to qcow/backing module Move the raw backing file reader into the new qcow/backing module so it can be shared between qcow_sync and the upcoming qcow_async backend. Signed-off-by: Anatol Belski --- block/src/qcow/backing.rs | 40 +++++++++++++++++++++++++++++++++++++++ block/src/qcow/mod.rs | 1 + block/src/qcow_sync.rs | 28 +-------------------------- 3 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 block/src/qcow/backing.rs diff --git a/block/src/qcow/backing.rs b/block/src/qcow/backing.rs new file mode 100644 index 000000000..1ad1b74b9 --- /dev/null +++ b/block/src/qcow/backing.rs @@ -0,0 +1,40 @@ +// Copyright © 2021 Intel Corporation +// +// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause + +//! Thread safe backing file readers for QCOW2 images. + +use std::io; +use std::os::fd::{AsRawFd, OwnedFd}; + +use crate::qcow::metadata::BackingRead; +use crate::qcow_common::pread_exact; + +/// Raw backing file using pread64 on a duplicated fd. +pub(crate) struct RawBacking { + pub(crate) fd: OwnedFd, + pub(crate) virtual_size: u64, +} + +// SAFETY: The only I/O operation is pread64 which is position independent +// and safe for concurrent use from multiple threads. +unsafe impl Sync for RawBacking {} + +impl BackingRead for RawBacking { + fn read_at(&self, address: u64, buf: &mut [u8]) -> io::Result<()> { + if address >= self.virtual_size { + buf.fill(0); + return Ok(()); + } + let available = (self.virtual_size - address) as usize; + if available >= buf.len() { + pread_exact(self.fd.as_raw_fd(), buf, address) + } else { + pread_exact(self.fd.as_raw_fd(), &mut buf[..available], address)?; + buf[available..].fill(0); + Ok(()) + } + } +} diff --git a/block/src/qcow/mod.rs b/block/src/qcow/mod.rs index 0c77b865c..4fc4916f3 100644 --- a/block/src/qcow/mod.rs +++ b/block/src/qcow/mod.rs @@ -4,6 +4,7 @@ // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause +pub(crate) mod backing; mod decoder; mod header; pub(crate) mod metadata; diff --git a/block/src/qcow_sync.rs b/block/src/qcow_sync.rs index 694fe80af..5665ad475 100644 --- a/block/src/qcow_sync.rs +++ b/block/src/qcow_sync.rs @@ -15,6 +15,7 @@ use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt}; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFileError}; use crate::disk_file; use crate::error::{BlockError, BlockErrorKind, BlockResult, ErrorOp}; +use crate::qcow::backing::RawBacking; use crate::qcow::metadata::{ BackingRead, ClusterReadMapping, ClusterWriteMapping, DeallocAction, QcowMetadata, }; @@ -26,33 +27,6 @@ use crate::qcow_common::{ gather_from_iovecs, pread_exact, pwrite_all, scatter_to_iovecs, zero_fill_iovecs, }; -/// Raw backing file using pread64 on a duplicated fd. -struct RawBacking { - fd: OwnedFd, - virtual_size: u64, -} - -// SAFETY: The only I/O operation is pread64 which is position independent -// and safe for concurrent use from multiple threads. -unsafe impl Sync for RawBacking {} - -impl BackingRead for RawBacking { - fn read_at(&self, address: u64, buf: &mut [u8]) -> io::Result<()> { - if address >= self.virtual_size { - buf.fill(0); - return Ok(()); - } - let available = (self.virtual_size - address) as usize; - if available >= buf.len() { - pread_exact(self.fd.as_raw_fd(), buf, address) - } else { - pread_exact(self.fd.as_raw_fd(), &mut buf[..available], address)?; - buf[available..].fill(0); - Ok(()) - } - } -} - /// QCOW2 backing file with RwLock metadata and pread64 data reads. /// /// Read only because backing files never receive writes. Nested backing