vircgroup: introduce virCgroupV2DevicesDetectProg

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>
This commit is contained in:
Pavel Hrdina 2019-06-24 14:25:04 +02:00
parent 48423a0b5d
commit ce11a5c59f
3 changed files with 118 additions and 0 deletions

View File

@ -1719,6 +1719,7 @@ virCgroupV2Register;
# util/vircgroupv2devices.h
virCgroupV2DevicesAttachProg;
virCgroupV2DevicesAvailable;
virCgroupV2DevicesDetectProg;
# util/virclosecallbacks.h
virCloseCallbacksGet;

View 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 */

View File

@ -27,3 +27,6 @@ int
virCgroupV2DevicesAttachProg(virCgroupPtr group,
int mapfd,
size_t max);
int
virCgroupV2DevicesDetectProg(virCgroupPtr group);