hive-c0re: per-agent btrfs disk usage + optional quota (#1793)

Follow-up to the btrfs-subvolume migration. Operator-opt-in disk
accounting + quotas on agent state subvolumes via btrfs qgroups:

- three privileged ops (qgroup ops need root): EnsureBtrfsQuota
  (btrfs quota enable on the agent-state filesystem — statfs-gated,
  idempotent, no-op off btrfs), ReadSubvolumeUsage (btrfs qgroup show
  -f --raw for one agent), SetSubvolumeQuota (btrfs qgroup limit, or
  clear). Reuses the is_on_btrfs helper from the subvolume work.
- priv_client wrappers, incl parse_qgroup_usage -> (referenced,
  exclusive) bytes.
- hivectl 'quota' subcommand: enable / show [agent] / limit <agent>
  <size|none>, with a K/M/G/T size parser + human-readable output.

Quota is deliberately NOT auto-enabled: btrfs quota enable triggers a
full rescan that is I/O-heavy on a large filesystem, and the operator
should choose when to pay that. 'quota show' on a plain-dir agent (no
subvolume) reports no qgroup data rather than erroring.
This commit is contained in:
atlas 2026-06-19 14:10:49 +02:00 committed by mara
commit 9ff55399e5
5 changed files with 373 additions and 0 deletions

View file

@ -373,6 +373,39 @@ pub enum PrivRequest {
/// Logical agent name (validated by `validate_agent_name`).
agent_name: String,
},
// --- btrfs qgroup accounting + quota (operator opt-in) ---
/// Enable btrfs qgroup accounting on the filesystem holding
/// `AGENT_STATE_ROOT` (`btrfs quota enable <AGENT_STATE_ROOT>`).
/// Prerequisite for per-agent usage reads + quotas. **Operator
/// opt-in** — never run automatically: enabling triggers a full
/// rescan with real I/O cost on a large filesystem. Idempotent
/// (already-enabled is success); a no-op on non-btrfs (statfs gate).
/// Requires root.
EnsureBtrfsQuota,
/// Read an agent state subvolume's btrfs qgroup usage
/// (`btrfs qgroup show -f --raw <AGENT_STATE_ROOT>/<agent_name>`).
/// Returns the raw `qgroup show` row in stdout for hive-c0re to parse
/// (referenced + exclusive bytes). Errors with "quota not enabled" when
/// accounting is off — hive-c0re surfaces that gracefully. Requires root
/// (qgroup show on a subvolume needs `CAP_SYS_ADMIN`).
ReadSubvolumeUsage {
/// Logical agent name (validated by `validate_agent_name`).
agent_name: String,
},
/// Set (or clear) a btrfs qgroup size limit on an agent's state
/// subvolume (`btrfs qgroup limit <bytes|none> <…/agent_name>`).
/// `limit_bytes = Some(n)` caps referenced usage at `n` bytes;
/// `None` clears the limit (`none`). Requires quota enabled first
/// ([`PrivRequest::EnsureBtrfsQuota`]). Requires root.
SetSubvolumeQuota {
/// Logical agent name (validated by `validate_agent_name`).
agent_name: String,
/// Byte cap on referenced usage; `None` clears the limit.
limit_bytes: Option<u64>,
},
}
/// Response from the privileged helper.