mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-26 04:36:37 +03:00
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:
@@ -1,10 +1,10 @@
|
||||
#ifndef VMSIG_INPUT_H
|
||||
#define VMSIG_INPUT_H
|
||||
|
||||
/* Private config of the input adapter (vmctl). cfg==NULL => stub mode. Armed mode
|
||||
* (VMSIG_WITH_VMCTL) opens vmctl_open() and actuates for real. Injection is ALWAYS
|
||||
* uinput (orphaned host uinput + external QEMU input-linux). qmp_path is kept for the
|
||||
* SERVICE path (power/lifecycle via vmctl QMP), not for input injection. */
|
||||
/* Private config of the input adapter (vmctl, in-tree at src/si/input/). cfg==NULL or
|
||||
* stub!=0 => stub mode (ack without actuation). stub==0 opens vmctl_open() and actuates for
|
||||
* real. Injection is ALWAYS uinput (orphaned host uinput + external QEMU input-linux);
|
||||
* qmp_path is kept for the SERVICE path (power/lifecycle via vmctl QMP), not for injection. */
|
||||
typedef struct {
|
||||
int stub;
|
||||
const char* qmp_path; /* for power/lifecycle (vmctl QMP); NOT input injection */
|
||||
|
||||
@@ -3,19 +3,17 @@
|
||||
* Mechanism (recommended): vmctl is a blocking QMP round-trip; we run it on a
|
||||
* worker thread, completion ack via a completion-eventfd. The uinput path is a
|
||||
* local instantaneous write; when armed it would be done inline (see comment in submit).
|
||||
* Real actuation is under VMSIG_WITH_VMCTL; otherwise the stub acks (spine without a VM). */
|
||||
* Real actuation when cfg.stub==0 (vmctl opened); otherwise the stub acks (spine without a VM).
|
||||
* vmctl is the in-tree input driver (src/si/input/, absorbed); cfg.stub gates opening it. */
|
||||
#include "vmsig_adapter.h"
|
||||
#include "adapter_util.h"
|
||||
#include "input.h"
|
||||
#include "vmctl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
#include "vmctl.h"
|
||||
#endif
|
||||
|
||||
/* POD request/result of the worker. */
|
||||
typedef struct {
|
||||
int cmd; /* 0 = input event, 1 = lifecycle */
|
||||
@@ -40,9 +38,7 @@ struct vmsig_adapter {
|
||||
vmsig_emit emit;
|
||||
vmsig_worker* worker;
|
||||
const char* qmp_path; /* borrowed from cfg (valid through attach); SERVICE power/lifecycle */
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
vmctl_t* vmctl;
|
||||
#endif
|
||||
vmctl_t* vmctl; /* NULL in stub mode (cfg.stub) — no actuator opened */
|
||||
};
|
||||
|
||||
static int input_job(void* user, const void* reqp, void* resp) {
|
||||
@@ -53,7 +49,6 @@ static int input_job(void* user, const void* reqp, void* resp) {
|
||||
rs->corr = rq->corr;
|
||||
rs->origin = rq->origin;
|
||||
rs->noack = rq->noack;
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
if (a->vmctl) {
|
||||
int r = -1;
|
||||
if (rq->cmd == 0) {
|
||||
@@ -87,9 +82,8 @@ static int input_job(void* user, const void* reqp, void* resp) {
|
||||
rs->ok = (r == 0);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
(void)a;
|
||||
rs->ok = 1; /* stub: ack without actuation */
|
||||
rs->ok = 1; /* stub: ack without actuation (vmctl not opened) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -109,7 +103,6 @@ static int in_attach(vmsig_adapter* a, const vmsig_emit* emit, vmsig_fd_reg* reg
|
||||
a->worker = vmsig_worker_new(input_job, a, 1, 64); /* QMP is a serial channel, cap 64 */
|
||||
if (!a->worker) return -1;
|
||||
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
if (!a->stub) {
|
||||
/* armed: open the actuator. Injection is ALWAYS uinput (orphaned host uinput + external
|
||||
* QEMU input-linux). PTR_BOTH gives both pointer forms a device (A=abs tablet, B=rel
|
||||
@@ -125,7 +118,6 @@ static int in_attach(vmsig_adapter* a, const vmsig_emit* emit, vmsig_fd_reg* reg
|
||||
a->vmctl = vmctl_open(&vcfg);
|
||||
if (!a->vmctl) { vmsig_worker_free(a->worker); a->worker = NULL; return -1; }
|
||||
}
|
||||
#endif
|
||||
|
||||
reg[0].fd = vmsig_worker_evfd(a->worker);
|
||||
reg[0].epoll_events = EPOLLIN;
|
||||
@@ -166,7 +158,6 @@ static int in_submit(vmsig_adapter* a, const vmsig_event* ev) {
|
||||
* actuate — nothing to hold). */
|
||||
vmsig_input_held h;
|
||||
memset(&h, 0, sizeof h);
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
if (a->vmctl) {
|
||||
const uint32_t capn = (uint32_t)(sizeof h.ent / sizeof h.ent[0]);
|
||||
unsigned char bits[VMCTL_KEYS_SNAPSHOT_BYTES];
|
||||
@@ -184,7 +175,6 @@ static int in_submit(vmsig_adapter* a, const vmsig_event* ev) {
|
||||
else h.flags |= VMSIG_INPUT_HELD_TRUNC;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
vmsig_event up;
|
||||
memset(&up, 0, sizeof up);
|
||||
up.kind = VMSIG_EV_INPUT_HELD; up.source = VMSIG_SRC_INPUT; up.dir = VMSIG_DIR_UP;
|
||||
@@ -223,9 +213,7 @@ static int in_submit(vmsig_adapter* a, const vmsig_event* ev) {
|
||||
static void in_close(vmsig_adapter* a) {
|
||||
if (!a) return;
|
||||
vmsig_worker_free(a->worker);
|
||||
#ifdef VMSIG_WITH_VMCTL
|
||||
if (a->vmctl) vmctl_close(a->vmctl);
|
||||
#endif
|
||||
free(a);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ typedef struct {
|
||||
int stub; /* 1 => synthetic kcr3/RO-fd (spine without a VM) */
|
||||
const char* ram_path; /* armed: path to guest RAM backing (NOT published outward) */
|
||||
uint64_t low; /* below-4G split (vmie_win32_open / locator.low) */
|
||||
int ro_fd; /* >=0 => infra supplied a pre-sealed RO-fd (policy); */
|
||||
/* <0 => default: open(ram_path, O_RDONLY) / stub-memfd */
|
||||
int ro_fd; /* >=0 => infra hands a pre-sealed RO-fd (policy); OWNERSHIP */
|
||||
/* TRANSFERS to the adapter (closed in close()) — the */
|
||||
/* caller dups first if it must keep its own copy. */
|
||||
/* <0 => default: open(ram_path, O_RDONLY) / stub-memfd */
|
||||
} vmsig_memctx_cfg;
|
||||
|
||||
/* Max SRC bytes per atomic gva_write (bounds the worker POD slot; mc_req header + src
|
||||
|
||||
@@ -85,7 +85,7 @@ struct vmsig_adapter {
|
||||
int stub;
|
||||
const char* ram_path; /* armed: RAM-backing path (NOT published outward) */
|
||||
uint64_t low;
|
||||
int cfg_ro_fd; /* >=0 => infra-sealed RO-fd (policy); <0 => default */
|
||||
int cfg_ro_fd; /* >=0 => infra-sealed RO-fd (owned by adapter, closed in mc_close); <0 => default */
|
||||
vmsig_emit emit;
|
||||
int registered; /* register_memctx already called */
|
||||
vmsig_worker* worker; /* off-loop bootstrap + atomic writes */
|
||||
@@ -398,7 +398,11 @@ static void mc_close(vmsig_adapter* a) {
|
||||
if (a->win) vmie_win32_close(a->win); /* AFTER worker join: no in-flight gva_write */
|
||||
#endif
|
||||
if (a->stub_fd >= 0) close(a->stub_fd);
|
||||
/* cfg_ro_fd belongs to the infrastructure (the open caller) — do NOT close it. */
|
||||
/* ro_fd ownership transferred to the adapter at open(): close it here so a re-grant
|
||||
* (detach + re-attach with a fresh infra ro_fd) does not leak the prior one. Infra
|
||||
* that must keep its own copy dups before handing it in — symmetric to the holder
|
||||
* side, which dups the borrowed RO-fd it receives. */
|
||||
if (a->cfg_ro_fd >= 0) close(a->cfg_ro_fd);
|
||||
free(a);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user