diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b75956c4e1..2ec9f06730 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1721,6 +1721,7 @@ virCgroupV2DevicesAttachProg; virCgroupV2DevicesAvailable; virCgroupV2DevicesCreateProg; virCgroupV2DevicesDetectProg; +virCgroupV2DevicesPrepareProg; # util/virclosecallbacks.h virCloseCallbacksGet; diff --git a/src/util/vircgroupv2devices.c b/src/util/vircgroupv2devices.c index 330e40c63a..7e537f5368 100644 --- a/src/util/vircgroupv2devices.c +++ b/src/util/vircgroupv2devices.c @@ -446,6 +446,51 @@ virCgroupV2DevicesCreateMap(size_t size) } +static int +virCgroupV2DevicesReallocMap(int mapfd, + size_t size) +{ + uint64_t key = 0; + uint64_t prevKey = 0; + int rc; + int ret = -1; + VIR_AUTOCLOSE newmapfd = virCgroupV2DevicesCreateMap(size); + + VIR_DEBUG("realloc devices map mapfd:%d, size:%lu", mapfd, size); + + if (newmapfd < 0) + return -1; + + while ((rc = virBPFGetNextElem(mapfd, &prevKey, &key)) == 0) { + uint32_t val = 0; + + if (virBPFLookupElem(mapfd, &key, &val) < 0) { + virReportSystemError(errno, "%s", + _("failed to lookup device in old map")); + return -1; + } + + if (virBPFUpdateElem(newmapfd, &key, &val) < 0) { + virReportSystemError(errno, "%s", + _("failed to add device into new map")); + return -1; + } + + prevKey = key; + } + + if (rc < 0 && errno != ENOENT) { + virReportSystemError(errno, "%s", + _("failed to copy all device rules")); + return -1; + } + + ret = newmapfd; + newmapfd = -1; + return ret; +} + + int virCgroupV2DevicesCreateProg(virCgroupPtr group) { @@ -466,6 +511,33 @@ virCgroupV2DevicesCreateProg(virCgroupPtr group) mapfd = -1; return 0; } + + +int +virCgroupV2DevicesPrepareProg(virCgroupPtr group) +{ + if (virCgroupV2DevicesDetectProg(group) < 0) + return -1; + + if (virCgroupV2DevicesCreateProg(group) < 0) + return -1; + + if (group->unified.devices.count >= group->unified.devices.max) { + size_t max = group->unified.devices.max * 2; + int newmapfd = virCgroupV2DevicesReallocMap(group->unified.devices.mapfd, + max); + + if (newmapfd < 0) + return -1; + + if (virCgroupV2DevicesAttachProg(group, newmapfd, max) < 0) { + VIR_FORCE_CLOSE(newmapfd); + return -1; + } + } + + return 0; +} #else /* !HAVE_DECL_BPF_CGROUP_DEVICE */ bool virCgroupV2DevicesAvailable(virCgroupPtr group G_GNUC_UNUSED) @@ -504,4 +576,14 @@ virCgroupV2DevicesCreateProg(virCgroupPtr group G_GNUC_UNUSED) "with this kernel")); return -1; } + + +int +virCgroupV2DevicesPrepareProg(virCgroupPtr group G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("cgroups v2 BPF devices not supported " + "with this kernel")); + return -1; +} #endif /* !HAVE_DECL_BPF_CGROUP_DEVICE */ diff --git a/src/util/vircgroupv2devices.h b/src/util/vircgroupv2devices.h index db1316d072..357ed0c8bf 100644 --- a/src/util/vircgroupv2devices.h +++ b/src/util/vircgroupv2devices.h @@ -33,3 +33,6 @@ virCgroupV2DevicesDetectProg(virCgroupPtr group); int virCgroupV2DevicesCreateProg(virCgroupPtr group); + +int +virCgroupV2DevicesPrepareProg(virCgroupPtr group);