vmsig: management daemon, runtime endpoint lifecycle, roster, discovery, in-tree drivers, packaging

- core: runtime attach/detach of a per-endpoint adapter trio (runtime-safe add_adapter + vmsig_core_detach_endpoint, deferred reap)
- roster: VMSIG_EV_ROSTER + CAP_ROSTER, retained per-endpoint and replayed to late subscribers
- discovery: inotify trigger dir, vmid/endpoint slot allocator, host probe; vmsigd daemon with config + per-uid admission
- input driver and vgpu perception built in-tree; vgpu perception as a separate library
- memctx: own the supplied ro_fd (closed at detach)
- deb packaging: install rules, systemd unit, tmpfiles, default config
This commit is contained in:
2026-06-22 17:25:06 +03:00
parent 0d387a4249
commit 9bde398b6c
55 changed files with 4703 additions and 61 deletions
+49 -10
View File
@@ -68,10 +68,22 @@ vmsig_core* vmsig_core_new(vmsig_ctx* ctx) {
int vmsig_core_add_adapter(vmsig_core* c, const vmsig_adapter_ops* ops,
const void* cfg, uint32_t endpoint) {
if (!c || !ops || c->nadapters >= VMSIG_MAX_ADAPTERS) return -1;
if (!c || !ops) return -1;
/* Reuse a reaped (inactive) adapter entry so runtime detach/re-attach churn does
* not exhaust the fixed table; otherwise grow up to the ceiling. */
int id = -1;
for (int i = 0; i < c->nadapters; i++)
if (!c->adapters[i].active) { id = i; break; }
if (id < 0) {
if (c->nadapters >= VMSIG_MAX_ADAPTERS) return -1;
id = c->nadapters++;
}
core_adapter_ent* e = &c->adapters[id];
uint16_t gen = e->gen; /* generation survives the memset below */
vmsig_adapter* a = ops->open(cfg, endpoint);
if (!a) return -1;
if (!a) return -1; /* entry stays inactive (reusable) */
vmsig_emit emit = { core_emit_up, core_register_memctx, core_unregister_memctx, c };
vmsig_fd_reg reg[VMSIG_ADAPTER_FDS];
@@ -80,23 +92,48 @@ int vmsig_core_add_adapter(vmsig_core* c, const vmsig_adapter_ops* ops,
int n = ops->attach(a, &emit, reg, VMSIG_ADAPTER_FDS);
if (n < 0) { ops->close(a); return -1; }
memset(e, 0, sizeof *e);
e->ops = ops;
e->a = a;
e->endpoint = endpoint;
e->active = 1;
e->gen = (uint16_t)(gen + 1);
e->nslot = 0;
for (int i = 0; i < n; i++) {
uint32_t events = reg[i].epoll_events ? reg[i].epoll_events : (uint32_t)EPOLLIN;
core_slot* s = core_register_fd(c, reg[i].fd, events, SLOT_ADAPTER);
if (!s) { ops->close(a); return -1; }
if (!s) {
/* roll back: deregister the fds enrolled so far, then close + free the entry. */
for (int k = 0; k < e->nslot; k++) {
epoll_ctl(c->epfd, EPOLL_CTL_DEL, e->slots[k]->fd, NULL);
e->slots[k]->role = SLOT_DEAD;
}
ops->close(a);
e->active = 0; e->a = NULL; e->nslot = 0;
return -1;
}
s->ops = ops;
s->adapter = a;
s->cookie = reg[i].cookie;
if (e->nslot < VMSIG_ADAPTER_FDS) e->slots[e->nslot++] = s;
}
int id = c->nadapters;
c->adapters[c->nadapters].ops = ops;
c->adapters[c->nadapters].a = a;
c->adapters[c->nadapters].endpoint = endpoint;
c->nadapters++;
return id;
}
/* Request runtime detach of every adapter on `endpoint` (deferred reap after the batch,
* mirrors core_request_drop). The teardown itself (epoch settle, SEAM_DOWN, lease release,
* epoll DEL, ops->close) runs in core_reap_adapters on the loop thread. */
void vmsig_core_detach_endpoint(vmsig_core* c, uint32_t endpoint) {
if (!c || endpoint >= 64) return;
int any = 0;
for (int i = 0; i < c->nadapters; i++) {
core_adapter_ent* e = &c->adapters[i];
if (e->active && e->endpoint == endpoint) { e->reap = 1; any = 1; }
}
if (any) core_wake(c);
}
int vmsig_core_add_control(vmsig_core* c, const vmsig_control_ops* ops, void* ctl,
const vmsig_grant* grant) {
if (!c || !ops) return -1;
@@ -137,6 +174,7 @@ int vmsig_core_add_control(vmsig_core* c, const vmsig_control_ops* ops, void* ct
* this control is qualified). For a control added BEFORE the first publication,
* the cell is not yet valid — it receives MEMCTX via the normal multicast in pump_up. */
core_memctx_replay(c, id);
core_roster_replay(c, id); /* late subscriber: retained VM roster (CAP_ROSTER) */
return id; /* ncontrols already bumped when picking id (on growth); reuse does not grow it */
}
@@ -205,7 +243,8 @@ void vmsig_core_free(vmsig_core* c) {
* FIRST: their close stops off-loop workers and unregisters their seams (e.g.
* memctx) BEFORE destruction. */
for (int i = 0; i < c->nadapters; i++)
if (c->adapters[i].ops->close) c->adapters[i].ops->close(c->adapters[i].a);
if (c->adapters[i].active && c->adapters[i].ops->close)
c->adapters[i].ops->close(c->adapters[i].a);
for (int i = 0; i < c->ncontrols; i++)
if (c->controls[i].active && c->controls[i].ops->close)
c->controls[i].ops->close(c->controls[i].ctl);