btrfs subvols: scrub tracker tags from comments; harden subvol chown
- Replace the #-number tracker references in code comments with prose (tracker-tag lint; hive convention is prose in source). - ensure_agent_subvolume now treats a chown failure on the freshly created subvolume as fatal: it rolls the subvolume back (deletes it) and returns an error, instead of warning and leaving a root-owned subvol that hive-c0re can't write into (which would also make the c0re-side exists-check skip the retry, wedging the agent).
This commit is contained in:
parent
1f602d5fda
commit
eb103a5660
3 changed files with 28 additions and 13 deletions
|
|
@ -660,7 +660,7 @@ pub async fn destroy(coord: &Arc<Coordinator>, name: &str, purge: bool) -> Resul
|
||||||
let _ = std::fs::remove_dir_all(&runtime);
|
let _ = std::fs::remove_dir_all(&runtime);
|
||||||
}
|
}
|
||||||
if purge {
|
if purge {
|
||||||
// The state root may be a btrfs subvolume (#1762): a subvolume root
|
// The state root may be a btrfs subvolume: a subvolume root
|
||||||
// can't be removed with rmdir/`remove_dir_all`, so delete it via
|
// can't be removed with rmdir/`remove_dir_all`, so delete it via
|
||||||
// hive-priv (root) first. No-op for plain-dir agents — the loop below
|
// hive-priv (root) first. No-op for plain-dir agents — the loop below
|
||||||
// then handles the plain-dir state root plus the applied dir.
|
// then handles the plain-dir state root plus the applied dir.
|
||||||
|
|
|
||||||
|
|
@ -878,7 +878,7 @@ pub fn ensure_state_dir(notes_dir: &Path) -> Result<()> {
|
||||||
/// filesystem supports it — BEFORE the per-agent subdirs (`state/`, `claude/`,
|
/// filesystem supports it — BEFORE the per-agent subdirs (`state/`, `claude/`,
|
||||||
/// `harness/`) are created by `ensure_state_dir` / `ensure_claude_dir`.
|
/// `harness/`) are created by `ensure_state_dir` / `ensure_claude_dir`.
|
||||||
///
|
///
|
||||||
/// Progressive enhancement (the #1762 model): if the root already exists
|
/// Progressive enhancement: if the root already exists
|
||||||
/// (any agent provisioned before this landed, plain dir or subvol) it's left
|
/// (any agent provisioned before this landed, plain dir or subvol) it's left
|
||||||
/// exactly as-is — no auto-migration — and the priv round-trip is skipped. On
|
/// exactly as-is — no auto-migration — and the priv round-trip is skipped. On
|
||||||
/// a non-btrfs host the priv op no-ops and the root is later created as a
|
/// a non-btrfs host the priv op no-ops and the root is later created as a
|
||||||
|
|
|
||||||
|
|
@ -565,17 +565,32 @@ async fn ensure_agent_subvolume(agent_name: &str) -> Result<(String, String)> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The subvol root is created root-owned; hive-c0re (the `hive-core` user)
|
// The subvol root is created root-owned, but hive-c0re (the `hive-core`
|
||||||
// must be able to mkdir state/ claude/ harness/ inside it, exactly as it
|
// user) must be able to mkdir state/ claude/ harness/ inside it — exactly
|
||||||
// would in a plain dir. Match the owner of AGENT_STATE_ROOT (hive-core).
|
// as it would in a plain dir. Chown it to AGENT_STATE_ROOT's owner
|
||||||
if let Ok(meta) = std::fs::metadata(&root)
|
// (hive-core). This MUST succeed: a root-owned subvol would make the
|
||||||
&& let Err(e) = std::os::unix::fs::chown(&agent_root, Some(meta.uid()), Some(meta.gid()))
|
// downstream dir creation fail with a confusing permission error, and the
|
||||||
{
|
// c0re-side exists-check would then skip re-running this op on retry,
|
||||||
tracing::warn!(
|
// wedging the agent. So on any failure roll the subvol back and bail — the
|
||||||
agent = %agent_name,
|
// create path surfaces a clear error and a retry starts clean.
|
||||||
error = %e,
|
let chown_result = std::fs::metadata(&root)
|
||||||
"ensure_agent_subvolume: chown subvol to agents-root owner failed"
|
.with_context(|| format!("stat agents root {} for ownership", root.display()))
|
||||||
);
|
.and_then(|meta| {
|
||||||
|
std::os::unix::fs::chown(&agent_root, Some(meta.uid()), Some(meta.gid())).with_context(
|
||||||
|
|| format!("chown subvol {} to agents-root owner", agent_root.display()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
if let Err(e) = chown_result {
|
||||||
|
// Best-effort rollback so we never leave a root-owned subvol behind.
|
||||||
|
let _ = Command::new("btrfs")
|
||||||
|
.args(["subvolume", "delete"])
|
||||||
|
.arg(&agent_root)
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
return Err(e.context(format!(
|
||||||
|
"rolled back subvolume {} after chown failed",
|
||||||
|
agent_root.display()
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
tracing::info!(agent = %agent_name, path = %agent_root.display(), "created agent state subvolume");
|
tracing::info!(agent = %agent_name, path = %agent_root.display(), "created agent state subvolume");
|
||||||
Ok((String::new(), String::new()))
|
Ok((String::new(), String::new()))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue