From ce11a5c59f6fcaeae8d9a7bd60747ffdac91e3df Mon Sep 17 00:00:00 2001 From: Pavel Hrdina Date: Mon, 24 Jun 2019 14:25:04 +0200 Subject: [PATCH] vircgroup: introduce virCgroupV2DevicesDetectProg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function will be called if libvirtd was restarted while some domains were running. It will try to detect existing programs attached to the guest cgroup. Signed-off-by: Pavel Hrdina Reviewed-by: Ján Tomko --- src/libvirt_private.syms | 1 + src/util/vircgroupv2devices.c | 114 ++++++++++++++++++++++++++++++++++ src/util/vircgroupv2devices.h | 3 + 3 files changed, 118 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 975733f71e..d4e446cbef 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1719,6 +1719,7 @@ virCgroupV2Register; # util/vircgroupv2devices.h virCgroupV2DevicesAttachProg; virCgroupV2DevicesAvailable; +virCgroupV2DevicesDetectProg; # util/virclosecallbacks.h virCloseCallbacksGet; diff --git a/src/util/vircgroupv2devices.c b/src/util/vircgroupv2devices.c index c30a23f165..62f66250c3 100644 --- a/src/util/vircgroupv2devices.c +++ b/src/util/vircgroupv2devices.c @@ -322,6 +322,110 @@ virCgroupV2DevicesAttachProg(virCgroupPtr group, VIR_FORCE_CLOSE(mapfd); return ret; } + + +static int +virCgroupV2DevicesCountMapEntries(int mapfd) +{ + int ret = 0; + int rc; + uint64_t key = 0; + uint64_t prevKey = 0; + + while ((rc = virBPFGetNextElem(mapfd, &prevKey, &key)) == 0) { + ret++; + prevKey = key; + } + + if (rc < 0) + return -1; + + return ret; +} + + +# define MAX_PROG_IDS 10 + +int +virCgroupV2DevicesDetectProg(virCgroupPtr group) +{ + g_autofree char *path = NULL; + VIR_AUTOCLOSE cgroupfd = -1; + unsigned int progcnt = 0; + unsigned int progids[MAX_PROG_IDS] = { 0 }; + int progfd = -1; + int mapfd = -1; + int nitems = -1; + struct bpf_prog_info progInfo = { 0 }; + struct bpf_map_info mapInfo = { 0 }; + g_autofree unsigned int *mapIDs = NULL; + + if (group->unified.devices.progfd > 0 && group->unified.devices.mapfd > 0) + return 0; + + if (virCgroupPathOfController(group, VIR_CGROUP_CONTROLLER_DEVICES, + NULL, &path) < 0) { + return -1; + } + + cgroupfd = open(path, O_RDONLY); + if (cgroupfd < 0) { + virReportSystemError(errno, _("unable to open '%s'"), path); + return -1; + } + + if (virBPFQueryProg(cgroupfd, MAX_PROG_IDS, BPF_CGROUP_DEVICE, + &progcnt, progids) < 0) { + virReportSystemError(errno, "%s", _("unable to query cgroup BPF progs")); + return -1; + } + + if (progcnt == 0) + return 0; + + /* No need to have alternate code, this function will not be called + * if compiled with old kernel. */ + progfd = virBPFGetProg(progids[0]); + if (progfd < 0) { + virReportSystemError(errno, "%s", _("failed to get cgroup BPF prog FD")); + return -1; + } + + if (virBPFGetProgInfo(progfd, &progInfo, &mapIDs) < 0) { + virReportSystemError(errno, "%s", _("failed to get cgroup BPF prog info")); + return -1; + } + + if (progInfo.nr_map_ids == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("no map for cgroup BPF prog")); + return -1; + } + + mapfd = virBPFGetMap(mapIDs[0]); + if (mapfd < 0) { + virReportSystemError(errno, "%s", _("failed to get cgroup BPF map FD")); + return -1; + } + + if (virBPFGetMapInfo(mapfd, &mapInfo) < 0) { + virReportSystemError(errno, "%s", _("failed to get cgroup BPF map info")); + return -1; + } + + nitems = virCgroupV2DevicesCountMapEntries(mapfd); + if (nitems < 0) { + virReportSystemError(errno, "%s", _("failed to count cgroup BPF map items")); + return -1; + } + + group->unified.devices.progfd = progfd; + group->unified.devices.mapfd = mapfd; + group->unified.devices.max = mapInfo.max_entries; + group->unified.devices.count = nitems; + + return 0; +} #else /* !HAVE_DECL_BPF_CGROUP_DEVICE */ bool virCgroupV2DevicesAvailable(virCgroupPtr group G_GNUC_UNUSED) @@ -340,4 +444,14 @@ virCgroupV2DevicesAttachProg(virCgroupPtr group G_GNUC_UNUSED, "with this kernel")); return -1; } + + +int +virCgroupV2DevicesDetectProg(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 57454e80af..882bbd66f1 100644 --- a/src/util/vircgroupv2devices.h +++ b/src/util/vircgroupv2devices.h @@ -27,3 +27,6 @@ int virCgroupV2DevicesAttachProg(virCgroupPtr group, int mapfd, size_t max); + +int +virCgroupV2DevicesDetectProg(virCgroupPtr group);