Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 src/firecracker/src/api_server/request/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ fn parse_put_snapshot_load(body: &Body) -> Result<ParsedRequest, RequestError> {
resume_vm: snapshot_config.resume_vm,
network_overrides: snapshot_config.network_overrides,
vsock_override: snapshot_config.vsock_override,
block_delta_dir: snapshot_config.block_delta_dir,
};

// Construct the `ParsedRequest` object.
Expand Down
22 changes: 20 additions & 2 deletions src/firecracker/swagger/firecracker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1220,10 +1220,16 @@ definitions:
type: string
description:
Type of the IO engine used by the device. "Async" is supported on
host kernels newer than 5.10.51.
host kernels newer than 5.10.51. "Overlay" enables copy-on-write
with dirty bitmap tracking for fast snapshots (requires base_path).
This field is optional for virtio-block config and should be omitted for vhost-user-block configuration.
enum: ["Sync", "Async"]
enum: ["Sync", "Async", "Overlay"]
default: "Sync"
base_path:
type: string
description:
Read-only base image path for overlay mode. Required when io_engine
is "Overlay". The path_on_host field becomes the overlay file path.

# VhostUserBlock specific parameters
socket:
Expand Down Expand Up @@ -1572,6 +1578,12 @@ definitions:
description:
Type of snapshot to create. It is optional and by default, a full
snapshot is created.
block_delta_dir:
type: string
description:
Directory for block device delta files. When set, overlay block
devices write delta files (containing only dirty blocks) into this
directory, named {drive_id}.delta.

NetworkOverride:
type: object
Expand Down Expand Up @@ -1650,6 +1662,12 @@ definitions:
for restoring a snapshot with a different socket path than the one used
when the snapshot was created. For example, when the original socket path
is no longer available or when deploying to a different environment.
block_delta_dir:
type: string
description:
Directory containing block device delta files for cloning. Each
overlay device looks for {drive_id}.delta in this directory and
applies it to a fresh overlay on restore.


TokenBucket:
Expand Down
1 change: 1 addition & 0 deletions src/vmm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,7 @@ pub(crate) mod tests {
file_engine_type: None,

socket: None,
base_path: None,
};

block_dev_configs
Expand Down
37 changes: 37 additions & 0 deletions src/vmm/src/device_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,43 @@ impl DeviceManager {
}
}

/// Write delta files for all overlay block devices into the given directory.
/// Each delta file is named `{drive_id}.delta`.
/// Returns the first error encountered, if any.
pub fn write_block_deltas(
&self,
delta_dir: &std::path::Path,
) -> Result<(), crate::devices::virtio::block::virtio::io::delta::DeltaError> {
use crate::devices::virtio::block::device::Block;
use crate::devices::virtio::device::VirtioDeviceType;

let mut first_error: Option<crate::devices::virtio::block::virtio::io::delta::DeltaError> =
None;

let _: Result<(), Infallible> =
self.mmio_devices
.for_each_virtio_mmio_device(|_, _, device| {
let mmio_transport_locked = device.inner.lock().expect("Poisoned lock");
let mut locked_device = mmio_transport_locked.locked_device();
if locked_device.device_type() == VirtioDeviceType::Block {
let block = locked_device.as_mut_any().downcast_mut::<Block>().unwrap();
let delta_path = delta_dir.join(format!("{}.delta", block.id()));
if let Err(e) = block.write_delta(&delta_path) {
error!("Failed to write block delta for {}: {:?}", block.id(), e);
if first_error.is_none() {
first_error = Some(e);
}
}
}
Ok(())
});

match first_error {
Some(e) => Err(e),
None => Ok(()),
}
}

/// Mark queue memory dirty for activated VirtIO devices
pub fn mark_virtio_queue_memory_dirty(&self, mem: &GuestMemoryMmap) {
// Go through MMIO VirtIO devices
Expand Down
14 changes: 14 additions & 0 deletions src/vmm/src/devices/virtio/block/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use event_manager::{EventOps, Events, MutEventSubscriber};
use log::info;
use vmm_sys_util::eventfd::EventFd;

use std::path::Path;

use super::BlockError;
use super::persist::{BlockConstructorArgs, BlockState};
use super::vhost_user::device::{VhostUserBlock, VhostUserBlockConfig};
use super::virtio::device::{VirtioBlock, VirtioBlockConfig};
use super::virtio::io::delta;
use crate::devices::virtio::ActivateError;
use crate::devices::virtio::device::{VirtioDevice, VirtioDeviceType};
use crate::devices::virtio::queue::{InvalidAvailIdx, Queue};
Expand Down Expand Up @@ -115,6 +118,17 @@ impl Block {
Self::VhostUser(_) => true,
}
}

/// Write a delta file if this block device uses an overlay engine.
pub fn write_delta(
&mut self,
delta_path: &Path,
) -> Result<Option<delta::DeltaStats>, delta::DeltaError> {
match self {
Self::Virtio(b) => b.write_delta(delta_path),
Self::VhostUser(_) => Ok(None),
}
}
}

impl VirtioDevice for Block {
Expand Down
4 changes: 4 additions & 0 deletions src/vmm/src/devices/virtio/block/vhost_user/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl From<VhostUserBlockConfig> for BlockDeviceConfig {
file_engine_type: None,

socket: Some(value.socket),
base_path: None,
}
}
}
Expand Down Expand Up @@ -416,6 +417,7 @@ mod tests {
file_engine_type: None,

socket: Some("sock".to_string()),
base_path: None,
};
VhostUserBlockConfig::try_from(&block_config).unwrap();

Expand All @@ -431,6 +433,7 @@ mod tests {
file_engine_type: Some(FileEngineType::Sync),

socket: None,
base_path: None,
};
VhostUserBlockConfig::try_from(&block_config).unwrap_err();

Expand All @@ -446,6 +449,7 @@ mod tests {
file_engine_type: Some(FileEngineType::Sync),

socket: Some("sock".to_string()),
base_path: None,
};
VhostUserBlockConfig::try_from(&block_config).unwrap_err();
}
Expand Down
Loading