[libvirt] [PATCH v2 00/16] Add vhost-user-gpu support

v1: https://www.redhat.com/archives/libvir-list/2019-June/msg00102.html This is v2 of Marc-André's series with minor changes. I'm not taking over this series, I just fixed these as part of the patch rebase so I can review it :) Changes since v1: - rebase to master - if test file build by dropping LDADDS usage - syntax-check issues: * use #pragma once * if () bracket issues * jump label indent issues * error message %s usage * size_t for loops I didn't know much about vhost-user-gpu before this series, here's what I've learned. vhost-user is a generic mechanism that allows implementing virtio device dataplane handling in a separate userspace process. vhost-user-gpu here notably moves the virgl 3d handling out of the main qemu process. The external process will be /usr/libexec/vhost-user-gpu, which comes from qemu.git contrib/vhost-user-gpu code, first released in qemu-4.1. Part of this series deals with discovering the location on disk of the vhost-user-gpu binary, and what capabilities it provides. This uses a similar mechanism to firmware.json, described in qemu docs/interop/vhost-user.json https://github.com/qemu/qemu/blob/master/docs/interop/vhost-user.json qemu 4.1 ships a 50-qemu-gpu.json to match. I believe virtio-fs will use a similar mechanism when it lands in upstream qemu, as virtiofsd is a separate process that communicates with qemu over vhost-user. For a bit more background on vhost-user-gpu process handling and the json interop motivation, here's some of the qemu discussion: https://lists.nongnu.org/archive/html/qemu-devel/2018-08/msg02610.html https://lists.nongnu.org/archive/html/qemu-devel/2018-09/msg00807.html For this series, the XML to enable this is: <video model='virtio' vhostuser='yes'> <acceleration accel3d='yes' rendernode='/path/to/rendernode'/> </video> rendernode is optional qemu_vhost_user.c handles vhost-user.json qemu_vhost_user_gpu.c handles the process management for vhost-user-gpu Marc-André Lureau (16): qemu: extract out qemuFetchConfigs from firmware domain: add "vhostuser" attribute to virtio video model domain: add rendernode attribute on <accel> qemu-cgroup: allow accel rendernode access qemu: add vhost-user-gpu capabilities checks qemu: check that qemu is vhost-user-vga capable qemu: validate virtio-gpu with vhost-user qemu: restrict 'virgl=' option to non-vhostuser video type qemu: add vhost-user helpers qemu: add qemuSecurityStartVhostUserGPU helper qemu: add vhost-user-gpu helper unit qemu: prepare domain for vhost-user GPU qemu: start/stop the vhost-user-gpu external device qemu: build vhost-user GPU devices tests: mock execv/execve tests: add vhost-user-gpu xml2argv tests docs/formatdomain.html.in | 11 + docs/schemas/domaincommon.rng | 16 +- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 2 + src/conf/domain_conf.c | 32 +- src/conf/domain_conf.h | 2 + src/qemu/Makefile.inc.am | 6 + src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 2 + src/qemu/qemu_cgroup.c | 24 ++ src/qemu/qemu_command.c | 54 ++- src/qemu/qemu_configs.c | 183 ++++++++ src/qemu/qemu_configs.h | 28 ++ src/qemu/qemu_domain.c | 11 +- src/qemu/qemu_extdevice.c | 75 +++- src/qemu/qemu_extdevice.h | 5 + src/qemu/qemu_firmware.c | 144 +------ src/qemu/qemu_process.c | 18 +- src/qemu/qemu_security.c | 47 +++ src/qemu/qemu_security.h | 6 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ src/qemu/qemu_vhost_user_gpu.c | 305 ++++++++++++++ src/qemu/qemu_vhost_user_gpu.h | 50 +++ tests/Makefile.am | 9 + .../caps_4.1.0.x86_64.xml | 2 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ .../vhost-user-gpu-secondary.args | 38 ++ .../vhost-user-gpu-secondary.xml | 44 ++ tests/qemuxml2argvdata/vhost-user-vga.args | 35 ++ tests/qemuxml2argvdata/vhost-user-vga.xml | 41 ++ tests/qemuxml2argvtest.c | 21 + tests/virfilewrapper.c | 22 + 39 files changed, 1676 insertions(+), 158 deletions(-) create mode 100644 src/qemu/qemu_configs.c create mode 100644 src/qemu/qemu_configs.h create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 100644 src/qemu/qemu_vhost_user_gpu.c create mode 100644 src/qemu/qemu_vhost_user_gpu.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c create mode 100644 tests/qemuxml2argvdata/vhost-user-gpu-secondary.args create mode 100644 tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml create mode 100644 tests/qemuxml2argvdata/vhost-user-vga.args create mode 100644 tests/qemuxml2argvdata/vhost-user-vga.xml -- 2.21.0

From: Marc-André Lureau <marcandre.lureau@redhat.com> The same config files disovery & priority rules are used for vhost-user backends. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_configs.c | 183 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_configs.h | 28 ++++++ src/qemu/qemu_firmware.c | 144 +----------------------------- 4 files changed, 215 insertions(+), 142 deletions(-) create mode 100644 src/qemu/qemu_configs.c create mode 100644 src/qemu/qemu_configs.h diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 30a9751cfd..f7a0fa4a84 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -30,6 +30,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_hotplugpriv.h \ qemu/qemu_conf.c \ qemu/qemu_conf.h \ + qemu/qemu_configs.c \ + qemu/qemu_configs.h \ qemu/qemu_process.c \ qemu/qemu_process.h \ qemu/qemu_processpriv.h \ diff --git a/src/qemu/qemu_configs.c b/src/qemu/qemu_configs.c new file mode 100644 index 0000000000..39b8906be5 --- /dev/null +++ b/src/qemu/qemu_configs.c @@ -0,0 +1,183 @@ +/* + * qemu_configs.c: QEMU firmware/vhost-user etc configs + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_configs.h" +#include "configmake.h" +#include "viralloc.h" +#include "virenum.h" +#include "virfile.h" +#include "virhash.h" +#include "virlog.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_configs"); + +static int +qemuBuildFileList(virHashTablePtr files, const char *dir) +{ + DIR *dirp; + struct dirent *ent = NULL; + int rc; + int ret = -1; + + if ((rc = virDirOpenIfExists(&dirp, dir)) < 0) + return -1; + + if (rc == 0) + return 0; + + while ((rc = virDirRead(dirp, &ent, dir)) > 0) { + VIR_AUTOFREE(char *) filename = NULL; + VIR_AUTOFREE(char *) path = NULL; + struct stat sb; + + if (STRPREFIX(ent->d_name, ".")) + continue; + + if (VIR_STRDUP(filename, ent->d_name) < 0) + goto cleanup; + + if (virAsprintf(&path, "%s/%s", dir, filename) < 0) + goto cleanup; + + if (stat(path, &sb) < 0) { + virReportSystemError(errno, _("Unable to access %s"), path); + goto cleanup; + } + + if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) + continue; + + if (virHashUpdateEntry(files, filename, path) < 0) + goto cleanup; + + path = NULL; + } + + if (rc < 0) + goto cleanup; + + ret = 0; + cleanup: + virDirClose(&dirp); + return ret; +} + +static int +qemuConfigFilesSorter(const virHashKeyValuePair *a, + const virHashKeyValuePair *b) +{ + return strcmp(a->key, b->key); +} + +#define QEMU_SYSTEM_LOCATION PREFIX "/share/qemu" +#define QEMU_ETC_LOCATION SYSCONFDIR "/qemu" + +int +qemuFetchConfigs(const char *name, + char ***configs, + bool privileged) +{ + VIR_AUTOPTR(virHashTable) files = NULL; + VIR_AUTOFREE(char *) homeConfig = NULL; + VIR_AUTOFREE(char *) xdgConfig = NULL; + VIR_AUTOFREE(char *) sysLocation = virFileBuildPath(QEMU_SYSTEM_LOCATION, name, NULL); + VIR_AUTOFREE(char *) etcLocation = virFileBuildPath(QEMU_ETC_LOCATION, name, NULL); + VIR_AUTOFREE(virHashKeyValuePairPtr) pairs = NULL; + virHashKeyValuePairPtr tmp = NULL; + + *configs = NULL; + + if (!privileged) { + /* This is a slight divergence from the specification. + * Since the system daemon runs as root, it doesn't make + * much sense to parse files in root's home directory. It + * makes sense only for session daemon which runs under + * regular user. */ + if (VIR_STRDUP(xdgConfig, getenv("XDG_CONFIG_HOME")) < 0) + return -1; + + if (!xdgConfig) { + VIR_AUTOFREE(char *) home = virGetUserDirectory(); + + if (!home) + return -1; + + if (virAsprintf(&xdgConfig, "%s/.config", home) < 0) + return -1; + } + + if (virAsprintf(&homeConfig, "%s/qemu/%s", xdgConfig, name) < 0) + return -1; + } + + if (!(files = virHashCreate(10, virHashValueFree))) + return -1; + + if (qemuBuildFileList(files, sysLocation) < 0) + return -1; + + if (qemuBuildFileList(files, etcLocation) < 0) + return -1; + + if (homeConfig && + qemuBuildFileList(files, homeConfig) < 0) + return -1; + + /* At this point, the @files hash table contains unique set of filenames + * where each filename (as key) has the highest priority full pathname + * associated with it. */ + + if (virHashSize(files) == 0) + return 0; + + if (!(pairs = virHashGetItems(files, qemuConfigFilesSorter))) + return -1; + + for (tmp = pairs; tmp->key; tmp++) { + const char *path = tmp->value; + off_t len; + + if ((len = virFileLength(path, -1)) < 0) { + virReportSystemError(errno, + _("unable to get size of '%s'"), + path); + return -1; + } + + VIR_DEBUG("%s description path '%s' len=%jd", + name, path, (intmax_t) len); + + if (len == 0) { + /* Empty files are used to mask less specific instances + * of the same file. */ + continue; + } + + if (virStringListAdd(configs, path) < 0) + return -1; + } + + return 0; +} diff --git a/src/qemu/qemu_configs.h b/src/qemu/qemu_configs.h new file mode 100644 index 0000000000..5c113752d0 --- /dev/null +++ b/src/qemu/qemu_configs.h @@ -0,0 +1,28 @@ +/* + * qemu_configs.h: QEMU firmware/vhost-user etc configs + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "internal.h" + +int +qemuFetchConfigs(const char *name, + char ***configs, + bool privileged); diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c index 983a7c83b2..f0a6953d8b 100644 --- a/src/qemu/qemu_firmware.c +++ b/src/qemu/qemu_firmware.c @@ -23,13 +23,12 @@ #include <fnmatch.h> #include "qemu_firmware.h" +#include "qemu_configs.h" #include "configmake.h" #include "qemu_capabilities.h" #include "qemu_domain.h" #include "qemu_process.h" #include "virarch.h" -#include "virfile.h" -#include "virhash.h" #include "virjson.h" #include "virlog.h" #include "virstring.h" @@ -907,150 +906,11 @@ qemuFirmwareFormat(qemuFirmwarePtr fw) } -static int -qemuFirmwareBuildFileList(virHashTablePtr files, const char *dir) -{ - DIR *dirp; - struct dirent *ent = NULL; - int rc; - int ret = -1; - - if ((rc = virDirOpenIfExists(&dirp, dir)) < 0) - return -1; - - if (rc == 0) - return 0; - - while ((rc = virDirRead(dirp, &ent, dir)) > 0) { - VIR_AUTOFREE(char *) filename = NULL; - VIR_AUTOFREE(char *) path = NULL; - struct stat sb; - - if (STRPREFIX(ent->d_name, ".")) - continue; - - if (VIR_STRDUP(filename, ent->d_name) < 0) - goto cleanup; - - if (virAsprintf(&path, "%s/%s", dir, filename) < 0) - goto cleanup; - - if (stat(path, &sb) < 0) { - virReportSystemError(errno, _("Unable to access %s"), path); - goto cleanup; - } - - if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) - continue; - - if (virHashUpdateEntry(files, filename, path) < 0) - goto cleanup; - - path = NULL; - } - - if (rc < 0) - goto cleanup; - - ret = 0; - cleanup: - virDirClose(&dirp); - return ret; -} - -static int -qemuFirmwareFilesSorter(const virHashKeyValuePair *a, - const virHashKeyValuePair *b) -{ - return strcmp(a->key, b->key); -} - -#define QEMU_FIRMWARE_SYSTEM_LOCATION PREFIX "/share/qemu/firmware" -#define QEMU_FIRMWARE_ETC_LOCATION SYSCONFDIR "/qemu/firmware" - int qemuFirmwareFetchConfigs(char ***firmwares, bool privileged) { - VIR_AUTOPTR(virHashTable) files = NULL; - VIR_AUTOFREE(char *) homeConfig = NULL; - VIR_AUTOFREE(char *) xdgConfig = NULL; - VIR_AUTOFREE(virHashKeyValuePairPtr) pairs = NULL; - virHashKeyValuePairPtr tmp = NULL; - - *firmwares = NULL; - - if (!privileged) { - /* This is a slight divergence from the specification. - * Since the system daemon runs as root, it doesn't make - * much sense to parse files in root's home directory. It - * makes sense only for session daemon which runs under - * regular user. */ - if (VIR_STRDUP(xdgConfig, getenv("XDG_CONFIG_HOME")) < 0) - return -1; - - if (!xdgConfig) { - VIR_AUTOFREE(char *) home = virGetUserDirectory(); - - if (!home) - return -1; - - if (virAsprintf(&xdgConfig, "%s/.config", home) < 0) - return -1; - } - - if (virAsprintf(&homeConfig, "%s/qemu/firmware", xdgConfig) < 0) - return -1; - } - - if (!(files = virHashCreate(10, virHashValueFree))) - return -1; - - if (qemuFirmwareBuildFileList(files, QEMU_FIRMWARE_SYSTEM_LOCATION) < 0) - return -1; - - if (qemuFirmwareBuildFileList(files, QEMU_FIRMWARE_ETC_LOCATION) < 0) - return -1; - - if (homeConfig && - qemuFirmwareBuildFileList(files, homeConfig) < 0) - return -1; - - /* At this point, the @files hash table contains unique set of filenames - * where each filename (as key) has the highest priority full pathname - * associated with it. */ - - if (virHashSize(files) == 0) - return 0; - - if (!(pairs = virHashGetItems(files, qemuFirmwareFilesSorter))) - return -1; - - for (tmp = pairs; tmp->key; tmp++) { - const char *path = tmp->value; - off_t len; - - if ((len = virFileLength(path, -1)) < 0) { - virReportSystemError(errno, - _("unable to get size of '%s'"), - path); - return -1; - } - - VIR_DEBUG("firmware description path '%s' len=%jd", - path, (intmax_t) len); - - if (len == 0) { - /* Empty files are used to mask less specific instances - * of the same file. */ - continue; - } - - if (virStringListAdd(firmwares, path) < 0) - return -1; - } - - return 0; + return qemuFetchConfigs("firmware", firmwares, privileged); } -- 2.21.0

On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
The same config files disovery & priority rules are used for vhost-user backends.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_configs.c | 183 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_configs.h | 28 ++++++ src/qemu/qemu_firmware.c | 144 +----------------------------- 4 files changed, 215 insertions(+), 142 deletions(-) create mode 100644 src/qemu/qemu_configs.c create mode 100644 src/qemu/qemu_configs.h
diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 30a9751cfd..f7a0fa4a84 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -30,6 +30,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_hotplugpriv.h \ qemu/qemu_conf.c \ qemu/qemu_conf.h \ + qemu/qemu_configs.c \ + qemu/qemu_configs.h \ qemu/qemu_process.c \ qemu/qemu_process.h \ qemu/qemu_processpriv.h \
The code looks fine, but the 'configs' naming is too generic. I suggest going verbose with it, qemu_interop_json.[ch]. Functions then should be named qemuInteropJSONXXX I think you could start the series with this, and qemu_vhost_user.c but minus the one function that uses virDomainDef additions, and those two bits could be applied independent of the rest of the series IMO Thanks, Cole

