feat(#2862): receive a passed descriptor and stream a snapshot into it
hive-priv read requests with BufReader::lines, which cannot surface SCM_RIGHTS: ancillary data is attached to one specific recvmsg call, so a buffered line reader takes the bytes and silently drops the descriptor. Replace it with a recvmsg loop. The pairing is deliberately trivial. hive-sock-client connects per request, so a connection carries one line and at most one descriptor; a second descriptor arriving before its line is a protocol error rather than something to queue. check_fd_agreement rejects both mismatches -- an fd-taking op that got none, and a descriptor sent to an op that takes none -- and dropping the OwnedFd on that path closes it. recv_with_fds claims every descriptor the kernel attaches, including ones this protocol never expects, because an fd we fail to claim leaks for the life of the process. MSG_CMSG_CLOEXEC keeps a received descriptor out of every btrfs and nixos-container child. The control buffer is only cmsghdr-aligned, so descriptors are copied out byte-wise instead of read through a more strictly aligned pointer. SendAgentSnapshotToFd is SendAgentSnapshotToFile without the staging file: same validation and -p parent handling, stdout wired to the passed descriptor. It exists so hive-c0re can connect to a peer hive's snapshot store, write the header itself, and hand over the connected socket -- leaving this helper with no address, no protocol, and nobody in the data path once the send starts.
This commit is contained in:
parent
364bc290df
commit
51f352f0ca
2 changed files with 319 additions and 21 deletions
|
|
@ -715,6 +715,35 @@ pub enum PrivRequest {
|
|||
dest_file_name: String,
|
||||
},
|
||||
|
||||
/// Stream a previously-created read-only snapshot into a file
|
||||
/// descriptor the caller passes alongside this request (`SCM_RIGHTS`
|
||||
/// ancillary data on the same socket): `btrfs send [-p <parent>]
|
||||
/// <snapshot> >&<passed fd>`.
|
||||
///
|
||||
/// The network half of the inter-hive migration transport. hive-c0re
|
||||
/// connects to the peer hive's snapshot store, writes the header
|
||||
/// itself, and hands the **connected socket** over — so hive-priv
|
||||
/// never learns an address, a protocol, or that a network is
|
||||
/// involved, and nobody sits in the data path once the send starts
|
||||
/// (which is what makes a multi-gigabyte transfer survive a
|
||||
/// hive-c0re restart).
|
||||
///
|
||||
/// Exactly one descriptor must accompany this request. hive-priv
|
||||
/// rejects the request if none arrived, if more than one did, or if a
|
||||
/// descriptor arrives alongside any *other* operation — no guessing
|
||||
/// when the caller didn't say. Requires root.
|
||||
SendAgentSnapshotToFd {
|
||||
/// Logical agent name (validated by `validate_agent_name`).
|
||||
agent_name: String,
|
||||
/// Snapshot label to send, same validation as `SnapshotAgentSubvolume`.
|
||||
snapshot_name: String,
|
||||
/// Optional parent snapshot label for an incremental
|
||||
/// (`btrfs send -p`) send — must be an older read-only snapshot of
|
||||
/// the same agent, still present on disk. `None` sends the full
|
||||
/// snapshot.
|
||||
parent_snapshot_name: Option<String>,
|
||||
},
|
||||
|
||||
/// Write `/etc/tmpfiles.d/hyperhive-agents.conf` for the given agent set
|
||||
/// and immediately apply it with `systemd-tmpfiles --create`. Each entry
|
||||
/// declares the per-agent runtime dirs (`/run/hyperhive/agents/<name>` and
|
||||
|
|
|
|||
Loading…
Reference in a new issue