deb: survive crashed sessions and config-blind resumes
Two failures from resumed kernel sessions: A resumed build re-runs debian/rules build, but the kernels keep their wrapper-step stamps in debian/stamps and the flavour config rule there exports .config from the annotations with no config prerequisite: the resumed build silently kept the previous attempt's configuration and a config edit never reached the .deb. Dropping the stamp cache unconditionally would impose the kernel packaging's shape on every package, so it is data-driven instead: packages declare the caches under a resume_clear quirk, and resumed builds remove those tree-relative paths before the build. The inner kbuild keeps its own incremental state, so only the cheap wrapper passes re-run and config-affected objects recompile. A SIGKILLed build (OOM) leaves its overlay mounts and /proc bind mount behind, and overlayfs creates root-owned work state inside the workdir: the next plain build (recording is always on, it replaces the session of its identity) failed to clear the leftovers with a permission error. Session clearing now unmounts everything under each entry at depth (re-reading /proc/mounts, tolerating mount stacks from consecutive crashes) and escalates through sudo; when the tree still cannot be cleared, the build reports it and continues without a session instead of layering over a half-cleared one.
This commit is contained in:
@@ -54,6 +54,20 @@ pub struct OperationQuirks {
|
||||
/// like linux packages that use directories like "linux-main" or other custom names
|
||||
#[serde(default)]
|
||||
pub package_directory: Vec<String>,
|
||||
|
||||
/// Paths (relative to the package tree) removed before
|
||||
/// `debian/rules build` when the build resumes a previous attempt.
|
||||
///
|
||||
/// For packages whose debian/rules keeps a stamp cache that does not
|
||||
/// track its inputs (the Ubuntu/Debian kernels' `debian/stamps`: the
|
||||
/// flavour config rule exports `.config` from the annotations with no
|
||||
/// config prerequisite), a resumed build would keep building from the
|
||||
/// previous attempt's configuration. Listing the stamp directories
|
||||
/// here drops the cache so the wrapper steps re-run, while the inner
|
||||
/// build system (kbuild) keeps its own incremental state. Only list
|
||||
/// caches whose re-run is cheap or whose inner build is incremental.
|
||||
#[serde(default)]
|
||||
pub resume_clear: Vec<String>,
|
||||
}
|
||||
|
||||
/// Quirks for a specific package
|
||||
@@ -166,6 +180,33 @@ pub fn get_package_directories(package: &str, series: &str) -> Vec<String> {
|
||||
directories
|
||||
}
|
||||
|
||||
/// Get the paths to clear before a resumed `debian/rules build`
|
||||
///
|
||||
/// Every matching deb entry contributes its paths, in file order. See
|
||||
/// [`OperationQuirks::resume_clear`] for what belongs here.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `package` - The package name
|
||||
/// * `series` - The distribution series (e.g. "resolute")
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Vec<String>` - Tree-relative paths to remove, empty when the package
|
||||
/// opts out
|
||||
pub fn get_resume_clear_paths(package: &str, series: &str) -> Vec<String> {
|
||||
let Some(quirks) = get_package_quirks(&QUIRKS_DATA, package) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut paths = Vec::new();
|
||||
for deb in quirks
|
||||
.deb
|
||||
.iter()
|
||||
.filter(|q| entry_applies_to_series(q, series))
|
||||
{
|
||||
paths.extend(deb.resume_clear.iter().cloned());
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
||||
/// Apply the dependency quirks of `package` in `series` to parsed
|
||||
/// build-dependency clauses
|
||||
///
|
||||
@@ -374,4 +415,23 @@ mod tests {
|
||||
};
|
||||
assert!(apply_rules(&mut clauses, &deps, &opts()).is_err());
|
||||
}
|
||||
|
||||
/// The kernels opt in to clearing their stamp cache on resume, for
|
||||
/// every series; packages without the entry opt out by default.
|
||||
#[test]
|
||||
fn resume_clear_paths_are_data_driven() {
|
||||
for package in ["linux", "linux-riscv"] {
|
||||
assert_eq!(
|
||||
get_resume_clear_paths(package, "resolute"),
|
||||
vec!["debian/stamps".to_string()]
|
||||
);
|
||||
assert_eq!(
|
||||
get_resume_clear_paths(package, "some-future-series"),
|
||||
vec!["debian/stamps".to_string()],
|
||||
"the stamp-cache entry applies to every series"
|
||||
);
|
||||
}
|
||||
assert!(get_resume_clear_paths("hello", "resolute").is_empty());
|
||||
assert!(get_resume_clear_paths("no-such-package", "resolute").is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user