On 8/23/19 12:38 PM, Cole Robinson wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
The same config files disovery & priority rules are used for vhost-user backends.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_configs.c | 183 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_configs.h | 28 ++++++ src/qemu/qemu_firmware.c | 144 +----------------------------- 4 files changed, 215 insertions(+), 142 deletions(-) create mode 100644 src/qemu/qemu_configs.c create mode 100644 src/qemu/qemu_configs.h
diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 30a9751cfd..f7a0fa4a84 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -30,6 +30,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_hotplugpriv.h \ qemu/qemu_conf.c \ qemu/qemu_conf.h \ + qemu/qemu_configs.c \ + qemu/qemu_configs.h \ qemu/qemu_process.c \ qemu/qemu_process.h \ qemu/qemu_processpriv.h \
The code looks fine, but the 'configs' naming is too generic. I suggest going verbose with it, qemu_interop_json.[ch]. Functions then should be named qemuInteropJSONXXX
I think you could start the series with this, and qemu_vhost_user.c but minus the one function that uses virDomainDef additions, and those two bits could be applied independent of the rest of the series IMO
I realize now this file doesn't have anything json specific, so maybe qemu_interop or qemu_interop_config ? - Cole

On Fri, Aug 23, 2019 at 12:21:45PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
The same config files disovery & priority rules are used for vhost-user backends.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_configs.c | 183 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_configs.h | 28 ++++++ src/qemu/qemu_firmware.c | 144 +----------------------------- 4 files changed, 215 insertions(+), 142 deletions(-) create mode 100644 src/qemu/qemu_configs.c create mode 100644 src/qemu/qemu_configs.h
diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 30a9751cfd..f7a0fa4a84 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -30,6 +30,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_hotplugpriv.h \ qemu/qemu_conf.c \ qemu/qemu_conf.h \ + qemu/qemu_configs.c \ + qemu/qemu_configs.h \ qemu/qemu_process.c \ qemu/qemu_process.h \ qemu/qemu_processpriv.h \ diff --git a/src/qemu/qemu_configs.c b/src/qemu/qemu_configs.c new file mode 100644 index 0000000000..39b8906be5 --- /dev/null +++ b/src/qemu/qemu_configs.c @@ -0,0 +1,183 @@ +/* + * qemu_configs.c: QEMU firmware/vhost-user etc configs + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_configs.h" +#include "configmake.h" +#include "viralloc.h" +#include "virenum.h" +#include "virfile.h" +#include "virhash.h" +#include "virlog.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_configs"); + +static int +qemuBuildFileList(virHashTablePtr files, const char *dir) +{ + DIR *dirp; + struct dirent *ent = NULL; + int rc; + int ret = -1; + + if ((rc = virDirOpenIfExists(&dirp, dir)) < 0) + return -1; + + if (rc == 0) + return 0; + + while ((rc = virDirRead(dirp, &ent, dir)) > 0) { + VIR_AUTOFREE(char *) filename = NULL; + VIR_AUTOFREE(char *) path = NULL; + struct stat sb; + + if (STRPREFIX(ent->d_name, ".")) + continue; + + if (VIR_STRDUP(filename, ent->d_name) < 0) + goto cleanup; + + if (virAsprintf(&path, "%s/%s", dir, filename) < 0) + goto cleanup; + + if (stat(path, &sb) < 0) { + virReportSystemError(errno, _("Unable to access %s"), path); + goto cleanup; + } + + if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) + continue; + + if (virHashUpdateEntry(files, filename, path) < 0) + goto cleanup; + + path = NULL; + } + + if (rc < 0) + goto cleanup; + + ret = 0; + cleanup: + virDirClose(&dirp); + return ret; +} + +static int +qemuConfigFilesSorter(const virHashKeyValuePair *a, + const virHashKeyValuePair *b)
Indentation is off.
+{ + return strcmp(a->key, b->key); +} + +#define QEMU_SYSTEM_LOCATION PREFIX "/share/qemu" +#define QEMU_ETC_LOCATION SYSCONFDIR "/qemu" + +int +qemuFetchConfigs(const char *name, + char ***configs, + bool privileged) +{ + VIR_AUTOPTR(virHashTable) files = NULL; + VIR_AUTOFREE(char *) homeConfig = NULL; + VIR_AUTOFREE(char *) xdgConfig = NULL;
+ VIR_AUTOFREE(char *) sysLocation = virFileBuildPath(QEMU_SYSTEM_LOCATION, name, NULL); + VIR_AUTOFREE(char *) etcLocation = virFileBuildPath(QEMU_ETC_LOCATION, name, NULL);
These variables were not part of the original function. I'd expect a commit called 'extract out' to not have any functional impact and any changes would be done later.
+ VIR_AUTOFREE(virHashKeyValuePairPtr) pairs = NULL; + virHashKeyValuePairPtr tmp = NULL; + + *configs = NULL; +
Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> Accept a new attribute to specify usage of helper process, ex: <video> <model type='virtio' vhostuser='yes'/> </video> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- docs/formatdomain.html.in | 6 ++++++ docs/schemas/domaincommon.rng | 11 ++++++++++- src/conf/domain_conf.c | 14 ++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fcb7c59c00..ec650fbe17 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -7039,6 +7039,12 @@ qemu-kvm -net nic,model=? /dev/null Attribute <code>vram64</code> (<span class="since">since 1.3.3</span>) extends secondary bar and makes it addressable as 64bit memory. </p> + <p> + For guest type "kvm" and model type "virtio" there are + optional attributes. Attribute <code>vhost-user</code> + (<span class="since">since 5.5.0</span>) specify that a + vhost-user helper process should be associated with the GPU. + </p> </dd> <dt><code>acceleration</code></dt> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index c48f8c4f56..bac566855d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3581,7 +3581,6 @@ <value>vmvga</value> <value>xen</value> <value>vbox</value> - <value>virtio</value> <value>gop</value> <value>none</value> <value>bochs</value> @@ -3607,6 +3606,16 @@ </attribute> </optional> </group> + <group> + <attribute name="type"> + <value>virtio</value> + </attribute> + <optional> + <attribute name="vhostuser"> + <ref name="virYesNo"/> + </attribute> + </optional> + </group> </choice> <optional> <attribute name="vram"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b7a342bb91..f51575d57d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -15358,6 +15358,7 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, xmlNodePtr cur; VIR_XPATH_NODE_AUTORESTORE(ctxt); VIR_AUTOFREE(char *) type = NULL; + VIR_AUTOFREE(char *) vhostuser = NULL; VIR_AUTOFREE(char *) heads = NULL; VIR_AUTOFREE(char *) vram = NULL; VIR_AUTOFREE(char *) vram64 = NULL; @@ -15376,6 +15377,7 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, if (!type && !vram && !ram && !heads && virXMLNodeNameEqual(cur, "model")) { type = virXMLPropString(cur, "type"); + vhostuser = virXMLPropString(cur, "vhostuser"); ram = virXMLPropString(cur, "ram"); vram = virXMLPropString(cur, "vram"); vram64 = virXMLPropString(cur, "vram64"); @@ -15408,6 +15410,16 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, def->type = virDomainVideoDefaultType(dom); } + if (vhostuser != NULL) { + if (virStringParseYesNo(vhostuser, &def->vhostuser) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown vhostuser value '%s'"), vhostuser); + goto cleanup; + } + } else { + def->vhostuser = false; + } + if (ram) { if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) { virReportError(VIR_ERR_XML_ERROR, "%s", @@ -26486,6 +26498,8 @@ virDomainVideoDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " heads='%u'", def->heads); if (def->primary) virBufferAddLit(buf, " primary='yes'"); + if (def->vhostuser) + virBufferAddLit(buf, " vhostuser='yes'"); if (def->accel) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 33cef5b75c..bc2450f25e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1424,6 +1424,7 @@ struct _virDomainVideoDef { virDomainVideoDriverDefPtr driver; virDomainDeviceInfo info; virDomainVirtioOptionsPtr virtio; + bool vhostuser; }; /* graphics console modes */ -- 2.21.0

On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Accept a new attribute to specify usage of helper process, ex:
<video> <model type='virtio' vhostuser='yes'/> </video>
For other devices, we have <interface type='vhostuser'> <interface><driver name='vhost'/> <hostdev type='scsi_host'><source protocol='vhost'> Which is an attempt to make this more generic. IMO using vhostuser='yes' and is the simplest match to qemu terminology but maybe other people have stronger opinions.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- docs/formatdomain.html.in | 6 ++++++ docs/schemas/domaincommon.rng | 11 ++++++++++- src/conf/domain_conf.c | 14 ++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fcb7c59c00..ec650fbe17 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -7039,6 +7039,12 @@ qemu-kvm -net nic,model=? /dev/null Attribute <code>vram64</code> (<span class="since">since 1.3.3</span>) extends secondary bar and makes it addressable as 64bit memory. </p> + <p> + For guest type "kvm" and model type "virtio" there are + optional attributes. Attribute <code>vhost-user</code> + (<span class="since">since 5.5.0</span>) specify that a + vhost-user helper process should be associated with the GPU. + </p> </dd>
<dt><code>acceleration</code></dt> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index c48f8c4f56..bac566855d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3581,7 +3581,6 @@ <value>vmvga</value> <value>xen</value> <value>vbox</value> - <value>virtio</value> <value>gop</value> <value>none</value> <value>bochs</value> @@ -3607,6 +3606,16 @@ </attribute> </optional> </group> + <group> + <attribute name="type"> + <value>virtio</value> + </attribute> + <optional> + <attribute name="vhostuser"> + <ref name="virYesNo"/> + </attribute> + </optional> + </group> </choice> <optional> <attribute name="vram"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b7a342bb91..f51575d57d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -15358,6 +15358,7 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, xmlNodePtr cur; VIR_XPATH_NODE_AUTORESTORE(ctxt); VIR_AUTOFREE(char *) type = NULL; + VIR_AUTOFREE(char *) vhostuser = NULL; VIR_AUTOFREE(char *) heads = NULL; VIR_AUTOFREE(char *) vram = NULL; VIR_AUTOFREE(char *) vram64 = NULL; @@ -15376,6 +15377,7 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, if (!type && !vram && !ram && !heads && virXMLNodeNameEqual(cur, "model")) { type = virXMLPropString(cur, "type"); + vhostuser = virXMLPropString(cur, "vhostuser"); ram = virXMLPropString(cur, "ram"); vram = virXMLPropString(cur, "vram"); vram64 = virXMLPropString(cur, "vram64"); @@ -15408,6 +15410,16 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, def->type = virDomainVideoDefaultType(dom); }
+ if (vhostuser != NULL) { + if (virStringParseYesNo(vhostuser, &def->vhostuser) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown vhostuser value '%s'"), vhostuser); + goto cleanup; + } + } else { + def->vhostuser = false; + } + if (ram) { if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) { virReportError(VIR_ERR_XML_ERROR, "%s", @@ -26486,6 +26498,8 @@ virDomainVideoDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " heads='%u'", def->heads); if (def->primary) virBufferAddLit(buf, " primary='yes'"); + if (def->vhostuser) + virBufferAddLit(buf, " vhostuser='yes'"); if (def->accel) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 33cef5b75c..bc2450f25e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1424,6 +1424,7 @@ struct _virDomainVideoDef { virDomainVideoDriverDefPtr driver; virDomainDeviceInfo info; virDomainVirtioOptionsPtr virtio; + bool vhostuser;
I assume you followed the example of 'primary', but this should be a virTristateBool. Follow 'accel3d' parsing/formatting as an example Thanks, Cole

On Fri, Aug 23, 2019 at 12:51:56PM -0400, Cole Robinson wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Accept a new attribute to specify usage of helper process, ex:
<video> <model type='virtio' vhostuser='yes'/> </video>
For other devices, we have
<interface type='vhostuser'> <interface><driver name='vhost'/> <hostdev type='scsi_host'><source protocol='vhost'>
Which is an attempt to make this more generic.
IMO using vhostuser='yes'
missing verb?
and is the simplest match to qemu terminology but maybe other people have stronger opinions.
Yes. This does not belong in the model - it's a backend thing. <driver name='vhost'/> sounds best to me (and similarly to what commit 175077fd707db6ad87d6e2a079e82bc290ac2421 did, we can also expose <driver name='qemu'/>) Jano
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- docs/formatdomain.html.in | 6 ++++++ docs/schemas/domaincommon.rng | 11 ++++++++++- src/conf/domain_conf.c | 14 ++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-)

Hi On Tue, Aug 27, 2019 at 11:19 AM Ján Tomko <jtomko@redhat.com> wrote:
On Fri, Aug 23, 2019 at 12:51:56PM -0400, Cole Robinson wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Accept a new attribute to specify usage of helper process, ex:
<video> <model type='virtio' vhostuser='yes'/> </video>
For other devices, we have
<interface type='vhostuser'> <interface><driver name='vhost'/> <hostdev type='scsi_host'><source protocol='vhost'>
Which is an attempt to make this more generic.
IMO using vhostuser='yes'
missing verb?
and is the simplest match to qemu terminology but maybe other people have stronger opinions.
Yes.
This does not belong in the model - it's a backend thing.
<driver name='vhost'/> sounds best to me (and similarly to what commit 175077fd707db6ad87d6e2a079e82bc290ac2421 did, we can also expose <driver name='qemu'/>)
Shouldn't it be <driver name='vhost-user'/>? ('vhost' would be for a kernel backend)
Jano
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- docs/formatdomain.html.in | 6 ++++++ docs/schemas/domaincommon.rng | 11 ++++++++++- src/conf/domain_conf.c | 14 ++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-)
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Marc-André Lureau

On Thu, Aug 29, 2019 at 04:30:29PM +0400, Marc-André Lureau wrote:
Hi
On Tue, Aug 27, 2019 at 11:19 AM Ján Tomko <jtomko@redhat.com> wrote:
On Fri, Aug 23, 2019 at 12:51:56PM -0400, Cole Robinson wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Accept a new attribute to specify usage of helper process, ex:
<video> <model type='virtio' vhostuser='yes'/> </video>
For other devices, we have
<interface type='vhostuser'> <interface><driver name='vhost'/> <hostdev type='scsi_host'><source protocol='vhost'>
Which is an attempt to make this more generic.
IMO using vhostuser='yes'
missing verb?
and is the simplest match to qemu terminology but maybe other people have stronger opinions.
Yes.
This does not belong in the model - it's a backend thing.
<driver name='vhost'/> sounds best to me (and similarly to what commit 175077fd707db6ad87d6e2a079e82bc290ac2421 did, we can also expose <driver name='qemu'/>)
Shouldn't it be <driver name='vhost-user'/>?
Even better :) Jano
('vhost' would be for a kernel backend)
Jano

On Fri, Aug 23, 2019 at 12:21:46PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Accept a new attribute to specify usage of helper process, ex:
<video> <model type='virtio' vhostuser='yes'/> </video>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- docs/formatdomain.html.in | 6 ++++++ docs/schemas/domaincommon.rng | 11 ++++++++++-
Also, parser additions should include an addition to the XML test cases (virschematest will automatically pick them up and test them against the schema) and either genericxml2xmltest or qemuxml2xmltest. Jano
src/conf/domain_conf.c | 14 ++++++++++++++ src/conf/domain_conf.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-)

