Skip to content

Commit 2a322c8

Browse files
committed
vmm: Remove bitmaps before resizing VM disk
1 parent 17d4cd1 commit 2a322c8

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

vmm/src/main_service.rs

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::ops::Deref;
2+
use std::process::Command;
23
use std::time::{SystemTime, UNIX_EPOCH};
34

45
use anyhow::{anyhow, bail, Context, Result};
@@ -130,6 +131,47 @@ fn check_path_traversal(input: &str) -> Result<()> {
130131
Ok(())
131132
}
132133

134+
fn run_cmd(exec: &str, args: &[&str]) -> Result<Vec<u8>> {
135+
let mut cmd = Command::new(exec);
136+
cmd.args(args);
137+
let output = cmd
138+
.output()
139+
.with_context(|| format!("Failed to run command: {cmd:?}"))?;
140+
if !output.status.success() {
141+
let err = String::from_utf8_lossy(&output.stderr);
142+
bail!("Failed to run command {cmd:?}: {err}");
143+
}
144+
Ok(output.stdout)
145+
}
146+
147+
fn remove_all_qemu_bitmaps(disk_path: &str) -> Result<()> {
148+
// Get JSON info
149+
let output = run_cmd("qemu-img", &["info", "--output=json", disk_path])?;
150+
let info: serde_json::Value = serde_json::from_slice(&output)?;
151+
// Extract and remove bitmaps
152+
let Some(bitmaps) = info.pointer("/format-specific/data/bitmaps") else {
153+
return Ok(());
154+
};
155+
let bitmaps = bitmaps
156+
.as_array()
157+
.context("The bitmaps field is not an array")?;
158+
for bitmap in bitmaps {
159+
let Some(name) = bitmap["name"].as_str() else {
160+
info!("Invalid bitmap: {bitmap:?}");
161+
continue;
162+
};
163+
run_cmd("qemu-img", &["bitmap", "--remove", disk_path, name])?;
164+
info!("Removed bitmap {name} for {disk_path}");
165+
}
166+
Ok(())
167+
}
168+
169+
fn resize_qcow2(disk_path: &str, size_gb: u32) -> Result<()> {
170+
let new_size_str = format!("{}G", size_gb);
171+
run_cmd("qemu-img", &["resize", disk_path, &new_size_str])?;
172+
Ok(())
173+
}
174+
133175
impl RpcHandler {
134176
fn resolve_gpus(&self, gpu_cfg: &rpc::GpuConfig) -> Result<GpuConfig> {
135177
let gpus = resolve_gpus(gpu_cfg)?;
@@ -391,26 +433,19 @@ impl VmmRpc for RpcHandler {
391433
if let Some(image) = request.image {
392434
manifest.image = image;
393435
}
394-
if let Some(disk_size) = request.disk_size {
436+
let resize_disk_to = request
437+
.disk_size
438+
.filter(|&disk_size| disk_size != manifest.disk_size);
439+
if let Some(disk_size) = resize_disk_to {
395440
if disk_size < manifest.disk_size {
396441
bail!("Cannot shrink disk size");
397442
}
398-
manifest.disk_size = disk_size;
399-
400-
// Run qemu-img resize to resize the disk
401443
info!("Resizing disk to {}GB", disk_size);
402444
let hda_path = vm_work_dir.hda_path();
403-
let new_size_str = format!("{}G", disk_size);
404-
let output = std::process::Command::new("qemu-img")
405-
.args(["resize", &hda_path.display().to_string(), &new_size_str])
406-
.output()
407-
.context("Failed to resize disk")?;
408-
if !output.status.success() {
409-
bail!(
410-
"Failed to resize disk: {}",
411-
String::from_utf8_lossy(&output.stderr)
412-
);
413-
}
445+
let hda_str = hda_path.display().to_string();
446+
remove_all_qemu_bitmaps(&hda_str).context("Failed to remove qemu bitmaps")?;
447+
resize_qcow2(&hda_str, disk_size).context("Failed to resize disk")?;
448+
manifest.disk_size = disk_size;
414449
}
415450
vm_work_dir
416451
.put_manifest(&manifest)

0 commit comments

Comments
 (0)