]> xenbits.xensource.com Git - libvirt.git/commitdiff
vircgroup: introduce virCgroupV2DevicesDetectProg
authorPavel Hrdina <phrdina@redhat.com>
Mon, 24 Jun 2019 12:25:04 +0000 (14:25 +0200)
committerPavel Hrdina <phrdina@redhat.com>
Fri, 15 Nov 2019 11:58:31 +0000 (12:58 +0100)
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 <phrdina@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/libvirt_private.syms
src/util/vircgroupv2devices.c
src/util/vircgroupv2devices.h

index 975733f71ef047975908a3dba2d38a7e4b2b8f95..d4e446cbef3ae177d39475c91d6a58dcae7171aa 100644 (file)
@@ -1719,6 +1719,7 @@ virCgroupV2Register;
 # util/vircgroupv2devices.h
 virCgroupV2DevicesAttachProg;
 virCgroupV2DevicesAvailable;
+virCgroupV2DevicesDetectProg;
 
 # util/virclosecallbacks.h
 virCloseCallbacksGet;
index c30a23f1659aad40033fd3eb753643978f7649f5..62f66250c3256c3dc6a1b0d6d88d423bd777cd3f 100644 (file)
@@ -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 */
index 57454e80af1c4250e89f6a7c15f0103999e472cf..882bbd66f1e4d03abf6ed1b63ce96f39b9e6ed75 100644 (file)
@@ -27,3 +27,6 @@ int
 virCgroupV2DevicesAttachProg(virCgroupPtr group,
                              int mapfd,
                              size_t max);
+
+int
+virCgroupV2DevicesDetectProg(virCgroupPtr group);