From: Marc-André Lureau <marcandre.lureau@redhat.com> vhost-user-gpu helper may accept --render-node option to specify on which GPU should the renderning be done. (by comparison <graphics> rendernode is the target/display rendering) Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- docs/formatdomain.html.in | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 18 +++++++++++++++++- src/conf/domain_conf.h | 1 + 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index ec650fbe17..5a4807d937 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -7059,6 +7059,11 @@ qemu-kvm -net nic,model=? /dev/null <dd>Enable 3D acceleration (for vbox driver <span class="since">since 0.7.1</span>, qemu driver <span class="since">since 1.3.0</span>)</dd> + + <dt><code>rendernode</code></dt> + <dd>Absolute path to a host's DRI device to be used for + rendering (for vhost-user driver only, <span + class="since">since 5.5.0</span>)</dd> </dl> </dd> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index bac566855d..6e91fe6cef 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3644,6 +3644,11 @@ <ref name="virYesNo"/> </attribute> </optional> + <optional> + <attribute name="rendernode"> + <ref name="absFilePath"/> + </attribute> + </optional> </element> </optional> </element> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f51575d57d..2cc055491d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2832,6 +2832,8 @@ virDomainVideoDefClear(virDomainVideoDefPtr def) virDomainDeviceInfoClear(&def->info); + if (def->accel) + VIR_FREE(def->accel->rendernode); VIR_FREE(def->accel); VIR_FREE(def->virtio); VIR_FREE(def->driver); @@ -15270,6 +15272,7 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) int val; VIR_AUTOFREE(char *) accel2d = NULL; VIR_AUTOFREE(char *) accel3d = NULL; + VIR_AUTOFREE(char *) rendernode = NULL; cur = node->children; while (cur != NULL) { @@ -15278,12 +15281,13 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) virXMLNodeNameEqual(cur, "acceleration")) { accel3d = virXMLPropString(cur, "accel3d"); accel2d = virXMLPropString(cur, "accel2d"); + rendernode = virXMLPropString(cur, "rendernode"); } } cur = cur->next; } - if (!accel3d && !accel2d) + if (!accel3d && !accel2d && !rendernode) return NULL; if (VIR_ALLOC(def) < 0) @@ -15307,6 +15311,9 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) def->accel2d = val; } + if (VIR_STRDUP(def->rendernode, rendernode) < 0) + goto cleanup; + cleanup: return def; } @@ -15474,6 +15481,11 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, goto error; } } + if (!def->vhostuser && def->accel && def->accel->rendernode) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unsupported rendernode accel attribute without 'vhost-user'")); + goto error; + } if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info, flags) < 0) goto error; @@ -26452,6 +26464,10 @@ virDomainVideoAccelDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " accel2d='%s'", virTristateBoolTypeToString(def->accel2d)); } + if (def->rendernode) { + virBufferAsprintf(buf, " rendernode='%s'", + def->rendernode); + } virBufferAddLit(buf, "/>\n"); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bc2450f25e..707fbd1cd3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1405,6 +1405,7 @@ VIR_ENUM_DECL(virDomainVideoVGAConf); struct _virDomainVideoAccelDef { int accel2d; /* enum virTristateBool */ int accel3d; /* enum virTristateBool */ + char *rendernode; }; -- 2.21.0

On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
vhost-user-gpu helper may accept --render-node option to specify on which GPU should the renderning be done.
What does it do if the user doesn't pass one? Pick one itself, or just not use one somehow? If it picks one, then we may need to treat this like we treat other rendernode instances and autoallocate one if the user doesn't specify, otherwise we won't be able to add the path to the cgroup for example, or selinux label it if necessary. I'm not sure if that actually applies in this case, but it's worth considering.
(by comparison <graphics> rendernode is the target/display rendering)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com>
Also I see now that I accidentally signed off all these patches, that was not intentional. Please strip those from v3
--- docs/formatdomain.html.in | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 18 +++++++++++++++++- src/conf/domain_conf.h | 1 + 4 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index ec650fbe17..5a4807d937 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -7059,6 +7059,11 @@ qemu-kvm -net nic,model=? /dev/null <dd>Enable 3D acceleration (for vbox driver <span class="since">since 0.7.1</span>, qemu driver <span class="since">since 1.3.0</span>)</dd> + + <dt><code>rendernode</code></dt> + <dd>Absolute path to a host's DRI device to be used for + rendering (for vhost-user driver only, <span + class="since">since 5.5.0</span>)</dd> </dl> </dd>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index bac566855d..6e91fe6cef 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3644,6 +3644,11 @@ <ref name="virYesNo"/> </attribute> </optional> + <optional> + <attribute name="rendernode"> + <ref name="absFilePath"/> + </attribute> + </optional> </element> </optional> </element> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f51575d57d..2cc055491d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2832,6 +2832,8 @@ virDomainVideoDefClear(virDomainVideoDefPtr def)
virDomainDeviceInfoClear(&def->info);
+ if (def->accel) + VIR_FREE(def->accel->rendernode); VIR_FREE(def->accel); VIR_FREE(def->virtio); VIR_FREE(def->driver); @@ -15270,6 +15272,7 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) int val; VIR_AUTOFREE(char *) accel2d = NULL; VIR_AUTOFREE(char *) accel3d = NULL; + VIR_AUTOFREE(char *) rendernode = NULL;
cur = node->children; while (cur != NULL) { @@ -15278,12 +15281,13 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) virXMLNodeNameEqual(cur, "acceleration")) { accel3d = virXMLPropString(cur, "accel3d"); accel2d = virXMLPropString(cur, "accel2d"); + rendernode = virXMLPropString(cur, "rendernode"); } } cur = cur->next; }
- if (!accel3d && !accel2d) + if (!accel3d && !accel2d && !rendernode) return NULL;
if (VIR_ALLOC(def) < 0) @@ -15307,6 +15311,9 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) def->accel2d = val; }
+ if (VIR_STRDUP(def->rendernode, rendernode) < 0) + goto cleanup; +
Huh, this function has no error reporting? A bogus accel2d/accel3d value will raise an error but it never triggers the error path in the calling function. Not your fault of course :)
cleanup: return def; } @@ -15474,6 +15481,11 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, goto error; } } + if (!def->vhostuser && def->accel && def->accel->rendernode) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unsupported rendernode accel attribute without 'vhost-user'")); + goto error; + }
This function doesn't represent best practices, but this style of check should be moved to virDomainVideoDefValidate IMO Thanks, Cole

On Fri, Aug 23, 2019 at 01:04:53PM -0400, Cole Robinson wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
vhost-user-gpu helper may accept --render-node option to specify on which GPU should the renderning be done.
What does it do if the user doesn't pass one? Pick one itself, or just not use one somehow?
If it picks one, then we may need to treat this like we treat other rendernode instances and autoallocate one if the user doesn't specify, otherwise we won't be able to add the path to the cgroup for example, or selinux label it if necessary. I'm not sure if that actually applies in this case, but it's worth considering.
Even if we'll chose one automatically, we should at least output it in live XML.
(by comparison <graphics> rendernode is the target/display rendering)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com>
Also I see now that I accidentally signed off all these patches, that was not intentional. Please strip those from v3
Per https://libvirt.org/governance.html#codeofconduct we need your intentional agreement with the Developer Certificate of Origin: https://developercertificate.org/ to be able to include your changes. I'd be okay from stripping it from the patches you did not actually change, but it should stay on those where you actually changed something. Also, we do not have that process documented, but the kernel practice (and what I've been doing) seems to be that the maintainer merging the patch also adds a sign-off to provide that chain of certificates. Thirdly, I see some patches committed to libvirt by Marc-André but no mention in AUTHORS.in history - maybe it's time to get his commit access restored and documented?
--- docs/formatdomain.html.in | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 18 +++++++++++++++++- src/conf/domain_conf.h | 1 + 4 files changed, 28 insertions(+), 1 deletion(-)
@@ -15474,6 +15481,11 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, goto error; } } + if (!def->vhostuser && def->accel && def->accel->rendernode) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unsupported rendernode accel attribute without 'vhost-user'")); + goto error; + }
This function doesn't represent best practices, but this style of check should be moved to virDomainVideoDefValidate IMO
Yes. Jano
Thanks, Cole
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

Hi On Fri, Aug 23, 2019 at 9:05 PM Cole Robinson <crobinso@redhat.com> wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
vhost-user-gpu helper may accept --render-node option to specify on which GPU should the renderning be done.
What does it do if the user doesn't pass one? Pick one itself, or just not use one somehow?
This is left unspecified. So it may probe one itself and use it, or fallback to full-software.
If it picks one, then we may need to treat this like we treat other rendernode instances and autoallocate one if the user doesn't specify, otherwise we won't be able to add the path to the cgroup for example, or selinux label it if necessary. I'm not sure if that actually applies in this case, but it's worth considering.
I think we may want to auto-allocate a drm node if the helper accepts the argument, as it is almost always what you'd want. But then we lose the ability to *not* specify it. I am fine with that.
(by comparison <graphics> rendernode is the target/display rendering)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com>
Also I see now that I accidentally signed off all these patches, that was not intentional. Please strip those from v3
--- docs/formatdomain.html.in | 5 +++++ docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 18 +++++++++++++++++- src/conf/domain_conf.h | 1 + 4 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index ec650fbe17..5a4807d937 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -7059,6 +7059,11 @@ qemu-kvm -net nic,model=? /dev/null <dd>Enable 3D acceleration (for vbox driver <span class="since">since 0.7.1</span>, qemu driver <span class="since">since 1.3.0</span>)</dd> + + <dt><code>rendernode</code></dt> + <dd>Absolute path to a host's DRI device to be used for + rendering (for vhost-user driver only, <span + class="since">since 5.5.0</span>)</dd> </dl> </dd>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index bac566855d..6e91fe6cef 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3644,6 +3644,11 @@ <ref name="virYesNo"/> </attribute> </optional> + <optional> + <attribute name="rendernode"> + <ref name="absFilePath"/> + </attribute> + </optional> </element> </optional> </element> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f51575d57d..2cc055491d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2832,6 +2832,8 @@ virDomainVideoDefClear(virDomainVideoDefPtr def)
virDomainDeviceInfoClear(&def->info);
+ if (def->accel) + VIR_FREE(def->accel->rendernode); VIR_FREE(def->accel); VIR_FREE(def->virtio); VIR_FREE(def->driver); @@ -15270,6 +15272,7 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) int val; VIR_AUTOFREE(char *) accel2d = NULL; VIR_AUTOFREE(char *) accel3d = NULL; + VIR_AUTOFREE(char *) rendernode = NULL;
cur = node->children; while (cur != NULL) { @@ -15278,12 +15281,13 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) virXMLNodeNameEqual(cur, "acceleration")) { accel3d = virXMLPropString(cur, "accel3d"); accel2d = virXMLPropString(cur, "accel2d"); + rendernode = virXMLPropString(cur, "rendernode"); } } cur = cur->next; }
- if (!accel3d && !accel2d) + if (!accel3d && !accel2d && !rendernode) return NULL;
if (VIR_ALLOC(def) < 0) @@ -15307,6 +15311,9 @@ virDomainVideoAccelDefParseXML(xmlNodePtr node) def->accel2d = val; }
+ if (VIR_STRDUP(def->rendernode, rendernode) < 0) + goto cleanup; +
Huh, this function has no error reporting? A bogus accel2d/accel3d value will raise an error but it never triggers the error path in the calling function. Not your fault of course :)
cleanup: return def; } @@ -15474,6 +15481,11 @@ virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt, goto error; } } + if (!def->vhostuser && def->accel && def->accel->rendernode) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unsupported rendernode accel attribute without 'vhost-user'")); + goto error; + }
This function doesn't represent best practices, but this style of check should be moved to virDomainVideoDefValidate IMO
Thanks, Cole
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_cgroup.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index ecd96efb0a..eb6f993d8e 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -503,6 +503,25 @@ qemuSetupGraphicsCgroup(virDomainObjPtr vm, } +static int +qemuSetupVideoAccelCgroup(virDomainObjPtr vm, + virDomainVideoAccelDefPtr def) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret; + + if (!def->rendernode || + !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) + return 0; + + ret = virCgroupAllowDevicePath(priv->cgroup, def->rendernode, + VIR_CGROUP_DEVICE_RW, false); + virDomainAuditCgroupPath(vm, priv->cgroup, "allow", def->rendernode, + "rw", ret); + return ret; +} + + static int qemuSetupBlkioCgroup(virDomainObjPtr vm) { @@ -803,6 +822,11 @@ qemuSetupDevicesCgroup(virDomainObjPtr vm) goto cleanup; } + for (i = 0; i < vm->def->nvideos; i++) { + if (qemuSetupVideoAccelCgroup(vm, vm->def->videos[i]->accel) < 0) + goto cleanup; + } + for (i = 0; i < vm->def->ninputs; i++) { if (qemuSetupInputCgroup(vm, vm->def->inputs[i]) < 0) goto cleanup; -- 2.21.0

On Fri, Aug 23, 2019 at 12:21:48PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_cgroup.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> Those new devices are merged for QEMU 4.1. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_capabilities.c | 4 ++++ src/qemu/qemu_capabilities.h | 2 ++ tests/qemucapabilitiesdata/caps_4.1.0.x86_64.xml | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 73300128ea..d27f54d16e 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -537,6 +537,8 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 335 */ "bochs-display", "migration-file-drop-cache", + "vhost-user-gpu", + "vhost-user-vga", ); @@ -1127,6 +1129,8 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "virtio-serial-pci-non-transitional", QEMU_CAPS_VIRTIO_PCI_TRANSITIONAL }, { "max-x86_64-cpu", QEMU_CAPS_X86_MAX_CPU }, { "bochs-display", QEMU_CAPS_DEVICE_BOCHS_DISPLAY }, + { "vhost-user-gpu", QEMU_CAPS_DEVICE_VHOST_USER_GPU }, + { "vhost-user-vga", QEMU_CAPS_DEVICE_VHOST_USER_VGA }, }; static struct virQEMUCapsStringFlags virQEMUCapsDevicePropsVirtioBalloon[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 68ef6c49b4..6f1e1dd2f3 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -518,6 +518,8 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 335 */ QEMU_CAPS_DEVICE_BOCHS_DISPLAY, /* -device bochs-display */ QEMU_CAPS_MIGRATION_FILE_DROP_CACHE, /* migration with disk cache on is safe for type='file' disks */ + QEMU_CAPS_DEVICE_VHOST_USER_GPU, /* -device vhost-user-gpu */ + QEMU_CAPS_DEVICE_VHOST_USER_VGA, /* -device vhost-user-vga */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_4.1.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_4.1.0.x86_64.xml index f4583d7fe7..5d4540b3f7 100644 --- a/tests/qemucapabilitiesdata/caps_4.1.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_4.1.0.x86_64.xml @@ -209,6 +209,8 @@ <flag name='canonical-cpu-features'/> <flag name='bochs-display'/> <flag name='migration-file-drop-cache'/> + <flag name='vhost-user-gpu'/> + <flag name='vhost-user-vga'/> <version>4000050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100759</microcodeVersion> -- 2.21.0

On Fri, Aug 23, 2019 at 12:21:49PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Those new devices are merged for QEMU 4.1.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_capabilities.c | 4 ++++ src/qemu/qemu_capabilities.h | 2 ++ tests/qemucapabilitiesdata/caps_4.1.0.x86_64.xml | 2 ++ 3 files changed, 8 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> To support virtio VGA with vhost-user, vhost-user-vga device is necessary. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_domain.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index d0722f8761..bf0531126d 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -12386,9 +12386,14 @@ bool qemuDomainSupportsVideoVga(virDomainVideoDefPtr video, virQEMUCapsPtr qemuCaps) { - if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && - !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_VGA)) - return false; + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO) { + if (video->vhostuser) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_VGA)) + return false; + } else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_VGA)) { + return false; + } + } return true; } -- 2.21.0

