deb: wipe the staged tree when overlay staging falls back to a copy

On a resumed session whose overlay mount fails (no overlayfs, mount
error, non-overlay driver), the fallback used to copy the host tree
into the staged tree of the previous attempt: a merge that keeps the
old build stamps and resurrects files deleted on the host — a
silently half-stale build, exactly what resume must never produce.
The driver now reports the failure instead of copying, and the
caller wipes the staged build root and re-stages a fresh copy
(environment resumable, build artifacts discarded).
This commit is contained in:
2026-09-27 23:32:16 +02:00
parent 318bcea341
commit 961f6bc234
3 changed files with 89 additions and 37 deletions
+23 -29
View File
@@ -234,39 +234,33 @@ impl ContextDriver for UnshareDriver {
// The upper/work dirs are the persistent ones of a build session:
// mounting them again exposes the previous attempt's build
// artifacts over the (live) host tree.
if src.is_dir() && is_overlayfs_available() {
match self.mount_overlay(src, &dest_path, Some(upper), Some(work)) {
Ok(()) => {
debug!(
"Mounted overlay for {} at {} (reused upper {})",
src.display(),
dest_path.display(),
upper.display()
);
return Ok(super::api::OverlayStaging {
path: Path::new(dest_root).join(filename),
overlay: true,
});
}
Err(e) => {
debug!(
"Overlay remount failed for '{}', falling back to copy: {}",
src.display(),
e
);
}
}
// artifacts over the (live) host tree. Mount failure is an ERROR,
// never a silent copy fallback: a copy would merge the host tree
// into the stale staged tree of the previous attempt (old build
// stamps, dropped host deletions) — the caller decides to wipe and
// re-stage instead.
if !src.is_dir() {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"overlay staging only applies to directories",
));
}
if src.is_dir() {
copy_dir_recursive(src, &dest_path)?;
} else {
copy_file_with_times(src, &dest_path)?;
if !is_overlayfs_available() {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"overlayfs is not available on this system",
));
}
self.mount_overlay(src, &dest_path, Some(upper), Some(work))?;
debug!(
"Mounted overlay for {} at {} (reused upper {})",
src.display(),
dest_path.display(),
upper.display()
);
Ok(super::api::OverlayStaging {
path: Path::new(dest_root).join(filename),
overlay: false,
overlay: true,
})
}