#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn main() {
use std::time::Duration;
use supermachine::vmm::resources::VolumeSpec;
use supermachine::{Image, VmConfig};
let dir = "/tmp/supermachine-vol-fork";
let bake_backing = "/tmp/supermachine-vol-fork-bake.img";
let fork_a_backing = "/tmp/supermachine-vol-fork-a.img";
let fork_b_backing = "/tmp/supermachine-vol-fork-b.img";
for p in [bake_backing, fork_a_backing, fork_b_backing] {
let _ = std::fs::remove_file(p);
}
let _ = std::fs::remove_dir_all(dir);
const SIZE: u64 = 64 * 1024 * 1024;
eprintln!("=== BAKE: boot with a placeholder volume at /data, live-snapshot ===");
let bake_cfg =
VmConfig::new().with_volume(VolumeSpec::new(bake_backing, "/data").with_size_bytes(SIZE));
let image = Image::from_oci("alpine").expect("from_oci");
let vm = image.start(&bake_cfg).expect("bake start");
std::thread::sleep(Duration::from_millis(5000));
let baked = vm
.exec_builder()
.argv(["/bin/sh", "-c", "mount | grep -c ' /data '"])
.output()
.expect("bake exec");
eprintln!(
"bake: mounted={:?}",
String::from_utf8_lossy(&baked.stdout).trim_end()
);
let snap = vm.snapshot_live(dir).expect("snapshot_live");
vm.stop().expect("bake stop");
let run_fork = |label: &str, backing: &str, marker: &str| -> (bool, String) {
eprintln!("=== FORK {label}: restore with VmConfig::with_volume -> {backing} ===");
let cfg =
VmConfig::new().with_volume(VolumeSpec::new(backing, "/data").with_size_bytes(SIZE));
let vm = snap.start(&cfg).expect("fork start");
std::thread::sleep(Duration::from_millis(3000));
let w = vm
.exec_builder()
.argv([
"/bin/sh",
"-c",
&format!(
"M=$(mount | grep -c ' /data '); \
echo {marker} > /data/who; sync; \
P=$(cat /data/who 2>/dev/null); echo mounted=$M who=$P"
),
])
.output()
.expect("fork exec");
let got = String::from_utf8_lossy(&w.stdout).trim_end().to_string();
eprintln!("fork {label}: success={} {got:?}", w.success());
vm.stop().ok();
(
w.success() && got.contains("mounted=1") && got.contains(&format!("who={marker}")),
got,
)
};
let (a_ok, _a_got) = run_fork("A", fork_a_backing, "fork-a");
let (b_ok, _b_got) = run_fork("B", fork_b_backing, "fork-b");
let pass = a_ok && b_ok;
eprintln!(
"=== VOLUME-FORK-SWAP: {} (fork_a={a_ok} fork_b={b_ok}) ===",
if pass { "PASS" } else { "FAIL" }
);
assert!(pass, "per-fork volume backing swap on restore failed");
}
#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
fn main() {
eprintln!("kvm_volume_fork is Linux/x86_64 only");
}