On Fri, Aug 23, 2019 at 12:21:50PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
To support virtio VGA with vhost-user, vhost-user-vga device is necessary.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_domain.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> Check qemu capability, and accept 3d acceleration. 3d acceleration support is checked when looking for a suitable vhost-user helper. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_process.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index c9921646e9..c439f17011 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5274,8 +5274,10 @@ qemuProcessStartValidateVideo(virDomainObjPtr vm, !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VMWARE_SVGA)) || (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QXL)) || - (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && + (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && !video->vhostuser && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_GPU)) || + (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->vhostuser && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_GPU)) || (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_GPU_CCW))) { @@ -5285,7 +5287,15 @@ qemuProcessStartValidateVideo(virDomainObjPtr vm, return -1; } - if (video->accel) { + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && + video->vhostuser && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_GPU)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("this QEMU does not support vhost-user backed video device")); + return -1; + } + + if (!video->vhostuser && video->accel) { if (video->accel->accel3d == VIR_TRISTATE_SWITCH_ON && (video->type != VIR_DOMAIN_VIDEO_TYPE_VIRTIO || !virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_GPU_VIRGL))) { -- 2.21.0

From: Marc-André Lureau <marcandre.lureau@redhat.com> vhost-user device doesn't have a virgl option, it is passed to the vhost-user-gpu helper process instead. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_command.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 49652a8565..8bef103f68 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4683,9 +4683,11 @@ qemuBuildDeviceVideoStr(const virDomainDef *def, virBufferAsprintf(&buf, ",id=%s", video->info.alias); - if (video->accel && video->accel->accel3d == VIR_TRISTATE_SWITCH_ON) { - virBufferAsprintf(&buf, ",virgl=%s", - virTristateSwitchTypeToString(video->accel->accel3d)); + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && !video->vhostuser) { + if (video->accel && video->accel->accel3d == VIR_TRISTATE_SWITCH_ON) { + virBufferAsprintf(&buf, ",virgl=%s", + virTristateSwitchTypeToString(video->accel->accel3d)); + } } if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL) { -- 2.21.0

From: Marc-André Lureau <marcandre.lureau@redhat.com> Add qemuVhostUserFetchConfigs() to discover vhost-user helpers. qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ tests/Makefile.am | 9 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ 13 files changed, 609 insertions(+) create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4c57f0995f..2f7077ddc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -96,6 +96,7 @@ virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) VIR_FREE(info->loadparm); info->isolationGroup = 0; info->isolationGroupLocked = false; + VIR_FREE(info->vhost_user_binary); } void diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d0854925e3..0b0c525ad8 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -179,6 +179,7 @@ struct _virDomainDeviceInfo { * cases we might want to prevent that from happening by * locking the isolation group */ bool isolationGroupLocked; + char *vhost_user_binary; }; void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index f7a0fa4a84..18a9220d01 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -60,6 +60,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_qapi.h \ qemu/qemu_tpm.c \ qemu/qemu_tpm.h \ + qemu/qemu_vhost_user.c \ + qemu/qemu_vhost_user.h \ $(NULL) diff --git a/src/qemu/qemu_vhost_user.c b/src/qemu/qemu_vhost_user.c new file mode 100644 index 0000000000..7a97052ab9 --- /dev/null +++ b/src/qemu/qemu_vhost_user.c @@ -0,0 +1,394 @@ +/* + * qemu_vhost_user.c: QEMU vhost-user + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_vhost_user.h" +#include "qemu_configs.h" +#include "virjson.h" +#include "virlog.h" +#include "virstring.h" +#include "viralloc.h" +#include "virenum.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_vhost_user"); + +typedef enum { + QEMU_VHOST_USER_TYPE_NONE = 0, + QEMU_VHOST_USER_TYPE_9P, + QEMU_VHOST_USER_TYPE_BALLOON, + QEMU_VHOST_USER_TYPE_BLOCK, + QEMU_VHOST_USER_TYPE_CAIF, + QEMU_VHOST_USER_TYPE_CONSOLE, + QEMU_VHOST_USER_TYPE_CRYPTO, + QEMU_VHOST_USER_TYPE_GPU, + QEMU_VHOST_USER_TYPE_INPUT, + QEMU_VHOST_USER_TYPE_NET, + QEMU_VHOST_USER_TYPE_RNG, + QEMU_VHOST_USER_TYPE_RPMSG, + QEMU_VHOST_USER_TYPE_RPROC_SERIAL, + QEMU_VHOST_USER_TYPE_SCSI, + QEMU_VHOST_USER_TYPE_VSOCK, + + QEMU_VHOST_USER_TYPE_LAST +} qemuVhostUserType; + +VIR_ENUM_DECL(qemuVhostUserType); +VIR_ENUM_IMPL(qemuVhostUserType, + QEMU_VHOST_USER_TYPE_LAST, + "", + "9p", + "balloon", + "block", + "caif", + "console", + "crypto", + "gpu", + "input", + "net", + "rng", + "rpmsg", + "rproc-serial", + "scsi", + "vsock", +); + +typedef enum { + QEMU_VHOST_USER_GPU_FEATURE_NONE = 0, + QEMU_VHOST_USER_GPU_FEATURE_VIRGL, + QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE, + + QEMU_VHOST_USER_GPU_FEATURE_LAST +} qemuVhostUserGPUFeature; + +VIR_ENUM_DECL(qemuVhostUserGPUFeature); +VIR_ENUM_IMPL(qemuVhostUserGPUFeature, + QEMU_VHOST_USER_GPU_FEATURE_LAST, + "", + "virgl", + "render-node", +); + +typedef struct _qemuVhostUserGPU qemuVhostUserGPU; +typedef qemuVhostUserGPU *qemuVhostUserGPUPtr; +struct _qemuVhostUserGPU { + size_t nfeatures; + qemuVhostUserGPUFeature *features; +}; + +struct _qemuVhostUser { + /* Description intentionally not parsed. */ + qemuVhostUserType type; + char *binary; + /* Tags intentionally not parsed. */ + + union { + qemuVhostUserGPU gpu; + } capabilities; +}; + +static void +qemuVhostUserGPUFeatureFree(qemuVhostUserGPUFeature *features) +{ + VIR_FREE(features); +} + + +VIR_DEFINE_AUTOPTR_FUNC(qemuVhostUserGPUFeature, qemuVhostUserGPUFeatureFree); + +void +qemuVhostUserFree(qemuVhostUserPtr vu) +{ + if (!vu) + return; + + if (vu->type == QEMU_VHOST_USER_TYPE_GPU) + VIR_FREE(vu->capabilities.gpu.features); + + VIR_FREE(vu->binary); + + VIR_FREE(vu); +} + +/* 1MiB should be enough for everybody (TM) */ +#define DOCUMENT_SIZE (1024 * 1024) + +static int +qemuVhostUserTypeParse(const char *path, + virJSONValuePtr doc, + qemuVhostUserPtr vu) +{ + const char *type = virJSONValueObjectGetString(doc, "type"); + int tmp; + + VIR_DEBUG("vhost-user description path '%s' type : %s", + path, type); + + if ((tmp = qemuVhostUserTypeTypeFromString(type)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown vhost-user type: '%s'"), + type); + return -1; + } + + vu->type = tmp; + + return 0; +} + +static int +qemuVhostUserBinaryParse(const char *path, + virJSONValuePtr doc, + qemuVhostUserPtr vu) +{ + const char *binary = virJSONValueObjectGetString(doc, "binary"); + + VIR_DEBUG("vhost-user description path '%s' binary : %s", + path, binary); + + if (VIR_STRDUP(vu->binary, binary) < 0) + return -1; + + return 0; +} + +qemuVhostUserPtr +qemuVhostUserParse(const char *path) +{ + VIR_AUTOFREE(char *) cont = NULL; + VIR_AUTOPTR(virJSONValue) doc = NULL; + VIR_AUTOPTR(qemuVhostUser) vu = NULL; + qemuVhostUserPtr ret = NULL; + + if (virFileReadAll(path, DOCUMENT_SIZE, &cont) < 0) + return NULL; + + if (!(doc = virJSONValueFromString(cont))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to parse json file '%s'"), + path); + return NULL; + } + + if (VIR_ALLOC(vu) < 0) + return NULL; + + if (qemuVhostUserTypeParse(path, doc, vu) < 0) + return NULL; + + if (qemuVhostUserBinaryParse(path, doc, vu) < 0) + return NULL; + + VIR_STEAL_PTR(ret, vu); + return ret; +} + +char * +qemuVhostUserFormat(qemuVhostUserPtr vu) +{ + VIR_AUTOPTR(virJSONValue) doc = NULL; + + if (!vu) + return NULL; + + if (!(doc = virJSONValueNewObject())) + return NULL; + + if (virJSONValueObjectAppendString(doc, "type", + qemuVhostUserTypeTypeToString(vu->type)) < 0) + return NULL; + + if (virJSONValueObjectAppendString(doc, "binary", vu->binary) < 0) + return NULL; + + return virJSONValueToString(doc, true); +} + +int +qemuVhostUserFetchConfigs(char ***configs, + bool privileged) +{ + return qemuFetchConfigs("vhost-user", configs, privileged); +} + +static ssize_t +qemuVhostUserFetchParsedConfigs(bool privileged, + qemuVhostUserPtr **vhostuserRet, + char ***pathsRet) +{ + VIR_AUTOSTRINGLIST paths = NULL; + size_t npaths; + qemuVhostUserPtr *vus = NULL; + size_t i; + + if (qemuVhostUserFetchConfigs(&paths, privileged) < 0) + return -1; + + npaths = virStringListLength((const char **)paths); + + if (VIR_ALLOC_N(vus, npaths) < 0) + return -1; + + for (i = 0; i < npaths; i++) { + if (!(vus[i] = qemuVhostUserParse(paths[i]))) + goto error; + } + + VIR_STEAL_PTR(*vhostuserRet, vus); + if (pathsRet) + VIR_STEAL_PTR(*pathsRet, paths); + return npaths; + + error: + while (i > 0) + qemuVhostUserFree(vus[--i]); + VIR_FREE(vus); + return -1; +} + + +static int +qemuVhostUserGPUFillCapabilities(qemuVhostUserPtr vu, + virJSONValuePtr doc) +{ + qemuVhostUserGPUPtr gpu = &vu->capabilities.gpu; + virJSONValuePtr featuresJSON; + size_t nfeatures; + size_t i; + VIR_AUTOPTR(qemuVhostUserGPUFeature) features = NULL; + + if (!(featuresJSON = virJSONValueObjectGetArray(doc, "features"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to get features from '%s'"), + vu->binary); + return -1; + } + + nfeatures = virJSONValueArraySize(featuresJSON); + if (VIR_ALLOC_N(features, nfeatures) < 0) + return -1; + + for (i = 0; i < nfeatures; i++) { + virJSONValuePtr item = virJSONValueArrayGet(featuresJSON, i); + const char *tmpStr = virJSONValueGetString(item); + int tmp; + + if ((tmp = qemuVhostUserGPUFeatureTypeFromString(tmpStr)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown feature %s"), + tmpStr); + continue; + } + + features[i] = tmp; + } + + VIR_STEAL_PTR(gpu->features, features); + gpu->nfeatures = nfeatures; + + return 0; +} + + +static bool +qemuVhostUserGPUHasFeature(qemuVhostUserGPUPtr gpu, + qemuVhostUserGPUFeature feature) +{ + size_t i; + + for (i = 0; i < gpu->nfeatures; i++) { + if (gpu->features[i] == feature) + return true; + } + + return false; +} + + +int +qemuVhostUserFillDomainGPU(virQEMUDriverPtr driver, + virDomainVideoDefPtr video) +{ + qemuVhostUserPtr *vus = NULL; + ssize_t nvus = 0; + ssize_t i; + int ret = -1; + + if ((nvus = qemuVhostUserFetchParsedConfigs(driver->privileged, + &vus, NULL)) < 0) + goto end; + + for (i = 0; i < nvus; i++) { + qemuVhostUserPtr vu = vus[i]; + VIR_AUTOPTR(virJSONValue) doc = NULL; + VIR_AUTOFREE(char *) output = NULL; + VIR_AUTOPTR(virCommand) cmd = NULL; + + if (vu->type != QEMU_VHOST_USER_TYPE_GPU) + continue; + + cmd = virCommandNewArgList(vu->binary, "--print-capabilities", NULL); + virCommandSetOutputBuffer(cmd, &output); + if (virCommandRun(cmd, NULL) < 0) + continue; + + if (!(doc = virJSONValueFromString(output))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to parse json capabilities '%s'"), + vu->binary); + continue; + } + + if (qemuVhostUserGPUFillCapabilities(vu, doc) < 0) + continue; + + if (video->accel) { + if (video->accel->accel3d && + !qemuVhostUserGPUHasFeature(&vu->capabilities.gpu, + QEMU_VHOST_USER_GPU_FEATURE_VIRGL)) + continue; + + if (video->accel->rendernode && + !qemuVhostUserGPUHasFeature(&vu->capabilities.gpu, + QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE)) + continue; + } + + VIR_FREE(video->info.vhost_user_binary); + if (VIR_STRDUP(video->info.vhost_user_binary, vu->binary) < 0) + goto end; + + ret = 0; + break; + } + + if (i == nvus) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Unable to find a satisfying vhost-user-gpu")); + } + + end: + for (i = 0; i < nvus; i++) + qemuVhostUserFree(vus[i]); + VIR_FREE(vus); + return ret; +} diff --git a/src/qemu/qemu_vhost_user.h b/src/qemu/qemu_vhost_user.h new file mode 100644 index 0000000000..76701dd1fa --- /dev/null +++ b/src/qemu/qemu_vhost_user.h @@ -0,0 +1,48 @@ +/* + * qemu_vhost_user.h: QEMU vhost-user + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "domain_conf.h" +#include "qemu_conf.h" +#include "virautoclean.h" +#include "virarch.h" + +typedef struct _qemuVhostUser qemuVhostUser; +typedef qemuVhostUser *qemuVhostUserPtr; + +void +qemuVhostUserFree(qemuVhostUserPtr fw); + +VIR_DEFINE_AUTOPTR_FUNC(qemuVhostUser, qemuVhostUserFree); + +qemuVhostUserPtr +qemuVhostUserParse(const char *path); + +char * +qemuVhostUserFormat(qemuVhostUserPtr fw); + +int +qemuVhostUserFetchConfigs(char ***configs, + bool privileged); + +int +qemuVhostUserFillDomainGPU(virQEMUDriverPtr driver, + virDomainVideoDefPtr video); diff --git a/tests/Makefile.am b/tests/Makefile.am index f92710db43..4f4a5236ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -290,6 +290,7 @@ test_programs += qemuxml2argvtest qemuxml2xmltest \ qemumigparamstest \ qemusecuritytest \ qemufirmwaretest \ + qemuvhostusertest \ $(NULL) test_helpers += qemucapsprobe test_libraries += libqemumonitortestutils.la \ @@ -692,6 +693,13 @@ qemufirmwaretest_SOURCES = \ $(NULL) qemufirmwaretest_LDADD = $(qemu_LDADDS) +qemuvhostusertest_SOURCES = \ + qemuvhostusertest.c \ + testutils.h testutils.c \ + virfilewrapper.c virfilewrapper.h \ + $(NULL) +qemuvhostusertest_LDADD = $(qemu_LDADDS) + else ! WITH_QEMU EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c \ qemudomaincheckpointxml2xmltest.c qemudomainsnapshotxml2xmltest.c \ @@ -706,6 +714,7 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c \ qemusecuritytest.c qemusecuritytest.h \ qemusecuritymock.c \ qemufirmwaretest.c \ + qemuvhostusertest.c \ $(QEMUMONITORTESTUTILS_SOURCES) endif ! WITH_QEMU diff --git a/tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json b/tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json new file mode 120000 index 0000000000..aa93864aa7 --- /dev/null +++ b/tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json @@ -0,0 +1 @@ +../../../usr/share/qemu/vhost-user/50-gpu.json \ No newline at end of file diff --git a/tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json b/tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu b/tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu new file mode 100755 index 0000000000..a2c2ee0713 --- /dev/null +++ b/tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu @@ -0,0 +1,11 @@ +#!/bin/sh + +cat <<EOF +{ + "type": "gpu", + "features": [ + "render-node", + "virgl" + ] +} +EOF diff --git a/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json b/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json new file mode 120000 index 0000000000..7051776593 --- /dev/null +++ b/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json @@ -0,0 +1 @@ +50-gpu.json \ No newline at end of file diff --git a/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json b/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json new file mode 100644 index 0000000000..4c751971db --- /dev/null +++ b/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json @@ -0,0 +1,8 @@ +{ + "description": "QEMU vhost-user-gpu", + "type": "gpu", + "binary": "/usr/libexec/qemu/vhost-user/test-vhost-user-gpu", + "tags": [ + "CONFIG_OPENGL_DMABUF=y" + ] +} diff --git a/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json b/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json new file mode 120000 index 0000000000..7051776593 --- /dev/null +++ b/tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json @@ -0,0 +1 @@ +50-gpu.json \ No newline at end of file diff --git a/tests/qemuvhostusertest.c b/tests/qemuvhostusertest.c new file mode 100644 index 0000000000..52adf9834a --- /dev/null +++ b/tests/qemuvhostusertest.c @@ -0,0 +1,132 @@ +#include <config.h> + +#include <inttypes.h> + +#include "testutils.h" +#include "virfilewrapper.h" +#include "qemu/qemu_vhost_user.h" +#include "configmake.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +/* A very basic test. Parse given JSON vhostuser description into + * an internal structure, format it back and compare with the + * contents of the file (minus some keys that are not parsed). + */ +static int +testParseFormatVU(const void *opaque) +{ + const char *filename = opaque; + VIR_AUTOFREE(char *) path = NULL; + VIR_AUTOPTR(qemuVhostUser) vu = NULL; + VIR_AUTOFREE(char *) buf = NULL; + VIR_AUTOPTR(virJSONValue) json = NULL; + VIR_AUTOFREE(char *) expected = NULL; + VIR_AUTOFREE(char *) actual = NULL; + + if (virAsprintf(&path, "%s/qemuvhostuserdata/%s", + abs_srcdir, filename) < 0) + return -1; + + if (!(vu = qemuVhostUserParse(path))) + return -1; + + if (virFileReadAll(path, + 1024 * 1024, /* 1MiB */ + &buf) < 0) + return -1; + + if (!(json = virJSONValueFromString(buf))) + return -1; + + /* Description and tags are not parsed. */ + if (virJSONValueObjectRemoveKey(json, "description", NULL) < 0 || + virJSONValueObjectRemoveKey(json, "tags", NULL) < 0) + return -1; + + if (!(expected = virJSONValueToString(json, true))) + return -1; + + if (!(actual = qemuVhostUserFormat(vu))) + return -1; + + return virTestCompareToString(expected, actual); +} + + +static int +testVUPrecedence(const void *opaque ATTRIBUTE_UNUSED) +{ + VIR_AUTOFREE(char *) fakehome = NULL; + VIR_AUTOSTRINGLIST vuList = NULL; + size_t nvuList; + size_t i; + const char *expected[] = { + PREFIX "/share/qemu/vhost-user/30-gpu.json", + SYSCONFDIR "/qemu/vhost-user/40-gpu.json", + PREFIX "/share/qemu/vhost-user/60-gpu.json", + }; + const size_t nexpected = ARRAY_CARDINALITY(expected); + + if (VIR_STRDUP(fakehome, abs_srcdir "/qemuvhostuserdata/home/user/.config") < 0) + return -1; + + setenv("XDG_CONFIG_HOME", fakehome, 1); + + if (qemuVhostUserFetchConfigs(&vuList, false) < 0) + return -1; + + if (!vuList) { + fprintf(stderr, "Expected a non-NULL result, but got a NULL result\n"); + return -1; + } + + nvuList = virStringListLength((const char **)vuList); + + for (i = 0; i < MAX(nvuList, nexpected); i++) { + const char *e = i < nexpected ? expected[i] : NULL; + const char *f = i < nvuList ? vuList[i] : NULL; + + if (STRNEQ_NULLABLE(e, f)) { + fprintf(stderr, + "Unexpected path (i=%zu). Expected %s got %s \n", + i, NULLSTR(e), NULLSTR(f)); + return -1; + } + } + + return 0; +} + + +static int +mymain(void) +{ + int ret = 0; + + virFileWrapperAddPrefix(SYSCONFDIR "/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/etc/qemu/vhost-user"); + virFileWrapperAddPrefix(PREFIX "/share/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/usr/share/qemu/vhost-user"); + virFileWrapperAddPrefix("/home/user/.config/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/home/user/.config/qemu/vhost-user"); + +#define DO_PARSE_TEST(filename) \ + do { \ + if (virTestRun("QEMU vhost-user " filename, \ + testParseFormatVU, filename) < 0) \ + ret = -1; \ + } while (0) + + DO_PARSE_TEST("usr/share/qemu/vhost-user/50-gpu.json"); + + if (virTestRun("QEMU vhost-user precedence test", testVUPrecedence, NULL) < 0) + ret = -1; + + virFileWrapperClearPrefixes(); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + + +VIR_TEST_MAIN(mymain) -- 2.21.0

