Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4a93056
block: add mirror module skeleton
Coffeeri Apr 27, 2026
ba0a313
block: add MirroringAsyncIo skeleton
Coffeeri Apr 27, 2026
ead674c
block: add range lock primitive for mirror
Coffeeri Apr 28, 2026
9499d54
block: add CompletionIo for single-fd waits
Coffeeri Apr 29, 2026
fdec499
block: mirror mutating I/O to destination
Coffeeri Apr 28, 2026
ba1a18c
block: add background copy worker for mirror
Coffeeri Apr 29, 2026
bebb71e
virtio-devices: swap disk_image via queue commands
Coffeeri Apr 29, 2026
b05d425
virtio-devices: set up mirror command channels
Coffeeri Apr 29, 2026
835e72d
virtio-devices, block: add Block::start_mirror
Coffeeri Apr 30, 2026
502383d
vmm: add device manager block mirror start and status
Coffeeri Apr 30, 2026
605f4d9
vmm: add vm.disk-mirror-start REST endpoint
Coffeeri Apr 30, 2026
0541a88
vmm: add vm.disk-mirror-status REST endpoint
Coffeeri Apr 30, 2026
0f06cf6
virtio-devices, block: add Block::complete_mirror
Coffeeri May 3, 2026
07f181b
vmm: add vm.disk-mirror-complete REST endpoint
Coffeeri May 3, 2026
0d04dbd
virtio-devices, block: add Block::cancel_mirror
Coffeeri Jun 10, 2026
89a1b84
vmm: deny conflicting ops while a disk mirror runs
Coffeeri Jun 10, 2026
933e7ca
block: use source passthrough after mirror failure
Coffeeri Jul 23, 2026
6c307bd
vmm: add vm.disk-mirror-cancel REST endpoint
Coffeeri Jun 11, 2026
00078cb
block: preserve sparseness in CopyWorker
Coffeeri Jun 17, 2026
f089990
block: add mirror unit tests
Coffeeri Jun 22, 2026
5e227a6
block: test range guard held across mirror write
Coffeeri Jun 23, 2026
1515d98
virtio-devices, block: reject mirror ops on a paused device
Coffeeri Jun 23, 2026
b8af3af
vmm: reject mirror destination already backing a disk
Coffeeri Jun 24, 2026
1b7ee95
block: test mirror phase transitions and op fan-out
Coffeeri Jun 24, 2026
acff34c
docs: add disk mirroring guide
Coffeeri Jun 25, 2026
4252793
vmm: dedup block device lookup in DeviceManager
Coffeeri Jul 6, 2026
89de6e3
virtio-devices, vmm: lock mirror destination
Coffeeri Jul 13, 2026
da12203
block: reject QCOW2 backing chains for mirroring
Coffeeri Jul 20, 2026
34374ef
vmm: generalize postponed lifecycle events
Coffeeri Jul 21, 2026
07b12fc
vmm: postpone guest lifecycle for disk mirrors
Coffeeri Jul 21, 2026
13643c6
virtio-devices, block: emit disk mirror events
Coffeeri Aug 12, 2026
9ce1b29
virtio-devices: drain queues before a mirror switch-over
Coffeeri Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions block/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ io_uring = ["dep:io-uring"]
bitflags = { workspace = true }
byteorder = { workspace = true }
crc-any = "2.5.0"
event_monitor = { path = "../event_monitor" }
flate2 = "1.1"
io-uring = { version = "0.7.12", optional = true }
libc = { workspace = true }
Expand Down
23 changes: 23 additions & 0 deletions block/src/async_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause

use std::io;
use std::marker::PhantomData;
use std::os::fd::{AsRawFd, OwnedFd, RawFd};

Expand Down Expand Up @@ -58,6 +59,28 @@ impl AsRawFd for BorrowedDiskFd<'_> {
}
}

/// Returns true when `left` and `right` refer to the same file.
pub fn is_same_file(left: BorrowedDiskFd, right: BorrowedDiskFd) -> bool {
matches!(
(file_identity(left), file_identity(right)),
(Ok(left), Ok(right)) if left == right
)
}

/// Returns the `(device ID, inode number)` identity of the file behind `fd`.
fn file_identity(fd: BorrowedDiskFd) -> io::Result<(u64, u64)> {
let mut stat = std::mem::MaybeUninit::<libc::stat>::zeroed();
// SAFETY: `stat` points to writable memory for one `libc::stat`.
// `fstat` does not close or take ownership of the borrowed file descriptor.
let ret = unsafe { libc::fstat(fd.as_raw_fd(), stat.as_mut_ptr()) };
if ret != 0 {
return Err(io::Error::last_os_error());
}
// SAFETY: the zeroed buffer is a valid `libc::stat`.
let stat = unsafe { stat.assume_init() };
Ok((stat.st_dev, stat.st_ino))
}

#[derive(Error, Debug)]
pub enum AsyncIoError {
/// Failed vectored reading from file.
Expand Down
9 changes: 7 additions & 2 deletions block/src/disk_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
use std::fmt::Debug;

use crate::async_io::{AsyncIo, BorrowedDiskFd};
use crate::{BlockResult, DiskTopology};
use crate::{BlockError, BlockErrorKind, BlockResult, DiskTopology};

/// Reported capacity of a disk image.
pub trait DiskSize: Send + Debug {
Expand Down Expand Up @@ -96,7 +96,12 @@ pub trait Resizable: Send + Debug {
/// Every disk format implements `DiskSize` and `Geometry`.
/// `Sync` is required so that `Arc<dyn DiskFile>` can be shared
/// across threads for concurrent readonly access.
pub trait DiskFile: DiskSize + Geometry + Sync {}
pub trait DiskFile: DiskSize + Geometry + Sync {
/// Returns an error if this disk image cannot participate in block mirroring.
fn supports_mirroring(&self) -> BlockResult<()> {
Err(BlockError::from_kind(BlockErrorKind::UnsupportedFeature))
}
Comment thread
arctic-alpaca marked this conversation as resolved.
}

/// Full capability disk file trait.
///
Expand Down
1 change: 1 addition & 0 deletions block/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod fixed_vhd;
pub mod fixed_vhd_async;
pub mod fixed_vhd_disk;
pub mod fixed_vhd_sync;
pub mod mirror;
pub mod qcow;
#[cfg(feature = "io_uring")]
pub(crate) mod qcow_async;
Expand Down
Loading
Loading