/* slot.c — vmid <-> endpoint allocator (see slot.h). Pure logic + a tiny pointer-free * on-disk format; no core dependency. */ #define _GNU_SOURCE #include "slot.h" #include #include #include #include #include #include void slot_init(slot_table* t) { memset(t, 0, sizeof *t); } int slot_lookup(const slot_table* t, uint32_t vmid) { if (!vmid) return -1; for (int e = 0; e < VMSIG_SLOT_COUNT; e++) if (t->ent[e].vmid == vmid) return e; return -1; } int slot_alloc(slot_table* t, uint32_t vmid) { if (!vmid) return -1; int e = slot_lookup(t, vmid); if (e >= 0) return e; /* idempotent pin */ /* lowest free bit: ffsll of the complement (1-based; 0 => none free) */ int b = __builtin_ffsll((long long)~t->used_mask); if (b == 0) return -1; /* table full (64-VM ceiling) */ e = b - 1; t->ent[e].vmid = vmid; t->used_mask |= (1ull << e); return e; } void slot_free(slot_table* t, uint32_t vmid) { int e = slot_lookup(t, vmid); if (e < 0) return; t->ent[e].vmid = 0; t->used_mask &= ~(1ull << e); } /* ---- persistence: magic + version + 64 * uint32 vmid (native byte order, tmpfs-local) ---- */ #define SLOT_MAGIC 0x534C4F54u /* "SLOT" */ #define SLOT_VERSION 1u typedef struct { uint32_t magic; uint32_t version; uint32_t vmid[VMSIG_SLOT_COUNT]; } slot_blob; int slot_save(const slot_table* t, const char* path) { if (!path) return -1; slot_blob b; memset(&b, 0, sizeof b); b.magic = SLOT_MAGIC; b.version = SLOT_VERSION; for (int e = 0; e < VMSIG_SLOT_COUNT; e++) b.vmid[e] = t->ent[e].vmid; char tmp[512]; int n = snprintf(tmp, sizeof tmp, "%s.tmp", path); if (n < 0 || (size_t)n >= sizeof tmp) return -1; int fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); if (fd < 0) return -1; ssize_t w = write(fd, &b, sizeof b); int rc = (w == (ssize_t)sizeof b) ? 0 : -1; if (close(fd) != 0) rc = -1; if (rc == 0 && rename(tmp, path) != 0) rc = -1; if (rc != 0) unlink(tmp); return rc; } int slot_load(slot_table* t, const char* path) { slot_init(t); if (!path) return 0; int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) return 0; /* no file => fresh start (valid) */ slot_blob b; ssize_t r = read(fd, &b, sizeof b); close(fd); if (r != (ssize_t)sizeof b || b.magic != SLOT_MAGIC || b.version != SLOT_VERSION) { slot_init(t); /* corrupt/old => fresh start */ return 0; } for (int e = 0; e < VMSIG_SLOT_COUNT; e++) { t->ent[e].vmid = b.vmid[e]; if (b.vmid[e]) t->used_mask |= (1ull << e); } return 0; }