On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Add qemuVhostUserFetchConfigs() to discover vhost-user helpers.
qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ tests/Makefile.am | 9 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ 13 files changed, 609 insertions(+) create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4c57f0995f..2f7077ddc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -96,6 +96,7 @@ virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) VIR_FREE(info->loadparm); info->isolationGroup = 0; info->isolationGroupLocked = false; + VIR_FREE(info->vhost_user_binary); }
void diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d0854925e3..0b0c525ad8 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -179,6 +179,7 @@ struct _virDomainDeviceInfo { * cases we might want to prevent that from happening by * locking the isolation group */ bool isolationGroupLocked; + char *vhost_user_binary; };
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index f7a0fa4a84..18a9220d01 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -60,6 +60,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_qapi.h \ qemu/qemu_tpm.c \ qemu/qemu_tpm.h \ + qemu/qemu_vhost_user.c \ + qemu/qemu_vhost_user.h \ $(NULL)
diff --git a/src/qemu/qemu_vhost_user.c b/src/qemu/qemu_vhost_user.c new file mode 100644 index 0000000000..7a97052ab9 --- /dev/null +++ b/src/qemu/qemu_vhost_user.c @@ -0,0 +1,394 @@ +/* + * qemu_vhost_user.c: QEMU vhost-user + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_vhost_user.h" +#include "qemu_configs.h" +#include "virjson.h" +#include "virlog.h" +#include "virstring.h" +#include "viralloc.h" +#include "virenum.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_vhost_user"); + +typedef enum { + QEMU_VHOST_USER_TYPE_NONE = 0, + QEMU_VHOST_USER_TYPE_9P, + QEMU_VHOST_USER_TYPE_BALLOON, + QEMU_VHOST_USER_TYPE_BLOCK, + QEMU_VHOST_USER_TYPE_CAIF, + QEMU_VHOST_USER_TYPE_CONSOLE, + QEMU_VHOST_USER_TYPE_CRYPTO, + QEMU_VHOST_USER_TYPE_GPU, + QEMU_VHOST_USER_TYPE_INPUT, + QEMU_VHOST_USER_TYPE_NET, + QEMU_VHOST_USER_TYPE_RNG, + QEMU_VHOST_USER_TYPE_RPMSG, + QEMU_VHOST_USER_TYPE_RPROC_SERIAL, + QEMU_VHOST_USER_TYPE_SCSI, + QEMU_VHOST_USER_TYPE_VSOCK, + + QEMU_VHOST_USER_TYPE_LAST +} qemuVhostUserType; + +VIR_ENUM_DECL(qemuVhostUserType); +VIR_ENUM_IMPL(qemuVhostUserType, + QEMU_VHOST_USER_TYPE_LAST, + "", + "9p", + "balloon", + "block", + "caif", + "console", + "crypto", + "gpu", + "input", + "net", + "rng", + "rpmsg", + "rproc-serial", + "scsi", + "vsock", +); + +typedef enum { + QEMU_VHOST_USER_GPU_FEATURE_NONE = 0, + QEMU_VHOST_USER_GPU_FEATURE_VIRGL, + QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE, + + QEMU_VHOST_USER_GPU_FEATURE_LAST +} qemuVhostUserGPUFeature; + +VIR_ENUM_DECL(qemuVhostUserGPUFeature); +VIR_ENUM_IMPL(qemuVhostUserGPUFeature, + QEMU_VHOST_USER_GPU_FEATURE_LAST, + "", + "virgl", + "render-node", +); + +typedef struct _qemuVhostUserGPU qemuVhostUserGPU; +typedef qemuVhostUserGPU *qemuVhostUserGPUPtr; +struct _qemuVhostUserGPU { + size_t nfeatures; + qemuVhostUserGPUFeature *features; +}; + +struct _qemuVhostUser { + /* Description intentionally not parsed. */ + qemuVhostUserType type; + char *binary; + /* Tags intentionally not parsed. */ + + union { + qemuVhostUserGPU gpu; + } capabilities; +}; + +static void +qemuVhostUserGPUFeatureFree(qemuVhostUserGPUFeature *features) +{ + VIR_FREE(features); +} + +
Inconsistent double newline spacing here. But double newline seems to be more common for new code so I suggest standardizing on that.
+VIR_DEFINE_AUTOPTR_FUNC(qemuVhostUserGPUFeature, qemuVhostUserGPUFeatureFree); + +void +qemuVhostUserFree(qemuVhostUserPtr vu) +{ + if (!vu) + return; + + if (vu->type == QEMU_VHOST_USER_TYPE_GPU) + VIR_FREE(vu->capabilities.gpu.features); + + VIR_FREE(vu->binary); + + VIR_FREE(vu); +} + +/* 1MiB should be enough for everybody (TM) */ +#define DOCUMENT_SIZE (1024 * 1024) +
Since this is identical to qemu_firmware.c, maybe give it a proper name and move it to the shared file? Otherwise this and the preceding uncommented patches look okay to me, the behavior here largely mirrors qemu_firmware.c - Cole

Hi On Tue, Aug 27, 2019 at 12:30 AM Cole Robinson <crobinso@redhat.com> wrote:
On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Add qemuVhostUserFetchConfigs() to discover vhost-user helpers.
qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ tests/Makefile.am | 9 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ 13 files changed, 609 insertions(+) create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4c57f0995f..2f7077ddc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -96,6 +96,7 @@ virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) VIR_FREE(info->loadparm); info->isolationGroup = 0; info->isolationGroupLocked = false; + VIR_FREE(info->vhost_user_binary); }
void diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d0854925e3..0b0c525ad8 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -179,6 +179,7 @@ struct _virDomainDeviceInfo { * cases we might want to prevent that from happening by * locking the isolation group */ bool isolationGroupLocked; + char *vhost_user_binary; };
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index f7a0fa4a84..18a9220d01 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -60,6 +60,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_qapi.h \ qemu/qemu_tpm.c \ qemu/qemu_tpm.h \ + qemu/qemu_vhost_user.c \ + qemu/qemu_vhost_user.h \ $(NULL)
diff --git a/src/qemu/qemu_vhost_user.c b/src/qemu/qemu_vhost_user.c new file mode 100644 index 0000000000..7a97052ab9 --- /dev/null +++ b/src/qemu/qemu_vhost_user.c @@ -0,0 +1,394 @@ +/* + * qemu_vhost_user.c: QEMU vhost-user + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_vhost_user.h" +#include "qemu_configs.h" +#include "virjson.h" +#include "virlog.h" +#include "virstring.h" +#include "viralloc.h" +#include "virenum.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_vhost_user"); + +typedef enum { + QEMU_VHOST_USER_TYPE_NONE = 0, + QEMU_VHOST_USER_TYPE_9P, + QEMU_VHOST_USER_TYPE_BALLOON, + QEMU_VHOST_USER_TYPE_BLOCK, + QEMU_VHOST_USER_TYPE_CAIF, + QEMU_VHOST_USER_TYPE_CONSOLE, + QEMU_VHOST_USER_TYPE_CRYPTO, + QEMU_VHOST_USER_TYPE_GPU, + QEMU_VHOST_USER_TYPE_INPUT, + QEMU_VHOST_USER_TYPE_NET, + QEMU_VHOST_USER_TYPE_RNG, + QEMU_VHOST_USER_TYPE_RPMSG, + QEMU_VHOST_USER_TYPE_RPROC_SERIAL, + QEMU_VHOST_USER_TYPE_SCSI, + QEMU_VHOST_USER_TYPE_VSOCK, + + QEMU_VHOST_USER_TYPE_LAST +} qemuVhostUserType; + +VIR_ENUM_DECL(qemuVhostUserType); +VIR_ENUM_IMPL(qemuVhostUserType, + QEMU_VHOST_USER_TYPE_LAST, + "", + "9p", + "balloon", + "block", + "caif", + "console", + "crypto", + "gpu", + "input", + "net", + "rng", + "rpmsg", + "rproc-serial", + "scsi", + "vsock", +); + +typedef enum { + QEMU_VHOST_USER_GPU_FEATURE_NONE = 0, + QEMU_VHOST_USER_GPU_FEATURE_VIRGL, + QEMU_VHOST_USER_GPU_FEATURE_RENDER_NODE, + + QEMU_VHOST_USER_GPU_FEATURE_LAST +} qemuVhostUserGPUFeature; + +VIR_ENUM_DECL(qemuVhostUserGPUFeature); +VIR_ENUM_IMPL(qemuVhostUserGPUFeature, + QEMU_VHOST_USER_GPU_FEATURE_LAST, + "", + "virgl", + "render-node", +); + +typedef struct _qemuVhostUserGPU qemuVhostUserGPU; +typedef qemuVhostUserGPU *qemuVhostUserGPUPtr; +struct _qemuVhostUserGPU { + size_t nfeatures; + qemuVhostUserGPUFeature *features; +}; + +struct _qemuVhostUser { + /* Description intentionally not parsed. */ + qemuVhostUserType type; + char *binary; + /* Tags intentionally not parsed. */ + + union { + qemuVhostUserGPU gpu; + } capabilities; +}; + +static void +qemuVhostUserGPUFeatureFree(qemuVhostUserGPUFeature *features) +{ + VIR_FREE(features); +} + +
Inconsistent double newline spacing here. But double newline seems to be more common for new code so I suggest standardizing on that.
ok
+VIR_DEFINE_AUTOPTR_FUNC(qemuVhostUserGPUFeature, qemuVhostUserGPUFeatureFree); + +void +qemuVhostUserFree(qemuVhostUserPtr vu) +{ + if (!vu) + return; + + if (vu->type == QEMU_VHOST_USER_TYPE_GPU) + VIR_FREE(vu->capabilities.gpu.features); + + VIR_FREE(vu->binary); + + VIR_FREE(vu); +} + +/* 1MiB should be enough for everybody (TM) */ +#define DOCUMENT_SIZE (1024 * 1024) +
Since this is identical to qemu_firmware.c, maybe give it a proper name and move it to the shared file?
QEMU_INTEROP_DOCUMENT_SIZE ? (not sure it's really worth it, I am not changing it yet)
Otherwise this and the preceding uncommented patches look okay to me, the behavior here largely mirrors qemu_firmware.c
thanks
- Cole
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Marc-André Lureau

On Fri, Aug 23, 2019 at 12:21:53PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Add qemuVhostUserFetchConfigs() to discover vhost-user helpers.
qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary.
Looks good, but it seems like something we might want to start caching over time, especially if more than one helper per domain will be needed.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ tests/Makefile.am | 9 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ 13 files changed, 609 insertions(+) create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4c57f0995f..2f7077ddc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -96,6 +96,7 @@ virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) VIR_FREE(info->loadparm); info->isolationGroup = 0; info->isolationGroupLocked = false; + VIR_FREE(info->vhost_user_binary); }
void diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d0854925e3..0b0c525ad8 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -179,6 +179,7 @@ struct _virDomainDeviceInfo { * cases we might want to prevent that from happening by * locking the isolation group */ bool isolationGroupLocked; + char *vhost_user_binary; };
Not sure about the placement in DeviceInfo, looks more fit for 'driver' to me. Jano

Hi On Tue, Aug 27, 2019 at 12:29 PM Ján Tomko <jtomko@redhat.com> wrote:
On Fri, Aug 23, 2019 at 12:21:53PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Add qemuVhostUserFetchConfigs() to discover vhost-user helpers.
qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary.
Looks good, but it seems like something we might want to start caching over time, especially if more than one helper per domain will be needed.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ tests/Makefile.am | 9 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ 13 files changed, 609 insertions(+) create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4c57f0995f..2f7077ddc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -96,6 +96,7 @@ virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) VIR_FREE(info->loadparm); info->isolationGroup = 0; info->isolationGroupLocked = false; + VIR_FREE(info->vhost_user_binary); }
void diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d0854925e3..0b0c525ad8 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -179,6 +179,7 @@ struct _virDomainDeviceInfo { * cases we might want to prevent that from happening by * locking the isolation group */ bool isolationGroupLocked; + char *vhost_user_binary; };
Not sure about the placement in DeviceInfo, looks more fit for 'driver' to me.
That wouldn't follow firmware code, but other than that, driver doesn't really fit either since it's a per-domain/device value. -- Marc-André Lureau

