Skip to content

Commit f87c977

Browse files
authored
Merge pull request #594 from Dstack-TEE/worktree-vmm-no-delete-workdir
fix(vmm): preserve orphan VM workdir on restart
2 parents 06a8fe5 + 6cdb79c commit f87c977

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

vmm/src/app.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -302,17 +302,17 @@ impl App {
302302
// Persist the removing marker so crash recovery can resume
303303
let work_dir = self.work_dir(id);
304304
if let Err(err) = work_dir.set_removing() {
305-
warn!("Failed to write .removing marker for {id}: {err:?}");
305+
warn!("failed to write .removing marker for {id}: {err:?}");
306306
}
307307

308308
// Clean up port forwarding immediately
309309
self.cleanup_port_forward(id).await;
310310

311-
// Spawn background cleanup coroutine
311+
// User-initiated removal always deletes the workdir
312312
let app = self.clone();
313313
let id = id.to_string();
314314
tokio::spawn(async move {
315-
if let Err(err) = app.finish_remove_vm(&id).await {
315+
if let Err(err) = app.finish_remove_vm(&id, true).await {
316316
error!("Background cleanup failed for {id}: {err:?}");
317317
}
318318
});
@@ -321,8 +321,10 @@ impl App {
321321
}
322322

323323
/// Background cleanup: stop supervisor process, wait for it to exit,
324-
/// remove from supervisor, delete workdir, and free CID.
325-
async fn finish_remove_vm(&self, id: &str) -> Result<()> {
324+
/// remove from supervisor, optionally delete workdir, and free CID.
325+
///
326+
/// `delete_workdir`: true for user-initiated removal, false for orphan cleanup.
327+
async fn finish_remove_vm(&self, id: &str, delete_workdir: bool) -> Result<()> {
326328
// Stop the supervisor process (idempotent if already stopped)
327329
if let Err(err) = self.supervisor.stop(id).await {
328330
debug!("supervisor.stop({id}) during removal: {err:?}");
@@ -361,12 +363,20 @@ impl App {
361363
}
362364
}
363365

364-
// Delete the workdir (may already be gone, e.g. manual deletion before reload)
366+
// Only delete the workdir for user-initiated removal or if .removing marker exists.
367+
// Orphaned supervisor processes without the marker keep their data intact.
365368
let vm_path = self.work_dir(id);
366-
if vm_path.path().exists() {
367-
if let Err(err) = fs::remove_dir_all(&vm_path) {
368-
error!("Failed to remove VM directory for {id}: {err:?}");
369+
if delete_workdir || vm_path.is_removing() {
370+
if vm_path.path().exists() {
371+
if let Err(err) = fs::remove_dir_all(&vm_path) {
372+
error!("failed to remove VM directory for {id}: {err:?}");
373+
}
369374
}
375+
} else if vm_path.path().exists() {
376+
info!(
377+
"VM {id} workdir preserved (orphan cleanup): {}",
378+
vm_path.path().display()
379+
);
370380
}
371381

372382
// Free CID and remove from memory (last step)
@@ -381,7 +391,8 @@ impl App {
381391
Ok(())
382392
}
383393

384-
/// Spawn a background task to clean up a VM (stop + remove from supervisor + delete workdir).
394+
/// Spawn a background task to clean up a VM (stop + remove from supervisor).
395+
/// Workdir deletion is based on the `.removing` marker (only present for user-initiated removal).
385396
/// Returns false if a cleanup task is already running for this VM.
386397
fn spawn_finish_remove(&self, id: &str) -> bool {
387398
{
@@ -394,12 +405,13 @@ impl App {
394405
vm.state.removing = true;
395406
}
396407
// If VM is not in memory (e.g. orphaned supervisor process), no entry to guard
397-
// but we still need to clean up the supervisor process and workdir.
408+
// but we still need to clean up the supervisor process.
398409
}
399410
let app = self.clone();
400411
let id = id.to_string();
401412
tokio::spawn(async move {
402-
if let Err(err) = app.finish_remove_vm(&id).await {
413+
// Don't pass delete_workdir=true; rely on .removing marker check inside
414+
if let Err(err) = app.finish_remove_vm(&id, false).await {
403415
error!("Background cleanup failed for {id}: {err:?}");
404416
}
405417
});

0 commit comments

Comments
 (0)