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);
|
||||
}
|
||||
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
|
||||
// hive-priv (root) first. No-op for plain-dir agents — the loop below
|
||||
// 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/`,
|
||||
/// `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
|
||||
/// 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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
// must be able to mkdir state/ claude/ harness/ inside it, exactly as it
|
||||
// would in a plain dir. Match the owner of AGENT_STATE_ROOT (hive-core).
|
||||
if let Ok(meta) = std::fs::metadata(&root)
|
||||
&& let Err(e) = std::os::unix::fs::chown(&agent_root, Some(meta.uid()), Some(meta.gid()))
|
||||
{
|
||||
tracing::warn!(
|
||||
agent = %agent_name,
|
||||
error = %e,
|
||||
"ensure_agent_subvolume: chown subvol to agents-root owner failed"
|
||||
);
|
||||
// The subvol root is created root-owned, but hive-c0re (the `hive-core`
|
||||
// user) must be able to mkdir state/ claude/ harness/ inside it — exactly
|
||||
// as it would in a plain dir. Chown it to AGENT_STATE_ROOT's owner
|
||||
// (hive-core). This MUST succeed: a root-owned subvol would make the
|
||||
// downstream dir creation fail with a confusing permission error, and the
|
||||
// c0re-side exists-check would then skip re-running this op on retry,
|
||||
// wedging the agent. So on any failure roll the subvol back and bail — the
|
||||
// create path surfaces a clear error and a retry starts clean.
|
||||
let chown_result = std::fs::metadata(&root)
|
||||
.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");
|
||||
Ok((String::new(), String::new()))
|
||||
|
|
|
|||
Loading…
Reference in a new issue