On Fri, Aug 30, 2019 at 04:04:14PM +0400, Marc-André Lureau wrote:
Hi
On Tue, Aug 27, 2019 at 12:29 PM Ján Tomko <jtomko@redhat.com> wrote:
On Fri, Aug 23, 2019 at 12:21:53PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Add qemuVhostUserFetchConfigs() to discover vhost-user helpers.
qemuVhostUserFillDomainGPU() will find the first matching GPU helper with the required capabilities and set the associated vhost_user_binary.
Looks good, but it seems like something we might want to start caching over time, especially if more than one helper per domain will be needed.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.c | 1 + src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user.c | 394 ++++++++++++++++++ src/qemu/qemu_vhost_user.h | 48 +++ tests/Makefile.am | 9 + .../etc/qemu/vhost-user/40-gpu.json | 1 + .../etc/qemu/vhost-user/50-gpu.json | 0 .../qemu/vhost-user/test-vhost-user-gpu | 11 + .../usr/share/qemu/vhost-user/30-gpu.json | 1 + .../usr/share/qemu/vhost-user/50-gpu.json | 8 + .../usr/share/qemu/vhost-user/60-gpu.json | 1 + tests/qemuvhostusertest.c | 132 ++++++ 13 files changed, 609 insertions(+) create mode 100644 src/qemu/qemu_vhost_user.c create mode 100644 src/qemu/qemu_vhost_user.h create mode 120000 tests/qemuvhostuserdata/etc/qemu/vhost-user/40-gpu.json create mode 100644 tests/qemuvhostuserdata/etc/qemu/vhost-user/50-gpu.json create mode 100755 tests/qemuvhostuserdata/usr/libexec/qemu/vhost-user/test-vhost-user-gpu create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/30-gpu.json create mode 100644 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/50-gpu.json create mode 120000 tests/qemuvhostuserdata/usr/share/qemu/vhost-user/60-gpu.json create mode 100644 tests/qemuvhostusertest.c
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4c57f0995f..2f7077ddc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -96,6 +96,7 @@ virDomainDeviceInfoClear(virDomainDeviceInfoPtr info) VIR_FREE(info->loadparm); info->isolationGroup = 0; info->isolationGroupLocked = false; + VIR_FREE(info->vhost_user_binary); }
void diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d0854925e3..0b0c525ad8 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -179,6 +179,7 @@ struct _virDomainDeviceInfo { * cases we might want to prevent that from happening by * locking the isolation group */ bool isolationGroupLocked; + char *vhost_user_binary; };
Not sure about the placement in DeviceInfo, looks more fit for 'driver' to me.
That wouldn't follow firmware code, but other than that, driver doesn't really fit either since it's a per-domain/device value.
virDomainVideoDriverDefPtr driver; is the one I meant. Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> See function documentation. Used in a following patch. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_security.c | 47 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_security.h | 6 +++++ 2 files changed, 53 insertions(+) diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c index 3cd6d9bd3d..86b06594f6 100644 --- a/src/qemu/qemu_security.c +++ b/src/qemu/qemu_security.c @@ -433,6 +433,53 @@ qemuSecurityRestoreChardevLabel(virQEMUDriverPtr driver, } +/* + * qemuSecurityStartVhostUserGPU: + * + * @driver: the QEMU driver + * @vm: the domain object + * @cmd: the command to run + * @existstatus: pointer to int returning exit status of process + * @cmdret: pointer to int returning result of virCommandRun + * + * Start the vhost-user-gpu process with approriate labels. + * This function returns -1 on security setup error, 0 if all the + * setup was done properly. In case the virCommand failed to run + * 0 is returned but cmdret is set appropriately with the process + * exitstatus also set. + */ +int +qemuSecurityStartVhostUserGPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virCommandPtr cmd, + int *exitstatus, + int *cmdret) +{ + int ret = -1; + + if (virSecurityManagerSetChildProcessLabel(driver->securityManager, + vm->def, cmd) < 0) + goto cleanup; + + if (virSecurityManagerPreFork(driver->securityManager) < 0) + goto cleanup; + + ret = 0; + + *cmdret = virCommandRun(cmd, exitstatus); + + virSecurityManagerPostFork(driver->securityManager); + + if (*cmdret < 0) + goto cleanup; + + return 0; + + cleanup: + return ret; +} + + /* * qemuSecurityStartTPMEmulator: * diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h index 68e377f418..a48ed8ec78 100644 --- a/src/qemu/qemu_security.h +++ b/src/qemu/qemu_security.h @@ -77,6 +77,12 @@ int qemuSecurityRestoreChardevLabel(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainChrDefPtr chr); +int qemuSecurityStartVhostUserGPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virCommandPtr cmd, + int *exitstatus, + int *cmdret); + int qemuSecurityStartTPMEmulator(virQEMUDriverPtr driver, virDomainObjPtr vm, virCommandPtr cmd, -- 2.21.0

On Fri, Aug 23, 2019 at 12:21:54PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
See function documentation. Used in a following patch.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_security.c | 47 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_security.h | 6 +++++ 2 files changed, 53 insertions(+)
diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c index 3cd6d9bd3d..86b06594f6 100644 --- a/src/qemu/qemu_security.c +++ b/src/qemu/qemu_security.c @@ -433,6 +433,53 @@ qemuSecurityRestoreChardevLabel(virQEMUDriverPtr driver, }
+/* + * qemuSecurityStartVhostUserGPU: + * + * @driver: the QEMU driver + * @vm: the domain object + * @cmd: the command to run + * @existstatus: pointer to int returning exit status of process + * @cmdret: pointer to int returning result of virCommandRun + * + * Start the vhost-user-gpu process with approriate labels. + * This function returns -1 on security setup error, 0 if all the + * setup was done properly. In case the virCommand failed to run + * 0 is returned but cmdret is set appropriately with the process + * exitstatus also set. + */ +int +qemuSecurityStartVhostUserGPU(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virCommandPtr cmd, + int *exitstatus, + int *cmdret) +{ + int ret = -1; + + if (virSecurityManagerSetChildProcessLabel(driver->securityManager, + vm->def, cmd) < 0) + goto cleanup; + + if (virSecurityManagerPreFork(driver->securityManager) < 0) + goto cleanup; + + ret = 0; + + *cmdret = virCommandRun(cmd, exitstatus); + + virSecurityManagerPostFork(driver->securityManager); + + if (*cmdret < 0) + goto cleanup; + + return 0; + + cleanup: + return ret;
The cleanup section is pointless here. Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> Similar to the qemu_tpm.c, add a unit with a few functions to start/stop and setup the cgroup of the external vhost-user-gpu process. See function documentation. Since the vhost-user connection fd isn't necessarily specific to QEMU, it was easier to add it to virDomainDeviceInfo, although a reasonable place could be qemuDomainObjPrivate (with an associate hashtable device-info -> qemu-device-info for example). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user_gpu.c | 305 +++++++++++++++++++++++++++++++++ src/qemu/qemu_vhost_user_gpu.h | 50 ++++++ 4 files changed, 358 insertions(+) create mode 100644 src/qemu/qemu_vhost_user_gpu.c create mode 100644 src/qemu/qemu_vhost_user_gpu.h diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 0b0c525ad8..23cc2e9ba6 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -180,6 +180,7 @@ struct _virDomainDeviceInfo { * locking the isolation group */ bool isolationGroupLocked; char *vhost_user_binary; + int vhost_user_fd; }; void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 18a9220d01..d394eab957 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -62,6 +62,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_tpm.h \ qemu/qemu_vhost_user.c \ qemu/qemu_vhost_user.h \ + qemu/qemu_vhost_user_gpu.c \ + qemu/qemu_vhost_user_gpu.h \ $(NULL) diff --git a/src/qemu/qemu_vhost_user_gpu.c b/src/qemu/qemu_vhost_user_gpu.c new file mode 100644 index 0000000000..0735af1473 --- /dev/null +++ b/src/qemu/qemu_vhost_user_gpu.c @@ -0,0 +1,305 @@ +/* + * qemu_vhost_user_gpu.c: QEMU vhost-user GPU support + * + * Copyright (C) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_vhost_user_gpu.h" +#include "qemu_vhost_user.h" +#include "qemu_extdevice.h" + +#include "conf/domain_conf.h" +#include "configmake.h" +#include "vircommand.h" +#include "viralloc.h" +#include "virlog.h" +#include "virutil.h" +#include "virfile.h" +#include "virstring.h" +#include "virtime.h" +#include "virpidfile.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("qemu.vhost-user-gpu"); + + +static char * +qemuVhostUserGPUCreatePidFilename(const char *stateDir, + const char *shortName, + const char *alias) +{ + char *pidfile = NULL; + char *devicename = NULL; + + if (virAsprintf(&devicename, "%s-%s-vhost-user-gpu", shortName, alias) < 0) + return NULL; + + pidfile = virPidFileBuildPath(stateDir, devicename); + + VIR_FREE(devicename); + + return pidfile; +} + + +/* + * qemuVhostUserGPUGetPid: + * @binpath: path of executable associated with the pidfile + * @stateDir: the directory where vhost-user-gpu writes the pidfile into + * @shortName: short name of the domain + * @alias: video device alias + * @pid: pointer to pid + * + * Return -errno upon error, or zero on successful reading of the pidfile. + * If the PID was not still alive, zero will be returned, and @pid will be + * set to -1; + */ +static int +qemuVhostUserGPUGetPid(const char *binPath, + const char *stateDir, + const char *shortName, + const char *alias, + pid_t *pid) +{ + int ret; + char *pidfile = qemuVhostUserGPUCreatePidFilename(stateDir, shortName, alias); + if (!pidfile) + return -ENOMEM; + + ret = virPidFileReadPathIfAlive(pidfile, pid, binPath); + + VIR_FREE(pidfile); + + return ret; +} + + +int qemuExtVhostUserGPUPrepareDomain(virQEMUDriverPtr driver, + virDomainVideoDefPtr video) +{ + return qemuVhostUserFillDomainGPU(driver, video); +} + + +/* + * qemuExtVhostUserGPUStart: + * @driver: QEMU driver + * @vm: the VM domain + * @video: the video device + * @logCtxt: log context + * + * Start the external vhost-user-gpu process: + * - open a socketpair for vhost-user communication + * - have the command line built + * - start the external process and sync with it before QEMU start + */ +int qemuExtVhostUserGPUStart(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainVideoDefPtr video, + qemuDomainLogContextPtr logCtxt) +{ + int ret = -1; + virCommandPtr cmd = NULL; + int exitstatus = 0; + char *errbuf = NULL; + virQEMUDriverConfigPtr cfg; + char *pidfile = NULL, *shortName = virDomainDefGetShortName(vm->def); + virTimeBackOffVar timebackoff; + const unsigned long long timeout = 500 * 1000; /* ms */ + int cmdret = 0, rc; + int pair[2] = { -1, -1 }; + + pid_t pid; + + if (!shortName) + return -1; + + cfg = virQEMUDriverGetConfig(driver); + + /* stop any left-over for this VM */ + qemuExtVhostUserGPUStop(driver, vm, video); + + if (!(pidfile = qemuVhostUserGPUCreatePidFilename( + cfg->stateDir, shortName, video->info.alias))) + goto error; + + if (qemuSecuritySetSocketLabel(driver->securityManager, vm->def) < 0) + goto cleanup; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { + virReportSystemError(errno, "%s", _("failed to create socket")); + goto error; + } + + if (qemuSecurityClearSocketLabel(driver->securityManager, vm->def) < 0) + goto cleanup; + + cmd = virCommandNew(video->info.vhost_user_binary); + if (!cmd) + goto error; + + virCommandClearCaps(cmd); + virCommandSetPidFile(cmd, pidfile); + virCommandDaemonize(cmd); + + if (qemuExtDeviceLogCommand(logCtxt, cmd, "vhost-user-gpu") < 0) + goto error; + + virCommandAddArgFormat(cmd, "--fd=%d", pair[0]); + virCommandPassFD(cmd, pair[0], VIR_COMMAND_PASS_FD_CLOSE_PARENT); + pair[0] = -1; + + if (video->accel) { + if (video->accel->accel3d) + virCommandAddArg(cmd, "--virgl"); + + if (video->accel->rendernode) + virCommandAddArgFormat(cmd, "--render-node=%s", video->accel->rendernode); + } + if (qemuSecurityStartVhostUserGPU(driver, vm, cmd, + &exitstatus, &cmdret) < 0) + goto error; + + if (cmdret < 0 || exitstatus != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not start 'vhost-user-gpu'. exitstatus: %d, " + "error: %s"), exitstatus, errbuf); + goto cleanup; + } + + /* check that the helper has written its pid into the file */ + if (virTimeBackOffStart(&timebackoff, 1, timeout) < 0) + goto error; + while (virTimeBackOffWait(&timebackoff)) { + rc = qemuVhostUserGPUGetPid(video->info.vhost_user_binary, + cfg->stateDir, shortName, video->info.alias, &pid); + if (rc < 0) + continue; + if (rc == 0 && pid == (pid_t)-1) + goto error; + break; + } + + ret = 0; + video->info.vhost_user_fd = pair[1]; + pair[1] = -1; + + cleanup: + VIR_FORCE_CLOSE(pair[0]); + VIR_FORCE_CLOSE(pair[1]); + virObjectUnref(cfg); + VIR_FREE(pidfile); + virCommandFree(cmd); + + return ret; + + error: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("vhost-user-gpu failed to start")); + goto cleanup; +} + + +/* + * qemuExtVhostUserGPUStop: + * + * @driver: QEMU driver + * @vm: the VM domain + * @video: the video device + * + * Check if vhost-user process pidfile is around, kill the process, + * and remove the pidfile. + */ +void qemuExtVhostUserGPUStop(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainVideoDefPtr video) +{ + virErrorPtr orig_err; + char *pidfile, *shortName = virDomainDefGetShortName(vm->def); + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + + if (!(pidfile = qemuVhostUserGPUCreatePidFilename( + cfg->stateDir, shortName, video->info.alias))) { + VIR_WARN("Unable to construct vhost-user-gpu pidfile path"); + return; + } + + virErrorPreserveLast(&orig_err); + if (virPidFileForceCleanupPath(pidfile) < 0) { + VIR_WARN("Unable to kill vhost-user-gpu process"); + } else { + if (unlink(pidfile) < 0 && + errno != ENOENT) { + virReportSystemError(errno, + _("Unable to remove stale pidfile %s"), + pidfile); + } + } + virErrorRestore(&orig_err); + + VIR_FREE(pidfile); +} + + +/* + * qemuExtVhostUserGPUSetupCgroup: + * + * @driver: QEMU driver + * @def: domain definition + * @video: the video device + * @cgroupe: a cgroup + * + * Add the vhost-user-gpu PID to the given cgroup. + */ +int +qemuExtVhostUserGPUSetupCgroup(virQEMUDriverPtr driver, + virDomainDefPtr def, + virDomainVideoDefPtr video, + virCgroupPtr cgroup) +{ + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + char *pidfile = NULL; + char *shortName = NULL; + int ret = -1, rc; + pid_t pid; + + shortName = virDomainDefGetShortName(def); + if (!shortName) + goto cleanup; + + rc = qemuVhostUserGPUGetPid(video->info.vhost_user_binary, + cfg->stateDir, shortName, video->info.alias, &pid); + if (rc < 0 || (rc == 0 && pid == (pid_t)-1)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get process id of vhost-user-gpu")); + goto cleanup; + } + if (virCgroupAddProcess(cgroup, pid) < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(pidfile); + VIR_FREE(shortName); + virObjectUnref(cfg); + + return ret; +} diff --git a/src/qemu/qemu_vhost_user_gpu.h b/src/qemu/qemu_vhost_user_gpu.h new file mode 100644 index 0000000000..85054894fd --- /dev/null +++ b/src/qemu/qemu_vhost_user_gpu.h @@ -0,0 +1,50 @@ +/* + * qemu_vhost_user_gpu.h: QEMU vhost-user GPU support + * + * Copyright (C) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "domain_conf.h" +#include "qemu_domain.h" +#include "qemu_security.h" + +int qemuExtVhostUserGPUPrepareDomain(virQEMUDriverPtr driver, + virDomainVideoDefPtr video) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) + ATTRIBUTE_RETURN_CHECK; + +int qemuExtVhostUserGPUStart(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainVideoDefPtr video, + qemuDomainLogContextPtr logCtxt) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_RETURN_CHECK; + +void qemuExtVhostUserGPUStop(virQEMUDriverPtr driver, + virDomainObjPtr def, + virDomainVideoDefPtr video) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int +qemuExtVhostUserGPUSetupCgroup(virQEMUDriverPtr driver, + virDomainDefPtr def, + virDomainVideoDefPtr video, + virCgroupPtr cgroup) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_RETURN_CHECK; -- 2.21.0

On 8/23/19 12:21 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Similar to the qemu_tpm.c, add a unit with a few functions to start/stop and setup the cgroup of the external vhost-user-gpu process. See function documentation.
Since the vhost-user connection fd isn't necessarily specific to QEMU, it was easier to add it to virDomainDeviceInfo, although a reasonable place could be qemuDomainObjPrivate (with an associate hashtable device-info -> qemu-device-info for example).
Yeah stuffing those two fields in DeviceInfo is no good IMO but your idea sounds good to me. I think you can hash on info->alias which should be assigned at this point and will be unique for every device.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user_gpu.c | 305 +++++++++++++++++++++++++++++++++ src/qemu/qemu_vhost_user_gpu.h | 50 ++++++ 4 files changed, 358 insertions(+) create mode 100644 src/qemu/qemu_vhost_user_gpu.c create mode 100644 src/qemu/qemu_vhost_user_gpu.h
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 0b0c525ad8..23cc2e9ba6 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -180,6 +180,7 @@ struct _virDomainDeviceInfo { * locking the isolation group */ bool isolationGroupLocked; char *vhost_user_binary; + int vhost_user_fd; };
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 18a9220d01..d394eab957 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -62,6 +62,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_tpm.h \ qemu/qemu_vhost_user.c \ qemu/qemu_vhost_user.h \ + qemu/qemu_vhost_user_gpu.c \ + qemu/qemu_vhost_user_gpu.h \ $(NULL)
diff --git a/src/qemu/qemu_vhost_user_gpu.c b/src/qemu/qemu_vhost_user_gpu.c new file mode 100644 index 0000000000..0735af1473 --- /dev/null +++ b/src/qemu/qemu_vhost_user_gpu.c @@ -0,0 +1,305 @@ +/* + * qemu_vhost_user_gpu.c: QEMU vhost-user GPU support + * + * Copyright (C) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_vhost_user_gpu.h" +#include "qemu_vhost_user.h" +#include "qemu_extdevice.h" + +#include "conf/domain_conf.h" +#include "configmake.h" +#include "vircommand.h" +#include "viralloc.h" +#include "virlog.h" +#include "virutil.h" +#include "virfile.h" +#include "virstring.h" +#include "virtime.h" +#include "virpidfile.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("qemu.vhost-user-gpu"); +
For consistency, these should be underscores: qemu.vhost_user_gpu The code looks like a mix of qemu_tpm and scsi prmanager handling from qemu_process.c. There's definitely opportunities for code reuse but that can come after this series IMO rather than requiring it up front and slowing things down further. However you can convert a few things here to VIR_AUTOFREE and VIR_AUTOUNREF fairly easily. This and the tpm code use virCgroupAddProcess but the prmanager code uses virCgroupAddMachineProcess ... I don't really understand the distinction, they seem to be similar usecases, a helper process per VM. Something to explore maybe Giving some the public functions here an Ext prefix seems weird since that's not present in the filename at all. I realize that's what the TPM code does but I don't really get it there either Otherwise this seems to be following established patterns so no major comments from me - Cole

On Fri, Aug 23, 2019 at 12:21:55PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Similar to the qemu_tpm.c, add a unit with a few functions to start/stop and setup the cgroup of the external vhost-user-gpu process. See function documentation.
Since the vhost-user connection fd isn't necessarily specific to QEMU, it was easier to add it to virDomainDeviceInfo, although a reasonable place could be qemuDomainObjPrivate (with an associate hashtable device-info -> qemu-device-info for example).
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/conf/device_conf.h | 1 + src/qemu/Makefile.inc.am | 2 + src/qemu/qemu_vhost_user_gpu.c | 305 +++++++++++++++++++++++++++++++++ src/qemu/qemu_vhost_user_gpu.h | 50 ++++++ 4 files changed, 358 insertions(+) create mode 100644 src/qemu/qemu_vhost_user_gpu.c create mode 100644 src/qemu/qemu_vhost_user_gpu.h
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 0b0c525ad8..23cc2e9ba6 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -180,6 +180,7 @@ struct _virDomainDeviceInfo { * locking the isolation group */ bool isolationGroupLocked; char *vhost_user_binary; + int vhost_user_fd; };
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info); diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am index 18a9220d01..d394eab957 100644 --- a/src/qemu/Makefile.inc.am +++ b/src/qemu/Makefile.inc.am @@ -62,6 +62,8 @@ QEMU_DRIVER_SOURCES = \ qemu/qemu_tpm.h \ qemu/qemu_vhost_user.c \ qemu/qemu_vhost_user.h \ + qemu/qemu_vhost_user_gpu.c \ + qemu/qemu_vhost_user_gpu.h \ $(NULL)
diff --git a/src/qemu/qemu_vhost_user_gpu.c b/src/qemu/qemu_vhost_user_gpu.c new file mode 100644 index 0000000000..0735af1473 --- /dev/null +++ b/src/qemu/qemu_vhost_user_gpu.c @@ -0,0 +1,305 @@ +/* + * qemu_vhost_user_gpu.c: QEMU vhost-user GPU support + * + * Copyright (C) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "qemu_vhost_user_gpu.h" +#include "qemu_vhost_user.h" +#include "qemu_extdevice.h" + +#include "conf/domain_conf.h" +#include "configmake.h" +#include "vircommand.h" +#include "viralloc.h" +#include "virlog.h" +#include "virutil.h" +#include "virfile.h" +#include "virstring.h" +#include "virtime.h" +#include "virpidfile.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("qemu.vhost-user-gpu"); + + +static char * +qemuVhostUserGPUCreatePidFilename(const char *stateDir, + const char *shortName, + const char *alias) +{ + char *pidfile = NULL; + char *devicename = NULL; + + if (virAsprintf(&devicename, "%s-%s-vhost-user-gpu", shortName, alias) < 0) + return NULL; + + pidfile = virPidFileBuildPath(stateDir, devicename); + + VIR_FREE(devicename); + + return pidfile; +} + + +/* + * qemuVhostUserGPUGetPid: + * @binpath: path of executable associated with the pidfile + * @stateDir: the directory where vhost-user-gpu writes the pidfile into + * @shortName: short name of the domain + * @alias: video device alias + * @pid: pointer to pid + * + * Return -errno upon error, or zero on successful reading of the pidfile. + * If the PID was not still alive, zero will be returned, and @pid will be + * set to -1; + */ +static int +qemuVhostUserGPUGetPid(const char *binPath, + const char *stateDir, + const char *shortName, + const char *alias, + pid_t *pid) +{ + int ret; + char *pidfile = qemuVhostUserGPUCreatePidFilename(stateDir, shortName, alias); + if (!pidfile) + return -ENOMEM; + + ret = virPidFileReadPathIfAlive(pidfile, pid, binPath); + + VIR_FREE(pidfile); + + return ret; +} + + +int qemuExtVhostUserGPUPrepareDomain(virQEMUDriverPtr driver, + virDomainVideoDefPtr video) +{ + return qemuVhostUserFillDomainGPU(driver, video); +} + + +/* + * qemuExtVhostUserGPUStart: + * @driver: QEMU driver + * @vm: the VM domain + * @video: the video device + * @logCtxt: log context + * + * Start the external vhost-user-gpu process: + * - open a socketpair for vhost-user communication + * - have the command line built + * - start the external process and sync with it before QEMU start + */ +int qemuExtVhostUserGPUStart(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainVideoDefPtr video, + qemuDomainLogContextPtr logCtxt) +{ + int ret = -1; + virCommandPtr cmd = NULL; + int exitstatus = 0; + char *errbuf = NULL; + virQEMUDriverConfigPtr cfg; + char *pidfile = NULL, *shortName = virDomainDefGetShortName(vm->def);
These should be on separate lines and shortName needs to be freed. Jano

From: Marc-André Lureau <marcandre.lureau@redhat.com> Call qemuExtVhostUserGPUPrepareDomain() to fill the domain with the location of the vhost-user binary to start. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_extdevice.c | 29 +++++++++++++++++++++++++++++ src/qemu/qemu_extdevice.h | 5 +++++ src/qemu/qemu_process.c | 4 ++++ 3 files changed, 38 insertions(+) diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c index dc032aa60c..5c55aba006 100644 --- a/src/qemu/qemu_extdevice.c +++ b/src/qemu/qemu_extdevice.c @@ -21,6 +21,7 @@ #include <config.h> #include "qemu_extdevice.h" +#include "qemu_vhost_user_gpu.h" #include "qemu_domain.h" #include "qemu_tpm.h" @@ -92,6 +93,34 @@ qemuExtDevicesInitPaths(virQEMUDriverPtr driver, } +/* + * qemuExtDevicesPrepareDomain: + * + * @driver: QEMU driver + * @vm: domain + * + * Code that modifies live XML of a domain which is about to start. + */ +int +qemuExtDevicesPrepareDomain(virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + int ret = 0; + size_t i; + + for (i = 0; i < vm->def->nvideos; i++) { + virDomainVideoDefPtr video = vm->def->videos[i]; + + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->vhostuser) { + if ((ret = qemuExtVhostUserGPUPrepareDomain(driver, video) < 0)) + break; + } + } + + return ret; +} + + /* * qemuExtDevicesPrepareHost: * diff --git a/src/qemu/qemu_extdevice.h b/src/qemu/qemu_extdevice.h index 039b3e60dd..2412244d60 100644 --- a/src/qemu/qemu_extdevice.h +++ b/src/qemu/qemu_extdevice.h @@ -29,6 +29,11 @@ int qemuExtDeviceLogCommand(qemuDomainLogContextPtr logCtxt, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; +int qemuExtDevicesPrepareDomain(virQEMUDriverPtr driver, + virDomainObjPtr vm) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) + ATTRIBUTE_RETURN_CHECK; + int qemuExtDevicesPrepareHost(virQEMUDriverPtr driver, virDomainDefPtr def) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index c439f17011..ed767b0807 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6358,6 +6358,10 @@ qemuProcessPrepareDomain(virQEMUDriverPtr driver, if (qemuFirmwareFillDomain(driver, vm, flags) < 0) goto cleanup; + VIR_DEBUG("Preparing external devices"); + if (qemuExtDevicesPrepareDomain(driver, vm) < 0) + goto cleanup; + for (i = 0; i < vm->def->nchannels; i++) { if (qemuDomainPrepareChannel(vm->def->channels[i], priv->channelTargetDir) < 0) -- 2.21.0

From: Marc-André Lureau <marcandre.lureau@redhat.com> Each vhost-user-gpu needs its own helper gpu process. Start/stop them, and apply the emulator cgroup controller. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_extdevice.c | 46 +++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c index 5c55aba006..3dbcec3546 100644 --- a/src/qemu/qemu_extdevice.c +++ b/src/qemu/qemu_extdevice.c @@ -161,10 +161,21 @@ qemuExtDevicesStart(virQEMUDriverPtr driver, bool incomingMigration) { int ret = 0; + size_t i; if (qemuExtDevicesInitPaths(driver, vm->def) < 0) return -1; + for (i = 0; i < vm->def->nvideos; i++) { + virDomainVideoDefPtr video = vm->def->videos[i]; + + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->vhostuser) { + ret = qemuExtVhostUserGPUStart(driver, vm, video, logCtxt); + if (ret < 0) + return ret; + } + } + if (vm->def->tpm) ret = qemuExtTPMStart(driver, vm, logCtxt, incomingMigration); @@ -176,9 +187,18 @@ void qemuExtDevicesStop(virQEMUDriverPtr driver, virDomainObjPtr vm) { + size_t i; + if (qemuExtDevicesInitPaths(driver, vm->def) < 0) return; + for (i = 0; i < vm->def->nvideos; i++) { + virDomainVideoDefPtr video = vm->def->videos[i]; + + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->vhostuser) + qemuExtVhostUserGPUStop(driver, vm, video); + } + if (vm->def->tpm) qemuExtTPMStop(driver, vm); } @@ -187,6 +207,14 @@ qemuExtDevicesStop(virQEMUDriverPtr driver, bool qemuExtDevicesHasDevice(virDomainDefPtr def) { + size_t i; + + for (i = 0; i < def->nvideos; i++) { + if (def->videos[i]->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && + def->videos[i]->vhostuser) + return true; + } + if (def->tpm && def->tpm->type == VIR_DOMAIN_TPM_TYPE_EMULATOR) return true; @@ -199,10 +227,20 @@ qemuExtDevicesSetupCgroup(virQEMUDriverPtr driver, virDomainDefPtr def, virCgroupPtr cgroup) { - int ret = 0; + size_t i; - if (def->tpm) - ret = qemuExtTPMSetupCgroup(driver, def, cgroup); + for (i = 0; i < def->nvideos; i++) { + virDomainVideoDefPtr video = def->videos[i]; - return ret; + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && + video->vhostuser && + qemuExtVhostUserGPUSetupCgroup(driver, def, video, cgroup) < 0) + return -1; + } + + if (def->tpm && + qemuExtTPMSetupCgroup(driver, def, cgroup) < 0) + return -1; + + return 0; } -- 2.21.0

From: Marc-André Lureau <marcandre.lureau@redhat.com> For each vhost-user GPUs, - build a socket chardev, and pass the vhost-user socket to it - build a vhost-user video device and associate it with the chardev Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_command.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8bef103f68..0e1d9510e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4672,8 +4672,15 @@ qemuBuildDeviceVideoStr(const virDomainDef *def, goto error; } - if (STREQ(model, "virtio-gpu")) { - if (qemuBuildVirtioDevStr(&buf, "virtio-gpu", qemuCaps, + if (video->vhostuser) { + if (STREQ(model, "virtio-vga")) + model = "vhost-user-vga"; + if (STREQ(model, "virtio-gpu")) + model = "vhost-user-gpu"; + } + + if (STREQ(model, "virtio-gpu") || STREQ(model, "vhost-user-gpu")) { + if (qemuBuildVirtioDevStr(&buf, model, qemuCaps, VIR_DOMAIN_DEVICE_VIDEO, video) < 0) { goto error; } @@ -4715,6 +4722,10 @@ qemuBuildDeviceVideoStr(const virDomainDef *def, if (video->heads) virBufferAsprintf(&buf, ",max_outputs=%u", video->heads); } + } else if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->vhostuser) { + if (video->heads) + virBufferAsprintf(&buf, ",max_outputs=%u", video->heads); + virBufferAsprintf(&buf, ",chardev=chr-vu-%s", video->info.alias); } else if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO) { if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_GPU_MAX_OUTPUTS)) { if (video->heads) @@ -4830,6 +4841,23 @@ qemuBuildVgaVideoCommand(virCommandPtr cmd, } +static char * +qemuBuildVhostUserChardevStr(const char *alias, + int *fd, + virCommandPtr cmd) +{ + char *chardev = NULL; + + if (virAsprintf(&chardev, "socket,id=chr-vu-%s,fd=%d", alias, *fd) < 0) + return NULL; + + virCommandPassFD(cmd, *fd, VIR_COMMAND_PASS_FD_CLOSE_PARENT); + *fd = -1; + + return chardev; +} + + static int qemuBuildVideoCommandLine(virCommandPtr cmd, const virDomainDef *def, @@ -4837,6 +4865,20 @@ qemuBuildVideoCommandLine(virCommandPtr cmd, { size_t i; + for (i = 0; i < def->nvideos; i++) { + VIR_AUTOFREE(char *) chardev = NULL; + virDomainVideoDefPtr video = def->videos[i]; + + if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO && video->vhostuser) { + if (!(chardev = qemuBuildVhostUserChardevStr(video->info.alias, + &video->info.vhost_user_fd, + cmd))) + return -1; + + virCommandAddArgList(cmd, "-chardev", chardev, NULL); + } + } + for (i = 0; i < def->nvideos; i++) { char *str = NULL; virDomainVideoDefPtr video = def->videos[i]; -- 2.21.0

On Fri, Aug 23, 2019 at 12:21:58PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
For each vhost-user GPUs, - build a socket chardev, and pass the vhost-user socket to it - build a vhost-user video device and associate it with the chardev
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_command.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8bef103f68..0e1d9510e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4672,8 +4672,15 @@ qemuBuildDeviceVideoStr(const virDomainDef *def, goto error; }
- if (STREQ(model, "virtio-gpu")) { - if (qemuBuildVirtioDevStr(&buf, "virtio-gpu", qemuCaps,
Eww, why do we do a string comparison here when we store the model as an enum?
+ if (video->vhostuser) { + if (STREQ(model, "virtio-vga")) + model = "vhost-user-vga"; + if (STREQ(model, "virtio-gpu")) + model = "vhost-user-gpu"; + }
Not sure why we need to reassign model here instead of getting it right the first time.
+
How different is the vhost-user-gpu device from virtio-gpu, don't we new a new VIDEO_TYPE_VHOST_USER instead? if (video->type == VIRTIO && !primary) for the condition below:
+ if (STREQ(model, "virtio-gpu") || STREQ(model, "vhost-user-gpu")) { + if (qemuBuildVirtioDevStr(&buf, model, qemuCaps, VIR_DOMAIN_DEVICE_VIDEO, video) < 0) { goto error; }
Jano

Hi On Tue, Aug 27, 2019 at 1:17 PM Ján Tomko <jtomko@redhat.com> wrote:
On Fri, Aug 23, 2019 at 12:21:58PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
For each vhost-user GPUs, - build a socket chardev, and pass the vhost-user socket to it - build a vhost-user video device and associate it with the chardev
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_command.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8bef103f68..0e1d9510e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4672,8 +4672,15 @@ qemuBuildDeviceVideoStr(const virDomainDef *def, goto error; }
- if (STREQ(model, "virtio-gpu")) { - if (qemuBuildVirtioDevStr(&buf, "virtio-gpu", qemuCaps,
Eww, why do we do a string comparison here when we store the model as an enum?
Yup, pre-existing. I suppose that can be fixed.
+ if (video->vhostuser) { + if (STREQ(model, "virtio-vga")) + model = "vhost-user-vga"; + if (STREQ(model, "virtio-gpu")) + model = "vhost-user-gpu"; + }
Not sure why we need to reassign model here instead of getting it right the first time.
+
How different is the vhost-user-gpu device from virtio-gpu, don't we new a new VIDEO_TYPE_VHOST_USER instead?
From guest PoV, it's actually the same device. So we shouldn't introduce a new virDomainVideoType, right? But we need a mapping to -device, it has to be in libvirt qemu driver.
if (video->type == VIRTIO && !primary) for the condition below:
+ if (STREQ(model, "virtio-gpu") || STREQ(model, "vhost-user-gpu")) { + if (qemuBuildVirtioDevStr(&buf, model, qemuCaps, VIR_DOMAIN_DEVICE_VIDEO, video) < 0) { goto error; }
Jano -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Marc-André Lureau

On 8/29/19 8:43 AM, Marc-André Lureau wrote:
Hi
On Tue, Aug 27, 2019 at 1:17 PM Ján Tomko <jtomko@redhat.com> wrote:
On Fri, Aug 23, 2019 at 12:21:58PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
For each vhost-user GPUs, - build a socket chardev, and pass the vhost-user socket to it - build a vhost-user video device and associate it with the chardev
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- src/qemu/qemu_command.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8bef103f68..0e1d9510e5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4672,8 +4672,15 @@ qemuBuildDeviceVideoStr(const virDomainDef *def, goto error; }
- if (STREQ(model, "virtio-gpu")) { - if (qemuBuildVirtioDevStr(&buf, "virtio-gpu", qemuCaps,
Eww, why do we do a string comparison here when we store the model as an enum?
Yup, pre-existing. I suppose that can be fixed.
virDomainVideoType only has VIRTIO and not virtio-gpu vs virtio-vga; that distinction depends on a few different criteria like arch and primary vs secondary. So video->type isn't a drop in replacement here
+ if (video->vhostuser) { + if (STREQ(model, "virtio-vga")) + model = "vhost-user-vga"; + if (STREQ(model, "virtio-gpu")) + model = "vhost-user-gpu"; + }
Not sure why we need to reassign model here instead of getting it right the first time.
+
How different is the vhost-user-gpu device from virtio-gpu, don't we new a new VIDEO_TYPE_VHOST_USER instead?
From guest PoV, it's actually the same device. So we shouldn't introduce a new virDomainVideoType, right? But we need a mapping to -device, it has to be in libvirt qemu driver.
I agree that existing model='virtio' should cover it - Cole

From: Marc-André Lureau <marcandre.lureau@redhat.com> Learn to override the paths to the program to execute (vhost-user helpers are executed to check for runtime capabilities). Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- tests/virfilewrapper.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/virfilewrapper.c b/tests/virfilewrapper.c index 160cd571e0..3d3f319f2c 100644 --- a/tests/virfilewrapper.c +++ b/tests/virfilewrapper.c @@ -44,6 +44,8 @@ static FILE *(*real_fopen)(const char *path, const char *mode); static int (*real_access)(const char *path, int mode); static int (*real_mkdir)(const char *path, mode_t mode); static DIR *(*real_opendir)(const char *path); +static int (*real_execv)(const char *path, char *const argv[]); +static int (*real_execve)(const char *path, char *const argv[], char *const envp[]); static void init_syms(void) { @@ -55,6 +57,8 @@ static void init_syms(void) VIR_MOCK_REAL_INIT(mkdir); VIR_MOCK_REAL_INIT(open); VIR_MOCK_REAL_INIT(opendir); + VIR_MOCK_REAL_INIT(execv); + VIR_MOCK_REAL_INIT(execve); } @@ -191,4 +195,22 @@ DIR *opendir(const char *path) return real_opendir(newpath ? newpath : path); } +int execv(const char *path, char *const argv[]) +{ + VIR_AUTOFREE(char *) newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + return real_execv(newpath ? newpath : path, argv); +} + +int execve(const char *path, char *const argv[], char *const envp[]) +{ + VIR_AUTOFREE(char *) newpath = NULL; + + PATH_OVERRIDE(newpath, path); + + return real_execve(newpath ? newpath : path, argv, envp); +} + #endif -- 2.21.0

From: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- .../vhost-user-gpu-secondary.args | 38 ++++++++++++++++ .../vhost-user-gpu-secondary.xml | 44 +++++++++++++++++++ tests/qemuxml2argvdata/vhost-user-vga.args | 35 +++++++++++++++ tests/qemuxml2argvdata/vhost-user-vga.xml | 41 +++++++++++++++++ tests/qemuxml2argvtest.c | 21 +++++++++ 5 files changed, 179 insertions(+) create mode 100644 tests/qemuxml2argvdata/vhost-user-gpu-secondary.args create mode 100644 tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml create mode 100644 tests/qemuxml2argvdata/vhost-user-vga.args create mode 100644 tests/qemuxml2argvdata/vhost-user-vga.xml diff --git a/tests/qemuxml2argvdata/vhost-user-gpu-secondary.args b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.args new file mode 100644 index 0000000000..5d41edad6b --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.args @@ -0,0 +1,38 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-object memory-backend-memfd,id=ram-node0,share=yes,size=224395264 \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ +-chardev socket,id=chr-vu-video0,fd=0 \ +-chardev socket,id=chr-vu-video1,fd=0 \ +-device vhost-user-vga,id=video0,max_outputs=1,chardev=chr-vu-video0,bus=pci.0,\ +addr=0x2 \ +-device vhost-user-gpu-pci,id=video1,max_outputs=1,chardev=chr-vu-video1,\ +bus=pci.0,addr=0x4 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml new file mode 100644 index 0000000000..2142497d6e --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml @@ -0,0 +1,44 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <memoryBacking> + <access mode='shared'/> + <source type='memfd'/> + </memoryBacking> + <vcpu placement='static'>1</vcpu> + <cpu> + <numa> + <cell id='0' cpus='0' memory='219136' unit='KiB'/> + </numa> + </cpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i686</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + <video> + <model type='virtio' heads='1' vhostuser='yes'/> + </video> + <video> + <model type='virtio' heads='1' vhostuser='yes'/> + </video> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/vhost-user-vga.args b/tests/qemuxml2argvdata/vhost-user-vga.args new file mode 100644 index 0000000000..ce690e4f21 --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-vga.args @@ -0,0 +1,35 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-object memory-backend-memfd,id=ram-node0,share=yes,size=224395264 \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ +-chardev socket,id=chr-vu-video0,fd=0 \ +-device vhost-user-vga,id=video0,max_outputs=1,chardev=chr-vu-video0,bus=pci.0,\ +addr=0x2 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/vhost-user-vga.xml b/tests/qemuxml2argvdata/vhost-user-vga.xml new file mode 100644 index 0000000000..81b1e7643e --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-vga.xml @@ -0,0 +1,41 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <memoryBacking> + <access mode='shared'/> + <source type='memfd'/> + </memoryBacking> + <vcpu placement='static'>1</vcpu> + <cpu> + <numa> + <cell id='0' cpus='0' memory='219136' unit='KiB'/> + </numa> + </cpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i686</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + <video> + <model type='virtio' heads='1' vhostuser='yes'/> + </video> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 1799eb3387..b4d705f721 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -674,6 +674,15 @@ mymain(void) virFileWrapperAddPrefix("/home/user/.config/qemu/firmware", abs_srcdir "/qemufirmwaredata/home/user/.config/qemu/firmware"); + virFileWrapperAddPrefix(SYSCONFDIR "/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/etc/qemu/vhost-user"); + virFileWrapperAddPrefix(PREFIX "/share/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/usr/share/qemu/vhost-user"); + virFileWrapperAddPrefix("/home/user/.config/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/home/user/.config/qemu/vhost-user"); + virFileWrapperAddPrefix("/usr/libexec/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/usr/libexec/qemu/vhost-user"); + /** * The following set of macros allows testing of XML -> argv conversion with a * real set of capabilities gathered from a real qemu copy. It is desired to use @@ -2981,6 +2990,18 @@ mymain(void) DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); DO_TEST_CAPS_ARCH_LATEST("aarch64-os-firmware-efi", "aarch64"); + DO_TEST("vhost-user-vga", + QEMU_CAPS_OBJECT_MEMORY_MEMFD, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY, + QEMU_CAPS_DEVICE_VHOST_USER_GPU, + QEMU_CAPS_DEVICE_VHOST_USER_VGA); + + DO_TEST("vhost-user-gpu-secondary", + QEMU_CAPS_OBJECT_MEMORY_MEMFD, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY, + QEMU_CAPS_DEVICE_VHOST_USER_GPU, + QEMU_CAPS_DEVICE_VHOST_USER_VGA); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.21.0

On 8/23/19 12:22 PM, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com>
There should be testing of the rendernode XML as well somewhere Thanks, Cole

On Fri, Aug 23, 2019 at 12:22:00PM -0400, Cole Robinson wrote:
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Cole Robinson <crobinso@redhat.com> --- .../vhost-user-gpu-secondary.args | 38 ++++++++++++++++ .../vhost-user-gpu-secondary.xml | 44 +++++++++++++++++++ tests/qemuxml2argvdata/vhost-user-vga.args | 35 +++++++++++++++ tests/qemuxml2argvdata/vhost-user-vga.xml | 41 +++++++++++++++++ tests/qemuxml2argvtest.c | 21 +++++++++ 5 files changed, 179 insertions(+) create mode 100644 tests/qemuxml2argvdata/vhost-user-gpu-secondary.args create mode 100644 tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml create mode 100644 tests/qemuxml2argvdata/vhost-user-vga.args create mode 100644 tests/qemuxml2argvdata/vhost-user-vga.xml
diff --git a/tests/qemuxml2argvdata/vhost-user-gpu-secondary.args b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.args new file mode 100644 index 0000000000..5d41edad6b --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.args @@ -0,0 +1,38 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-object memory-backend-memfd,id=ram-node0,share=yes,size=224395264 \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ +-chardev socket,id=chr-vu-video0,fd=0 \ +-chardev socket,id=chr-vu-video1,fd=0 \ +-device vhost-user-vga,id=video0,max_outputs=1,chardev=chr-vu-video0,bus=pci.0,\ +addr=0x2 \ +-device vhost-user-gpu-pci,id=video1,max_outputs=1,chardev=chr-vu-video1,\ +bus=pci.0,addr=0x4 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml new file mode 100644 index 0000000000..2142497d6e --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-gpu-secondary.xml @@ -0,0 +1,44 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <memoryBacking> + <access mode='shared'/> + <source type='memfd'/> + </memoryBacking> + <vcpu placement='static'>1</vcpu> + <cpu> + <numa> + <cell id='0' cpus='0' memory='219136' unit='KiB'/> + </numa> + </cpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i686</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + <video> + <model type='virtio' heads='1' vhostuser='yes'/> + </video> + <video> + <model type='virtio' heads='1' vhostuser='yes'/> + </video> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/vhost-user-vga.args b/tests/qemuxml2argvdata/vhost-user-vga.args new file mode 100644 index 0000000000..ce690e4f21 --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-vga.args @@ -0,0 +1,35 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-object memory-backend-memfd,id=ram-node0,share=yes,size=224395264 \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ +-chardev socket,id=chr-vu-video0,fd=0 \ +-device vhost-user-vga,id=video0,max_outputs=1,chardev=chr-vu-video0,bus=pci.0,\ +addr=0x2 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/vhost-user-vga.xml b/tests/qemuxml2argvdata/vhost-user-vga.xml new file mode 100644 index 0000000000..81b1e7643e --- /dev/null +++ b/tests/qemuxml2argvdata/vhost-user-vga.xml @@ -0,0 +1,41 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <memoryBacking> + <access mode='shared'/> + <source type='memfd'/> + </memoryBacking> + <vcpu placement='static'>1</vcpu> + <cpu> + <numa> + <cell id='0' cpus='0' memory='219136' unit='KiB'/> + </numa> + </cpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i686</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + <video> + <model type='virtio' heads='1' vhostuser='yes'/> + </video> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 1799eb3387..b4d705f721 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -674,6 +674,15 @@ mymain(void) virFileWrapperAddPrefix("/home/user/.config/qemu/firmware", abs_srcdir "/qemufirmwaredata/home/user/.config/qemu/firmware");
+ virFileWrapperAddPrefix(SYSCONFDIR "/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/etc/qemu/vhost-user"); + virFileWrapperAddPrefix(PREFIX "/share/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/usr/share/qemu/vhost-user"); + virFileWrapperAddPrefix("/home/user/.config/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/home/user/.config/qemu/vhost-user"); + virFileWrapperAddPrefix("/usr/libexec/qemu/vhost-user", + abs_srcdir "/qemuvhostuserdata/usr/libexec/qemu/vhost-user"); + /** * The following set of macros allows testing of XML -> argv conversion with a * real set of capabilities gathered from a real qemu copy. It is desired to use @@ -2981,6 +2990,18 @@ mymain(void) DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); DO_TEST_CAPS_ARCH_LATEST("aarch64-os-firmware-efi", "aarch64");
+ DO_TEST("vhost-user-vga", + QEMU_CAPS_OBJECT_MEMORY_MEMFD, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY, + QEMU_CAPS_DEVICE_VHOST_USER_GPU, + QEMU_CAPS_DEVICE_VHOST_USER_VGA); + + DO_TEST("vhost-user-gpu-secondary", + QEMU_CAPS_OBJECT_MEMORY_MEMFD, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY, + QEMU_CAPS_DEVICE_VHOST_USER_GPU, + QEMU_CAPS_DEVICE_VHOST_USER_VGA); +
use DO_TEST_CAPS_LATEST for new additions. We've actually had bug fixes with test cases that did not actually fix or test the correct bugs because the capabilities specified in DO_TEST did not match real QEMU binaries. Jano
if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir);
-- 2.21.0
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 8/23/19 12:21 PM, Cole Robinson wrote:
v1: https://www.redhat.com/archives/libvir-list/2019-June/msg00102.html
This is v2 of Marc-André's series with minor changes. I'm not taking over this series, I just fixed these as part of the patch rebase so I can review it :)
Changes since v1: - rebase to master - if test file build by dropping LDADDS usage - syntax-check issues: * use #pragma once * if () bracket issues * jump label indent issues * error message %s usage * size_t for loops
I didn't know much about vhost-user-gpu before this series, here's what I've learned.
vhost-user is a generic mechanism that allows implementing virtio device dataplane handling in a separate userspace process. vhost-user-gpu here notably moves the virgl 3d handling out of the main qemu process. The external process will be /usr/libexec/vhost-user-gpu, which comes from qemu.git contrib/vhost-user-gpu code, first released in qemu-4.1.
Part of this series deals with discovering the location on disk of the vhost-user-gpu binary, and what capabilities it provides. This uses a similar mechanism to firmware.json, described in qemu docs/interop/vhost-user.json
https://github.com/qemu/qemu/blob/master/docs/interop/vhost-user.json
qemu 4.1 ships a 50-qemu-gpu.json to match. I believe virtio-fs will use a similar mechanism when it lands in upstream qemu, as virtiofsd is a separate process that communicates with qemu over vhost-user.
For a bit more background on vhost-user-gpu process handling and the json interop motivation, here's some of the qemu discussion:
https://lists.nongnu.org/archive/html/qemu-devel/2018-08/msg02610.html https://lists.nongnu.org/archive/html/qemu-devel/2018-09/msg00807.html
For this series, the XML to enable this is:
<video model='virtio' vhostuser='yes'> <acceleration accel3d='yes' rendernode='/path/to/rendernode'/> </video>
That's wrong, it's <video> <model type='virtio' vhostuser='yes'> <acceleration accel3d='yes' rendernode='/path/to/rendernode'/> </model> </video> - Cole
participants (3)
-
Cole Robinson
-
Ján Tomko
-
Marc-André Lureau