[PATCH] qemu: Move PostParse functions out of qemu_domain.c
by Michal Privoznik
Problem with qemu_domain.c is that it's constantly growing. But
there are few options for improvement. For instance, validation
functions were moved out and now live in qemu_validate.c. We can
do the same for PostParse functions, though since PostParse may
modify domain definition, some functions need to be exported from
qemu_domain.c.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
Best viewed via 'git show --color-moved'.
po/POTFILES | 1 +
src/qemu/meson.build | 1 +
src/qemu/qemu_domain.c | 1898 +-----------------------------------
src/qemu/qemu_domain.h | 16 +-
src/qemu/qemu_postparse.c | 1925 +++++++++++++++++++++++++++++++++++++
src/qemu/qemu_postparse.h | 54 ++
tests/qemublocktest.c | 1 +
7 files changed, 2001 insertions(+), 1895 deletions(-)
create mode 100644 src/qemu/qemu_postparse.c
create mode 100644 src/qemu/qemu_postparse.h
diff --git a/po/POTFILES b/po/POTFILES
index 1ed4086d2c..c20781e1a8 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -189,6 +189,7 @@ src/qemu/qemu_monitor_text.c
src/qemu/qemu_namespace.c
src/qemu/qemu_nbdkit.c
src/qemu/qemu_passt.c
+src/qemu/qemu_postparse.c
src/qemu/qemu_process.c
src/qemu/qemu_qapi.c
src/qemu/qemu_saveimage.c
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 1d904bbc68..2a85e2e604 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -32,6 +32,7 @@ qemu_driver_sources = [
'qemu_namespace.c',
'qemu_nbdkit.c',
'qemu_passt.c',
+ 'qemu_postparse.c',
'qemu_process.c',
'qemu_qapi.c',
'qemu_saveimage.c',
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 562fa76a78..c798ef37fd 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -27,7 +27,6 @@
#include "qemu_cgroup.h"
#include "qemu_command.h"
#include "qemu_capabilities.h"
-#include "qemu_firmware.h"
#include "qemu_hostdev.h"
#include "qemu_migration_params.h"
#include "qemu_security.h"
@@ -38,6 +37,7 @@
#include "qemu_checkpoint.h"
#include "qemu_validate.h"
#include "qemu_namespace.h"
+#include "qemu_postparse.h"
#include "viralloc.h"
#include "virlog.h"
#include "virerror.h"
@@ -71,8 +71,6 @@
#include <sys/time.h>
#include <fcntl.h>
-#define QEMU_QXL_VGAMEM_DEFAULT 16 * 1024
-
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_domain");
@@ -2020,7 +2018,7 @@ qemuDomainObjPrivateAlloc(void *opaque)
}
-static int
+int
qemuStorageSourcePrivateDataAssignSecinfo(qemuDomainSecretInfo **secinfo,
char **alias)
{
@@ -4001,26 +3999,6 @@ virXMLNamespace virQEMUDriverDomainXMLNamespace = {
};
-static int
-qemuDomainDefAddImplicitInputDevice(virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- if (virQEMUCapsSupportsI8042(qemuCaps, def) &&
- def->features[VIR_DOMAIN_FEATURE_PS2] != VIR_TRISTATE_SWITCH_OFF) {
- if (virDomainDefMaybeAddInput(def,
- VIR_DOMAIN_INPUT_TYPE_MOUSE,
- VIR_DOMAIN_INPUT_BUS_PS2) < 0)
- return -1;
-
- if (virDomainDefMaybeAddInput(def,
- VIR_DOMAIN_INPUT_TYPE_KBD,
- VIR_DOMAIN_INPUT_BUS_PS2) < 0)
- return -1;
- }
-
- return 0;
-}
-
static int
qemuDomainDefSuggestDefaultAudioBackend(virQEMUDriver *driver,
virDomainDef *def,
@@ -4168,7 +4146,7 @@ qemuDomainDefClearDefaultAudioBackend(virQEMUDriver *driver,
return 0;
}
-static int
+int
qemuDomainDefAddDefaultAudioBackend(virQEMUDriver *driver,
virDomainDef *def)
{
@@ -4227,7 +4205,7 @@ qemuDomainGetSCSIControllerModel(const virDomainDef *def,
}
-static virDomainPanicModel
+virDomainPanicModel
qemuDomainDefaultPanicModel(const virDomainDef *def)
{
if (qemuDomainIsPSeries(def))
@@ -4246,834 +4224,6 @@ qemuDomainDefaultPanicModel(const virDomainDef *def)
}
-static int
-qemuDomainDefAddDefaultDevices(virQEMUDriver *driver,
- virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- bool addDefaultUSB = false;
- int usbModel = -1; /* "default for machinetype" */
- int pciRoot; /* index within def->controllers */
- bool addImplicitSATA = false;
- bool addPCIRoot = false;
- bool addPCIeRoot = false;
- bool addDefaultMemballoon = false;
- bool addDefaultUSBKBD = false;
- bool addDefaultUSBMouse = false;
- bool addPanicDevice = false;
- bool addITCOWatchdog = false;
- bool addIOMMU = false;
-
- /* add implicit input devices */
- if (qemuDomainDefAddImplicitInputDevice(def, qemuCaps) < 0)
- return -1;
-
- /* Add implicit PCI root controller if the machine has one */
- switch (def->os.arch) {
- case VIR_ARCH_I686:
- case VIR_ARCH_X86_64:
- addDefaultMemballoon = true;
-
- if (STREQ(def->os.machine, "isapc")) {
- break;
- }
-
- addDefaultUSB = true;
-
- if (qemuDomainIsQ35(def)) {
- addPCIeRoot = true;
- addImplicitSATA = true;
- addITCOWatchdog = true;
-
- if (virDomainDefGetVcpusMax(def) > QEMU_MAX_VCPUS_WITHOUT_EIM) {
- addIOMMU = true;
- }
-
- /* Prefer adding a USB3 controller if supported, fall back
- * to USB2 if there is no USB3 available, and if that's
- * unavailable don't add anything.
- */
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI))
- usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
- else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI))
- usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI;
- else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_USB_EHCI1))
- usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1;
- else
- addDefaultUSB = false;
- break;
- }
- if (qemuDomainIsI440FX(def))
- addPCIRoot = true;
- break;
-
- case VIR_ARCH_ARMV6L:
- case VIR_ARCH_ARMV7L:
- case VIR_ARCH_ARMV7B:
- case VIR_ARCH_AARCH64:
- if (STREQ(def->os.machine, "versatilepb"))
- addPCIRoot = true;
-
- /* Add default USB for the two machine types which historically
- * supported -usb */
- if (STREQ(def->os.machine, "versatilepb") ||
- STRPREFIX(def->os.machine, "realview")) {
- addDefaultUSB = true;
- usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
- }
-
- if (qemuDomainIsARMVirt(def))
- addPCIeRoot = true;
-
- break;
-
- case VIR_ARCH_PPC64:
- case VIR_ARCH_PPC64LE:
- addPCIRoot = true;
- addDefaultUSB = true;
- addDefaultUSBKBD = true;
- addDefaultUSBMouse = true;
- addDefaultMemballoon = true;
- /* For pSeries guests, the firmware provides the same
- * functionality as the pvpanic device, so automatically
- * add the definition if not already present */
- if (qemuDomainIsPSeries(def))
- addPanicDevice = true;
- break;
-
- case VIR_ARCH_ALPHA:
- case VIR_ARCH_PPC:
- case VIR_ARCH_PPCEMB:
- case VIR_ARCH_SH4:
- case VIR_ARCH_SH4EB:
- addDefaultUSB = true;
- addDefaultMemballoon = true;
- addPCIRoot = true;
- break;
-
- case VIR_ARCH_RISCV32:
- case VIR_ARCH_RISCV64:
- addDefaultMemballoon = true;
- if (qemuDomainIsRISCVVirt(def))
- addPCIeRoot = true;
- break;
-
- case VIR_ARCH_S390:
- case VIR_ARCH_S390X:
- addDefaultMemballoon = true;
- addPanicDevice = true;
- addPCIRoot = virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ZPCI);
- break;
-
- case VIR_ARCH_SPARC64:
- addDefaultUSB = true;
- addDefaultMemballoon = true;
- addPCIRoot = true;
- break;
-
- case VIR_ARCH_MIPS:
- case VIR_ARCH_MIPSEL:
- case VIR_ARCH_MIPS64:
- case VIR_ARCH_MIPS64EL:
- addDefaultUSB = true;
- addDefaultMemballoon = true;
- if (qemuDomainIsMipsMalta(def))
- addPCIRoot = true;
- break;
-
- case VIR_ARCH_LOONGARCH64:
- addPCIeRoot = true;
- break;
-
- case VIR_ARCH_CRIS:
- case VIR_ARCH_ITANIUM:
- case VIR_ARCH_LM32:
- case VIR_ARCH_M68K:
- case VIR_ARCH_MICROBLAZE:
- case VIR_ARCH_MICROBLAZEEL:
- case VIR_ARCH_OR32:
- case VIR_ARCH_PARISC:
- case VIR_ARCH_PARISC64:
- case VIR_ARCH_PPCLE:
- case VIR_ARCH_SPARC:
- case VIR_ARCH_UNICORE32:
- case VIR_ARCH_XTENSA:
- case VIR_ARCH_XTENSAEB:
- case VIR_ARCH_NONE:
- case VIR_ARCH_LAST:
- default:
- break;
- }
-
- if (addDefaultUSB &&
- virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_USB, 0) < 0 &&
- virDomainDefAddUSBController(def, 0, usbModel) < 0)
- return -1;
-
- if (addImplicitSATA &&
- virDomainDefMaybeAddController(
- def, VIR_DOMAIN_CONTROLLER_TYPE_SATA, 0, -1) < 0)
- return -1;
-
- pciRoot = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0);
-
- /* NB: any machine that sets addPCIRoot to true must also return
- * true from the function qemuDomainSupportsPCI().
- */
- if (addPCIRoot) {
- if (pciRoot >= 0) {
- if (def->controllers[pciRoot]->model != VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) {
- virReportError(VIR_ERR_XML_ERROR,
- _("The PCI controller with index='0' must be model='pci-root' for this machine type, but model='%1$s' was found instead"),
- virDomainControllerModelPCITypeToString(def->controllers[pciRoot]->model));
- return -1;
- }
- } else if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
- VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)) {
- return -1;
- }
- }
-
- /* When a machine has a pcie-root, make sure that there is always
- * a dmi-to-pci-bridge controller added as bus 1, and a pci-bridge
- * as bus 2, so that standard PCI devices can be connected
- *
- * NB: any machine that sets addPCIeRoot to true must also return
- * true from the function qemuDomainSupportsPCI().
- */
- if (addPCIeRoot) {
- if (pciRoot >= 0) {
- if (def->controllers[pciRoot]->model != VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
- virReportError(VIR_ERR_XML_ERROR,
- _("The PCI controller with index='0' must be model='pcie-root' for this machine type, but model='%1$s' was found instead"),
- virDomainControllerModelPCITypeToString(def->controllers[pciRoot]->model));
- return -1;
- }
- } else if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
- VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)) {
- return -1;
- }
- }
-
- if (addDefaultMemballoon && !def->memballoon) {
- virDomainMemballoonDef *memballoon;
- memballoon = g_new0(virDomainMemballoonDef, 1);
-
- memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
- def->memballoon = memballoon;
- }
-
- if (addDefaultUSBMouse) {
- bool hasUSBTablet = false;
- size_t j;
-
- for (j = 0; j < def->ninputs; j++) {
- if (def->inputs[j]->type == VIR_DOMAIN_INPUT_TYPE_TABLET &&
- def->inputs[j]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
- hasUSBTablet = true;
- break;
- }
- }
-
- /* Historically, we have automatically added USB keyboard and
- * mouse to some guests. While the former device is generally
- * safe to have, adding the latter is undesiderable if a USB
- * tablet is already present in the guest */
- if (hasUSBTablet)
- addDefaultUSBMouse = false;
- }
-
- if (addDefaultUSBKBD &&
- def->ngraphics > 0 &&
- virDomainDefMaybeAddInput(def,
- VIR_DOMAIN_INPUT_TYPE_KBD,
- VIR_DOMAIN_INPUT_BUS_USB) < 0)
- return -1;
-
- if (addDefaultUSBMouse &&
- def->ngraphics > 0 &&
- virDomainDefMaybeAddInput(def,
- VIR_DOMAIN_INPUT_TYPE_MOUSE,
- VIR_DOMAIN_INPUT_BUS_USB) < 0)
- return -1;
-
- if (addPanicDevice) {
- virDomainPanicModel defaultModel = qemuDomainDefaultPanicModel(def);
- size_t j;
-
- for (j = 0; j < def->npanics; j++) {
- if (def->panics[j]->model == VIR_DOMAIN_PANIC_MODEL_DEFAULT ||
- def->panics[j]->model == defaultModel)
- break;
- }
-
- if (j == def->npanics) {
- virDomainPanicDef *panic = g_new0(virDomainPanicDef, 1);
-
- VIR_APPEND_ELEMENT_COPY(def->panics, def->npanics, panic);
- }
- }
-
- if (addITCOWatchdog) {
- size_t i = 0;
-
- for (i = 0; i < def->nwatchdogs; i++) {
- if (def->watchdogs[i]->model == VIR_DOMAIN_WATCHDOG_MODEL_ITCO)
- break;
- }
-
- if (i == def->nwatchdogs) {
- virDomainWatchdogDef *watchdog = g_new0(virDomainWatchdogDef, 1);
-
- watchdog->model = VIR_DOMAIN_WATCHDOG_MODEL_ITCO;
- if (def->nwatchdogs)
- watchdog->action = def->watchdogs[0]->action;
- else
- watchdog->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
-
- VIR_APPEND_ELEMENT(def->watchdogs, def->nwatchdogs, watchdog);
- }
- }
-
- if (addIOMMU && !def->iommu &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_INTEL_IOMMU) &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_INTREMAP) &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_EIM)) {
- g_autoptr(virDomainIOMMUDef) iommu = NULL;
-
- iommu = virDomainIOMMUDefNew();
- iommu->model = VIR_DOMAIN_IOMMU_MODEL_INTEL;
- /* eim requires intremap. */
- iommu->intremap = VIR_TRISTATE_SWITCH_ON;
- iommu->eim = VIR_TRISTATE_SWITCH_ON;
-
- def->iommu = g_steal_pointer(&iommu);
- }
-
- if (qemuDomainDefAddDefaultAudioBackend(driver, def) < 0)
- return -1;
-
- return 0;
-}
-
-
-/**
- * qemuDomainDefEnableDefaultFeatures:
- * @def: domain definition
- * @qemuCaps: QEMU capabilities
- *
- * Make sure that features that should be enabled by default are actually
- * enabled and configure default values related to those features.
- */
-static void
-qemuDomainDefEnableDefaultFeatures(virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- /* The virt machine type always uses GIC: if the relevant information
- * was not included in the domain XML, we need to choose a suitable
- * GIC version ourselves */
- if ((def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ABSENT &&
- qemuDomainIsARMVirt(def)) ||
- (def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ON &&
- def->gic_version == VIR_GIC_VERSION_NONE)) {
- virGICVersion version;
-
- VIR_DEBUG("Looking for usable GIC version in domain capabilities");
- for (version = VIR_GIC_VERSION_LAST - 1;
- version > VIR_GIC_VERSION_NONE;
- version--) {
-
- /* We want to use the highest available GIC version for guests;
- * however, the emulated GICv3 is currently lacking a MSI controller,
- * making it unsuitable for the pure PCIe topology we aim for.
- *
- * For that reason, we skip this step entirely for TCG guests,
- * and rely on the code below to pick the default version, GICv2,
- * which supports all the features we need.
- *
- * See https://bugzilla.redhat.com/show_bug.cgi?id=1414081 */
- if (version == VIR_GIC_VERSION_3 &&
- def->virtType == VIR_DOMAIN_VIRT_QEMU) {
- continue;
- }
-
- if (virQEMUCapsSupportsGICVersion(qemuCaps,
- def->virtType,
- version)) {
- VIR_DEBUG("Using GIC version %s",
- virGICVersionTypeToString(version));
- def->gic_version = version;
- break;
- }
- }
-
- /* Use the default GIC version (GICv2) as a last-ditch attempt
- * if no match could be found above */
- if (def->gic_version == VIR_GIC_VERSION_NONE) {
- VIR_DEBUG("Using GIC version 2 (default)");
- def->gic_version = VIR_GIC_VERSION_2;
- }
-
- /* Even if we haven't found a usable GIC version in the domain
- * capabilities, we still want to enable this */
- def->features[VIR_DOMAIN_FEATURE_GIC] = VIR_TRISTATE_SWITCH_ON;
- }
-}
-
-
-static int
-qemuCanonicalizeMachine(virDomainDef *def, virQEMUCaps *qemuCaps)
-{
- const char *canon;
-
- if (!(canon = virQEMUCapsGetCanonicalMachine(qemuCaps, def->virtType,
- def->os.machine)))
- return 0;
-
- if (STRNEQ(canon, def->os.machine)) {
- char *tmp;
- tmp = g_strdup(canon);
- VIR_FREE(def->os.machine);
- def->os.machine = tmp;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainRecheckInternalPaths(virDomainDef *def,
- virQEMUDriverConfig *cfg,
- unsigned int flags)
-{
- size_t i = 0;
- size_t j = 0;
-
- for (i = 0; i < def->ngraphics; ++i) {
- virDomainGraphicsDef *graphics = def->graphics[i];
-
- for (j = 0; j < graphics->nListens; ++j) {
- virDomainGraphicsListenDef *glisten = &graphics->listens[j];
-
- /* This will happen only if we parse XML from old libvirts where
- * unix socket was available only for VNC graphics. In this
- * particular case we should follow the behavior and if we remove
- * the auto-generated socket based on config option from qemu.conf
- * we need to change the listen type to address. */
- if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
- glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET &&
- glisten->socket &&
- !glisten->autoGenerated &&
- STRPREFIX(glisten->socket, cfg->libDir)) {
- if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
- VIR_FREE(glisten->socket);
- glisten->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;
- } else {
- glisten->fromConfig = true;
- }
- }
- }
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefBootPostParse(virDomainDef *def,
- virQEMUDriver *driver,
- unsigned int parseFlags)
-{
- bool abiUpdate = !!(parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE);
-
- /* If we're loading an existing configuration from disk, we
- * should try as hard as possible to preserve historical
- * behavior. In particular, firmware autoselection being enabled
- * could never have resulted, before libvirt 9.2.0, in anything
- * but a raw firmware image being selected.
- *
- * In order to ensure that existing domains keep working even if
- * a firmware descriptor for a build with a different format is
- * given higher priority, explicitly add this requirement to the
- * definition before performing firmware selection */
- if (!abiUpdate && def->os.firmware) {
- if (!def->os.loader)
- def->os.loader = virDomainLoaderDefNew();
- if (!def->os.loader->format)
- def->os.loader->format = VIR_STORAGE_FILE_RAW;
- }
-
- /* Firmware selection can fail for a number of reasons, but the
- * most likely one is that the requested configuration contains
- * mistakes or includes constraints that are impossible to
- * satisfy on the current system.
- *
- * If that happens, we have to react differently based on the
- * situation: if we're defining a new domain or updating its ABI,
- * we should let the user know immediately so that they can
- * change the requested configuration, hopefully into one that we
- * can work with; if we're loading the configuration of an
- * existing domain from disk, however, we absolutely cannot error
- * out here, or the domain will disappear.
- *
- * To handle the second case gracefully, we clear any reported
- * errors and continue as if nothing had happened. When it's time
- * to start the domain, qemuFirmwareFillDomain() will be run
- * again, fail in the same way, and at that point we'll have a
- * chance to inform the user of any issues */
- if (qemuFirmwareFillDomain(driver, def, abiUpdate) < 0) {
- if (abiUpdate) {
- return -1;
- } else {
- virResetLastError();
- return 0;
- }
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefMachinePostParse(virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- if (!def->os.machine) {
- const char *machine = virQEMUCapsGetPreferredMachine(qemuCaps,
- def->virtType);
- if (!machine) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("could not get preferred machine for %1$s type=%2$s"),
- def->emulator,
- virDomainVirtTypeToString(def->virtType));
- return -1;
- }
-
- def->os.machine = g_strdup(machine);
- }
-
- if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
- return -1;
-
- return 0;
-}
-
-
-static int
-qemuDomainDefVcpusPostParse(virDomainDef *def)
-{
- unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
- virDomainVcpuDef *vcpu;
- virDomainVcpuDef *prevvcpu;
- size_t i;
- bool has_order = false;
-
- /* vcpu 0 needs to be present, first, and non-hotpluggable */
- vcpu = virDomainDefGetVcpu(def, 0);
- if (!vcpu->online) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("vcpu 0 can't be offline"));
- return -1;
- }
- if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("vcpu0 can't be hotpluggable"));
- return -1;
- }
- if (vcpu->order != 0 && vcpu->order != 1) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("vcpu0 must be enabled first"));
- return -1;
- }
-
- if (vcpu->order != 0)
- has_order = true;
-
- prevvcpu = vcpu;
-
- /* all online vcpus or non online vcpu need to have order set */
- for (i = 1; i < maxvcpus; i++) {
- vcpu = virDomainDefGetVcpu(def, i);
-
- if (vcpu->online &&
- (vcpu->order != 0) != has_order) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("all vcpus must have either set or unset order"));
- return -1;
- }
-
- /* few conditions for non-hotpluggable (thus online) vcpus */
- if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_NO) {
- /* they can be ordered only at the beginning */
- if (prevvcpu->hotpluggable == VIR_TRISTATE_BOOL_YES) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("online non-hotpluggable vcpus need to be ordered prior to hotplugable vcpus"));
- return -1;
- }
-
- /* they need to be in order (qemu doesn't support any order yet).
- * Also note that multiple vcpus may share order on some platforms */
- if (prevvcpu->order > vcpu->order) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("online non-hotpluggable vcpus must be ordered in ascending order"));
- return -1;
- }
- }
-
- prevvcpu = vcpu;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefSetDefaultCPU(virDomainDef *def,
- virArch hostarch,
- virQEMUCaps *qemuCaps)
-{
- const char *model;
-
- if (def->cpu &&
- (def->cpu->mode != VIR_CPU_MODE_CUSTOM ||
- def->cpu->model))
- return 0;
-
- if (!virCPUArchIsSupported(def->os.arch))
- return 0;
-
- /* Default CPU model info from QEMU is usable for TCG only except for
- * x86, s390, and ppc64. */
- if (!ARCH_IS_X86(def->os.arch) &&
- !ARCH_IS_S390(def->os.arch) &&
- !ARCH_IS_PPC64(def->os.arch) &&
- def->virtType != VIR_DOMAIN_VIRT_QEMU)
- return 0;
-
- model = virQEMUCapsGetMachineDefaultCPU(qemuCaps, def->os.machine, def->virtType);
- if (!model) {
- VIR_DEBUG("Unknown default CPU model for domain '%s'", def->name);
- return 0;
- }
-
- if (STREQ(model, "host") && def->virtType != VIR_DOMAIN_VIRT_KVM) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("QEMU reports invalid default CPU model \"host\" for non-kvm domain virt type"));
- return -1;
- }
-
- if (!def->cpu)
- def->cpu = virCPUDefNew();
-
- def->cpu->type = VIR_CPU_TYPE_GUEST;
-
- if (STREQ(model, "host")) {
- if (ARCH_IS_S390(def->os.arch) &&
- virQEMUCapsIsCPUModeSupported(qemuCaps, hostarch, def->virtType,
- VIR_CPU_MODE_HOST_MODEL,
- def->os.machine)) {
- def->cpu->mode = VIR_CPU_MODE_HOST_MODEL;
- } else {
- def->cpu->mode = VIR_CPU_MODE_HOST_PASSTHROUGH;
- }
-
- VIR_DEBUG("Setting default CPU mode for domain '%s' to %s",
- def->name, virCPUModeTypeToString(def->cpu->mode));
- } else {
- /* We need to turn off all CPU checks when the domain is started
- * because the default CPU (e.g., qemu64) may not be runnable on any
- * host. QEMU will just disable the unavailable features and we will
- * update the CPU definition accordingly and set check to FULL when
- * starting the domain. */
- def->cpu->check = VIR_CPU_CHECK_NONE;
- def->cpu->mode = VIR_CPU_MODE_CUSTOM;
- def->cpu->match = VIR_CPU_MATCH_EXACT;
- def->cpu->fallback = VIR_CPU_FALLBACK_FORBID;
- def->cpu->model = g_strdup(model);
-
- VIR_DEBUG("Setting default CPU model for domain '%s' to %s",
- def->name, model);
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefCPUPostParse(virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- virCPUFeatureDef *sveFeature = NULL;
- bool sveVectorLengthsProvided = false;
- size_t i;
-
- if (!def->cpu)
- return 0;
-
- for (i = 0; i < def->cpu->nfeatures; i++) {
- virCPUFeatureDef *feature = &def->cpu->features[i];
-
- if (STREQ(feature->name, "sve")) {
- sveFeature = feature;
- } else if (STRPREFIX(feature->name, "sve")) {
- sveVectorLengthsProvided = true;
- }
- }
-
- if (sveVectorLengthsProvided) {
- if (sveFeature) {
- if (sveFeature->policy == VIR_CPU_FEATURE_DISABLE ||
- sveFeature->policy == VIR_CPU_FEATURE_FORBID) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("SVE disabled, but SVE vector lengths provided"));
- return -1;
- } else {
- sveFeature->policy = VIR_CPU_FEATURE_REQUIRE;
- }
- } else {
- VIR_RESIZE_N(def->cpu->features, def->cpu->nfeatures_max,
- def->cpu->nfeatures, 1);
-
- def->cpu->features[def->cpu->nfeatures].name = g_strdup("sve");
- def->cpu->features[def->cpu->nfeatures].policy = VIR_CPU_FEATURE_REQUIRE;
-
- def->cpu->nfeatures++;
- }
- }
-
- /* Running domains were either started before QEMU_CAPS_CPU_MIGRATABLE was
- * introduced and thus we can't rely on it or they already have the
- * migratable default set. */
- if (def->id == -1 &&
- qemuCaps &&
- def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH &&
- def->cpu->migratable == VIR_TRISTATE_SWITCH_ABSENT) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_MIGRATABLE))
- def->cpu->migratable = VIR_TRISTATE_SWITCH_ON;
- else if (ARCH_IS_X86(def->os.arch))
- def->cpu->migratable = VIR_TRISTATE_SWITCH_OFF;
- }
-
- /* Nothing to be done if only CPU topology is specified. */
- if (def->cpu->mode == VIR_CPU_MODE_CUSTOM &&
- !def->cpu->model)
- return 0;
-
- if (def->cpu->check != VIR_CPU_CHECK_DEFAULT)
- return 0;
-
- switch ((virCPUMode) def->cpu->mode) {
- case VIR_CPU_MODE_HOST_PASSTHROUGH:
- case VIR_CPU_MODE_MAXIMUM:
- def->cpu->check = VIR_CPU_CHECK_NONE;
- break;
-
- case VIR_CPU_MODE_HOST_MODEL:
- def->cpu->check = VIR_CPU_CHECK_PARTIAL;
- break;
-
- case VIR_CPU_MODE_CUSTOM:
- /* Custom CPUs in TCG mode are not compared to host CPU by default. */
- if (def->virtType == VIR_DOMAIN_VIRT_QEMU)
- def->cpu->check = VIR_CPU_CHECK_NONE;
- else
- def->cpu->check = VIR_CPU_CHECK_PARTIAL;
- break;
-
- case VIR_CPU_MODE_LAST:
- break;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefTsegPostParse(virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- if (def->features[VIR_DOMAIN_FEATURE_SMM] != VIR_TRISTATE_SWITCH_ON)
- return 0;
-
- if (!def->tseg_specified)
- return 0;
-
- if (!qemuDomainIsQ35(def)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("SMM TSEG is only supported with q35 machine type"));
- return -1;
- }
-
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MCH_EXTENDED_TSEG_MBYTES)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Setting TSEG size is not supported with this QEMU binary"));
- return -1;
- }
-
- if (def->tseg_size & ((1 << 20) - 1)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("SMM TSEG size must be divisible by 1 MiB"));
- return -1;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefNumaAutoAdd(virDomainDef *def,
- unsigned int parseFlags)
-{
- bool abiUpdate = !!(parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE);
- unsigned long long nodeMem;
- size_t i;
-
- if (!abiUpdate ||
- !virDomainDefHasMemoryHotplug(def) ||
- virDomainNumaGetNodeCount(def->numa) > 0) {
- return 0;
- }
-
- nodeMem = virDomainDefGetMemoryTotal(def);
-
- if (!def->numa)
- def->numa = virDomainNumaNew();
-
- virDomainNumaSetNodeCount(def->numa, 1);
-
- for (i = 0; i < def->nmems; i++) {
- virDomainMemoryDef *mem = def->mems[i];
-
- if (mem->size > nodeMem) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Total size of memory devices exceeds the total memory size"));
- return -1;
- }
-
- nodeMem -= mem->size;
-
- switch (mem->model) {
- case VIR_DOMAIN_MEMORY_MODEL_DIMM:
- case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
- case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
- if (mem->targetNode == -1)
- mem->targetNode = 0;
- break;
-
- case VIR_DOMAIN_MEMORY_MODEL_NONE:
- case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
- case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
- case VIR_DOMAIN_MEMORY_MODEL_LAST:
- break;
- }
- }
-
- virDomainNumaSetNodeMemorySize(def->numa, 0, nodeMem);
-
- return 0;
-}
-
-
/**
* qemuDomainDefNumaCPUsRectify:
* @numa: pointer to numa definition
@@ -5106,141 +4256,6 @@ qemuDomainDefNumaCPUsRectify(virDomainDef *def,
}
-static int
-qemuDomainDefNumaCPUsPostParse(virDomainDef *def,
- virQEMUCaps *qemuCaps,
- unsigned int parseFlags)
-{
- if (qemuDomainDefNumaAutoAdd(def, parseFlags) < 0)
- return -1;
-
- return qemuDomainDefNumaCPUsRectify(def, qemuCaps);
-}
-
-
-static int
-qemuDomainDefPostParseBasic(virDomainDef *def,
- void *opaque G_GNUC_UNUSED)
-{
- virQEMUDriver *driver = opaque;
-
- /* check for emulator and create a default one if needed */
- if (!def->emulator) {
- if (!(def->emulator = virQEMUCapsGetDefaultEmulator(
- driver->hostarch, def->os.arch))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("No emulator found for arch '%1$s'"),
- virArchToString(def->os.arch));
- return 1;
- }
- }
-
- return 0;
-}
-
-
-/**
- * qemuDomainDefACPIPostParse:
- * @def: domain definition
- * @qemuCaps: qemu capabilities object
- *
- * Fixup the use of ACPI flag on certain architectures that never supported it
- * and users for some reason used it, which would break migration to newer
- * libvirt versions which check whether given machine type supports ACPI.
- *
- * The fixup is done in post-parse as it's hard to update the ABI stability
- * check on source of the migration.
- */
-static void
-qemuDomainDefACPIPostParse(virDomainDef *def,
- virQEMUCaps *qemuCaps,
- unsigned int parseFlags)
-{
- /* Only cases when ACPI is enabled need to be fixed up */
- if (def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON)
- return;
-
- /* Strip the <acpi/> feature only for non-fresh configs, in order to still
- * produce an error if the feature is present in a newly defined one.
- *
- * The use of the VIR_DOMAIN_DEF_PARSE_ABI_UPDATE looks counter-intuitive,
- * but it's used only in qemuDomainCreateXML/qemuDomainDefineXMLFlags APIs
- * */
- if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE)
- return;
-
- /* This fixup is applicable _only_ on architectures which were present as of
- * libvirt-9.2 and *never* supported ACPI. The fixup is currently done only
- * for existing users of s390(x) to fix migration for configs which had
- * <acpi/> despite being ignored.
- */
- if (def->os.arch != VIR_ARCH_S390 &&
- def->os.arch != VIR_ARCH_S390X)
- return;
-
- /* To be sure, we only strip ACPI if given machine type doesn't support it */
- if (virQEMUCapsMachineSupportsACPI(qemuCaps, def->virtType, def->os.machine) != VIR_TRISTATE_BOOL_NO)
- return;
-
- def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ABSENT;
-}
-
-
-static int
-qemuDomainDefPostParse(virDomainDef *def,
- unsigned int parseFlags,
- void *opaque,
- void *parseOpaque)
-{
- virQEMUDriver *driver = opaque;
- g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
- virQEMUCaps *qemuCaps = parseOpaque;
-
- /* Note that qemuCaps may be NULL when this function is called. This
- * function shall not fail in that case. It will be re-run on VM startup
- * with the capabilities populated.
- */
- if (!qemuCaps)
- return 1;
-
- if (qemuDomainDefMachinePostParse(def, qemuCaps) < 0)
- return -1;
-
- qemuDomainDefACPIPostParse(def, qemuCaps, parseFlags);
-
- if (qemuDomainDefBootPostParse(def, driver, parseFlags) < 0)
- return -1;
-
- if (qemuDomainDefAddDefaultDevices(driver, def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefSetDefaultCPU(def, driver->hostarch, qemuCaps) < 0)
- return -1;
-
- qemuDomainDefEnableDefaultFeatures(def, qemuCaps);
-
- if (qemuDomainRecheckInternalPaths(def, cfg, parseFlags) < 0)
- return -1;
-
- if (qemuSecurityVerify(driver->securityManager, def) < 0)
- return -1;
-
- if (qemuDomainDefVcpusPostParse(def) < 0)
- return -1;
-
- if (qemuDomainDefCPUPostParse(def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefTsegPostParse(def, qemuCaps) < 0)
- return -1;
-
- if (qemuDomainDefNumaCPUsPostParse(def, qemuCaps, parseFlags) < 0)
- return -1;
-
- return 0;
-}
-
-
int
qemuDomainValidateActualNetDef(const virDomainNetDef *net,
virQEMUCaps *qemuCaps G_GNUC_UNUSED)
@@ -5605,63 +4620,6 @@ qemuDomainValidateStorageSource(virStorageSource *src,
}
-/**
- * qemuDomainDefaultNetModel:
- * @def: domain definition
- * @qemuCaps: qemu capabilities
- *
- * Returns the default network model for a given domain. Note that if @qemuCaps
- * is NULL this function may return NULL if the default model depends on the
- * capabilities.
- */
-static int
-qemuDomainDefaultNetModel(const virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- /* When there are no backwards compatibility concerns getting in
- * the way, virtio is a good default */
- if (ARCH_IS_S390(def->os.arch) ||
- qemuDomainIsLoongArchVirt(def) ||
- qemuDomainIsRISCVVirt(def)) {
- return VIR_DOMAIN_NET_MODEL_VIRTIO;
- }
-
- if (ARCH_IS_ARM(def->os.arch)) {
- if (STREQ(def->os.machine, "versatilepb"))
- return VIR_DOMAIN_NET_MODEL_SMC91C111;
-
- if (qemuDomainIsARMVirt(def))
- return VIR_DOMAIN_NET_MODEL_VIRTIO;
-
- /* Incomplete. vexpress (and a few others) use this, but not all
- * arm boards */
- return VIR_DOMAIN_NET_MODEL_LAN9118;
- }
-
- /* In all other cases the model depends on the capabilities. If they were
- * not provided don't report any default. */
- if (!qemuCaps)
- return VIR_DOMAIN_NET_MODEL_UNKNOWN;
-
- /* Try several network devices in turn; each of these devices is
- * less likely be supported out-of-the-box by the guest operating
- * system than the previous one */
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_RTL8139))
- return VIR_DOMAIN_NET_MODEL_RTL8139;
-
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_E1000))
- return VIR_DOMAIN_NET_MODEL_E1000;
-
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_NET))
- return VIR_DOMAIN_NET_MODEL_VIRTIO;
-
- /* We've had no luck detecting support for any network device,
- * but we have to return something: might as well be rtl8139 */
- return VIR_DOMAIN_NET_MODEL_RTL8139;
-}
-
-
-
static bool
qemuDomainChrMatchDefaultPath(const char *prefix,
const char *infix,
@@ -5707,7 +4665,7 @@ qemuDomainChrMatchDefaultPath(const char *prefix,
* Please note, as of libvirt 9.7.0 the channelTargetDir is no longer derived
* from cfg->libDir but rather cfg->stateDir.
*/
-static void
+void
qemuDomainChrDefDropDefaultPath(virDomainChrDef *chr,
virQEMUDriver *driver)
{
@@ -5750,640 +4708,7 @@ qemuDomainChrDefDropDefaultPath(virDomainChrDef *chr,
}
-static int
-qemuDomainShmemDefPostParse(virDomainShmemDef *shm)
-{
- /* This was the default since the introduction of this device. */
- if (shm->model != VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL && !shm->size)
- shm->size = 4 << 20;
-
- /* Nothing more to check/change for IVSHMEM */
- if (shm->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM)
- return 0;
-
- if (!shm->server.enabled) {
- if (shm->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("shmem model '%1$s' is supported only with server option enabled"),
- virDomainShmemModelTypeToString(shm->model));
- return -1;
- }
-
- if (shm->msi.enabled) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("shmem model '%1$s' doesn't support msi"),
- virDomainShmemModelTypeToString(shm->model));
- }
- } else {
- if (shm->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("shmem model '%1$s' is supported only with server option disabled"),
- virDomainShmemModelTypeToString(shm->model));
- return -1;
- }
-
- if (shm->size) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("shmem model '%1$s' does not support size setting"),
- virDomainShmemModelTypeToString(shm->model));
- return -1;
- }
- shm->msi.enabled = true;
- if (!shm->msi.ioeventfd)
- shm->msi.ioeventfd = VIR_TRISTATE_SWITCH_ON;
- }
-
- return 0;
-}
-
-
-#define QEMU_USB_XHCI_MAXPORTS 15
-
-
-static int
-qemuDomainControllerDefPostParse(virDomainControllerDef *cont,
- const virDomainDef *def,
- virQEMUCaps *qemuCaps,
- unsigned int parseFlags)
-{
- switch (cont->type) {
- case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
- /* Set the default SCSI controller model if not already set */
- cont->model = qemuDomainGetSCSIControllerModel(def, cont, qemuCaps);
-
- if (cont->model < 0)
- return -1;
- break;
-
- case VIR_DOMAIN_CONTROLLER_TYPE_USB:
- if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_DEFAULT && qemuCaps) {
- /* Pick a suitable default model for the USB controller if none
- * has been selected by the user and we have the qemuCaps for
- * figuring out which controllers are supported.
- *
- * We rely on device availability instead of setting the model
- * unconditionally because, for some machine types, there's a
- * chance we will get away with using the legacy USB controller
- * when the relevant device is not available.
- *
- * See qemuBuildControllersCommandLine() */
-
- /* Default USB controller is piix3-uhci if available. Fall back to
- * 'pci-ohci' otherwise which is the default for non-x86 machines
- * which honour -usb */
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI))
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
- else if (!ARCH_IS_X86(def->os.arch) &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_OHCI))
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
-
- if (ARCH_IS_S390(def->os.arch)) {
- if (cont->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
- /* set the default USB model to none for s390 unless an
- * address is found */
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE;
- }
- } else if (ARCH_IS_PPC64(def->os.arch)) {
- /* To not break migration we need to set default USB controller
- * for ppc64 to pci-ohci if we cannot change ABI of the VM.
- * The nec-usb-xhci or qemu-xhci controller is used as default
- * only for newly defined domains or devices. */
- if ((parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE) &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI)) {
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
- } else if ((parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE) &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI)) {
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI;
- } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_OHCI)) {
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
- } else {
- /* Explicitly fallback to legacy USB controller for PPC64. */
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_DEFAULT;
- }
- } else if (def->os.arch == VIR_ARCH_AARCH64) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI))
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
- else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI))
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI;
- } else if (ARCH_IS_LOONGARCH(def->os.arch)) {
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI))
- cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
- }
- }
- /* forbid usb model 'qusb1' and 'qusb2' in this kind of hyperviosr */
- if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1 ||
- cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("USB controller model type 'qusb1' or 'qusb2' is not supported in %1$s"),
- virDomainVirtTypeToString(def->virtType));
- return -1;
- }
- if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI ||
- cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI) &&
- cont->opts.usbopts.ports > QEMU_USB_XHCI_MAXPORTS) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("'%1$s' controller only supports up to '%2$u' ports"),
- virDomainControllerModelUSBTypeToString(cont->model),
- QEMU_USB_XHCI_MAXPORTS);
- return -1;
- }
- break;
-
- case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
-
- /* pSeries guests can have multiple pci-root controllers,
- * but other machine types only support a single one */
- if (!qemuDomainIsPSeries(def) &&
- (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
- cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) &&
- cont->idx != 0) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("pci-root and pcie-root controllers should have index 0"));
- return -1;
- }
-
- if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS &&
- !qemuDomainIsI440FX(def)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("pci-expander-bus controllers are only supported on 440fx-based machinetypes"));
- return -1;
- }
- if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS &&
- !(qemuDomainIsQ35(def) || qemuDomainIsARMVirt(def))) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("pcie-expander-bus controllers are not supported with this machine type"));
- return -1;
- }
-
- /* if a PCI expander bus or pci-root on Pseries has a NUMA node
- * set, make sure that NUMA node is configured in the guest
- * <cpu><numa> array. NUMA cell id's in this array are numbered
- * from 0 .. size-1.
- */
- if (cont->opts.pciopts.numaNode >= 0 &&
- cont->opts.pciopts.numaNode >=
- (int)virDomainNumaGetNodeCount(def->numa)) {
- virReportError(VIR_ERR_XML_ERROR,
- _("%1$s with index %2$d is configured for a NUMA node (%3$d) not present in the domain's <cpu><numa> array (%4$zu)"),
- virDomainControllerModelPCITypeToString(cont->model),
- cont->idx, cont->opts.pciopts.numaNode,
- virDomainNumaGetNodeCount(def->numa));
- return -1;
- }
- break;
-
- case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
- case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
- case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
- case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
- case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
- case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS:
- case VIR_DOMAIN_CONTROLLER_TYPE_ISA:
- case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
- break;
- }
-
- return 0;
-}
-
-static int
-qemuDomainChrDefPostParse(virDomainChrDef *chr,
- const virDomainDef *def,
- virQEMUDriver *driver,
- unsigned int parseFlags)
-{
- /* Historically, isa-serial and the default matched, so in order to
- * maintain backwards compatibility we map them here. The actual default
- * will be picked below based on the architecture and machine type. */
- if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
- chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA) {
- chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE;
- }
-
- /* Set the default serial type */
- if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
- chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE) {
- if (ARCH_IS_X86(def->os.arch)) {
- chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
- } else if (qemuDomainIsPSeries(def)) {
- chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO;
- } else if (qemuDomainIsARMVirt(def) ||
- qemuDomainIsLoongArchVirt(def) ||
- qemuDomainIsRISCVVirt(def)) {
- chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM;
- } else if (ARCH_IS_S390(def->os.arch)) {
- chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP;
- }
- }
-
- /* Set the default target model */
- if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
- chr->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_NONE) {
- switch ((virDomainChrSerialTargetType)chr->targetType) {
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA:
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_ISA_SERIAL;
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB:
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_USB_SERIAL;
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI:
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PCI_SERIAL;
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO:
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SPAPR_VTY;
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM:
- if (qemuDomainIsARMVirt(def)) {
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PL011;
- } else if (qemuDomainIsLoongArchVirt(def) ||
- qemuDomainIsRISCVVirt(def)) {
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_16550A;
- }
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP:
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPCONSOLE;
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA_DEBUG:
- chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_ISA_DEBUGCON;
- break;
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE:
- case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST:
- /* Nothing to do */
- break;
- }
- }
-
- /* clear auto generated unix socket path for inactive definitions */
- if (parseFlags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
- qemuDomainChrDefDropDefaultPath(chr, driver);
-
- /* For UNIX chardev if no path is provided we generate one.
- * This also implies that the mode is 'bind'. */
- if (chr->source &&
- chr->source->type == VIR_DOMAIN_CHR_TYPE_UNIX &&
- !chr->source->data.nix.path) {
- chr->source->data.nix.listen = true;
- }
- }
-
- return 0;
-}
-
-
-/**
- * qemuDomainDeviceDiskDefPostParseRestoreSecAlias:
- *
- * Re-generate aliases for objects related to the storage source if they
- * were not stored in the status XML by an older libvirt.
- *
- * Note that qemuCaps should be always present for a status XML.
- */
-static int
-qemuDomainDeviceDiskDefPostParseRestoreSecAlias(virDomainDiskDef *disk,
- unsigned int parseFlags)
-{
- qemuDomainStorageSourcePrivate *priv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
- bool restoreAuthSecret = false;
- bool restoreEncSecret = false;
- g_autofree char *authalias = NULL;
- g_autofree char *encalias = NULL;
-
- if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS) ||
- virStorageSourceIsEmpty(disk->src))
- return 0;
-
- /* network storage authentication secret */
- if (disk->src->auth &&
- (!priv || !priv->secinfo)) {
-
- /* only RBD and iSCSI (with capability) were supporting authentication
- * using secret object at the time we did not format the alias into the
- * status XML */
- if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_NETWORK &&
- (disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD ||
- disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI))
- restoreAuthSecret = true;
- }
-
- /* disk encryption secret */
- if (disk->src->encryption &&
- disk->src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS &&
- (!priv || !priv->encinfo))
- restoreEncSecret = true;
-
- if (!restoreAuthSecret && !restoreEncSecret)
- return 0;
-
- if (!priv) {
- if (!(disk->src->privateData = qemuDomainStorageSourcePrivateNew()))
- return -1;
-
- priv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
- }
-
- if (restoreAuthSecret) {
- authalias = g_strdup_printf("%s-secret0", disk->info.alias);
-
- if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->secinfo, &authalias) < 0)
- return -1;
- }
-
- if (restoreEncSecret) {
- if (!priv->encinfo) {
- priv->enccount = 1;
- priv->encinfo = g_new0(qemuDomainSecretInfo *, 1);
- }
-
- encalias = g_strdup_printf("%s-luks-secret0", disk->info.alias);
-
- if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo[0], &encalias) < 0)
- return -1;
- }
-
- return 0;
-}
-
-
int
-qemuDomainDeviceDiskDefPostParse(virDomainDiskDef *disk,
- unsigned int parseFlags)
-{
- virStorageSource *n;
-
- /* set default disk types and drivers */
- if (!virDomainDiskGetDriver(disk))
- virDomainDiskSetDriver(disk, "qemu");
-
- /* default disk format for drives */
- if (virDomainDiskGetFormat(disk) == VIR_STORAGE_FILE_NONE &&
- virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_VOLUME)
- virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
-
- /* default disk format for mirrored drive */
- if (disk->mirror &&
- disk->mirror->format == VIR_STORAGE_FILE_NONE)
- disk->mirror->format = VIR_STORAGE_FILE_RAW;
-
- /* default disk encryption engine */
- for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) {
- if (n->encryption && n->encryption->engine == VIR_STORAGE_ENCRYPTION_ENGINE_DEFAULT)
- n->encryption->engine = VIR_STORAGE_ENCRYPTION_ENGINE_QEMU;
- }
-
- if (qemuDomainDeviceDiskDefPostParseRestoreSecAlias(disk, parseFlags) < 0)
- return -1;
-
- /* regenerate TLS alias for old status XMLs */
- if (parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS &&
- disk->src->haveTLS == VIR_TRISTATE_BOOL_YES &&
- !disk->src->tlsAlias &&
- !(disk->src->tlsAlias = qemuAliasTLSObjFromSrcAlias(disk->info.alias)))
- return -1;
-
- return 0;
-}
-
-
-static int
-qemuDomainDeviceNetDefPostParse(virDomainNetDef *net,
- const virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- if (net->type == VIR_DOMAIN_NET_TYPE_VDPA &&
- !virDomainNetGetModelString(net)) {
- net->model = VIR_DOMAIN_NET_MODEL_VIRTIO;
- } else if (net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
- !virDomainNetGetModelString(net) &&
- virDomainNetResolveActualType(net) != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
- net->model = qemuDomainDefaultNetModel(def, qemuCaps);
- }
-
- if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
- net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT) {
- virDomainCapsDeviceNet netCaps = { };
-
- virQEMUCapsFillDomainDeviceNetCaps(qemuCaps, &netCaps);
-
- if (!VIR_DOMAIN_CAPS_ENUM_IS_SET(netCaps.backendType, VIR_DOMAIN_NET_BACKEND_DEFAULT) &&
- VIR_DOMAIN_CAPS_ENUM_IS_SET(netCaps.backendType, VIR_DOMAIN_NET_BACKEND_PASST)) {
- net->backend.type = VIR_DOMAIN_NET_BACKEND_PASST;
- }
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDefaultVideoDevice(const virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- if (ARCH_IS_PPC64(def->os.arch))
- return VIR_DOMAIN_VIDEO_TYPE_VGA;
- if (qemuDomainIsARMVirt(def) ||
- qemuDomainIsLoongArchVirt(def) ||
- qemuDomainIsRISCVVirt(def) ||
- ARCH_IS_S390(def->os.arch)) {
- return VIR_DOMAIN_VIDEO_TYPE_VIRTIO;
- }
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_CIRRUS_VGA))
- return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VGA))
- return VIR_DOMAIN_VIDEO_TYPE_VGA;
- return VIR_DOMAIN_VIDEO_TYPE_DEFAULT;
-}
-
-
-static int
-qemuDomainDeviceVideoDefPostParse(virDomainVideoDef *video,
- const virDomainDef *def,
- virQEMUCaps *qemuCaps)
-{
- if (video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT)
- video->type = qemuDomainDefaultVideoDevice(def, qemuCaps);
-
- if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL &&
- !video->vgamem) {
- video->vgamem = QEMU_QXL_VGAMEM_DEFAULT;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDevicePanicDefPostParse(virDomainPanicDef *panic,
- const virDomainDef *def)
-{
- if (panic->model == VIR_DOMAIN_PANIC_MODEL_DEFAULT)
- panic->model = qemuDomainDefaultPanicModel(def);
-
- return 0;
-}
-
-
-static int
-qemuDomainVsockDefPostParse(virDomainVsockDef *vsock)
-{
- if (vsock->model == VIR_DOMAIN_VSOCK_MODEL_DEFAULT)
- vsock->model = VIR_DOMAIN_VSOCK_MODEL_VIRTIO;
-
- return 0;
-}
-
-
-/**
- * qemuDomainDeviceHostdevDefPostParseRestoreSecAlias:
- *
- * Re-generate aliases for objects related to the storage source if they
- * were not stored in the status XML by an older libvirt.
- *
- * Note that qemuCaps should be always present for a status XML.
- */
-static int
-qemuDomainDeviceHostdevDefPostParseRestoreSecAlias(virDomainHostdevDef *hostdev,
- unsigned int parseFlags)
-{
- qemuDomainStorageSourcePrivate *priv;
- virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
- virDomainHostdevSubsysSCSIiSCSI *iscsisrc = &scsisrc->u.iscsi;
- g_autofree char *authalias = NULL;
-
- if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS))
- return 0;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI ||
- scsisrc->protocol != VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI ||
- !iscsisrc->src->auth)
- return 0;
-
- if (!(priv = qemuDomainStorageSourcePrivateFetch(iscsisrc->src)))
- return -1;
-
- if (priv->secinfo)
- return 0;
-
- authalias = g_strdup_printf("%s-secret0", hostdev->info->alias);
-
- if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->secinfo, &authalias) < 0)
- return -1;
-
- return 0;
-}
-
-
-/**
- * qemuDomainDeviceHostdevDefPostParseRestoreBackendAlias:
- *
- * Re-generate backend alias if it wasn't stored in the status XML by an older
- * libvirtd.
- *
- * Note that qemuCaps should be always present for a status XML.
- */
-static int
-qemuDomainDeviceHostdevDefPostParseRestoreBackendAlias(virDomainHostdevDef *hostdev,
- unsigned int parseFlags)
-{
- virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
- virStorageSource *src;
-
- if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS))
- return 0;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
- return 0;
-
- switch (scsisrc->protocol) {
- case VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_NONE:
- if (!scsisrc->u.host.src)
- scsisrc->u.host.src = virStorageSourceNew();
-
- src = scsisrc->u.host.src;
- break;
-
- case VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI:
- src = scsisrc->u.iscsi.src;
- break;
-
- case VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_LAST:
- default:
- virReportEnumRangeError(virDomainHostdevSCSIProtocolType, scsisrc->protocol);
- return -1;
- }
-
- if (!qemuBlockStorageSourceGetStorageNodename(src))
- qemuBlockStorageSourceSetStorageNodename(src, g_strdup_printf("libvirt-%s-backend", hostdev->info->alias));
-
- return 0;
-}
-
-
-static int
-qemuDomainHostdevDefMdevPostParse(virDomainHostdevSubsysMediatedDev *mdevsrc)
-{
- /* QEMU 2.12 added support for vfio-pci display type, we default to
- * 'display=off' to stay safe from future changes */
- if (mdevsrc->model == VIR_MDEV_MODEL_TYPE_VFIO_PCI &&
- mdevsrc->display == VIR_TRISTATE_SWITCH_ABSENT)
- mdevsrc->display = VIR_TRISTATE_SWITCH_OFF;
-
- return 0;
-}
-
-
-static int
-qemuDomainHostdevDefPostParse(virDomainHostdevDef *hostdev,
- unsigned int parseFlags)
-{
- virDomainHostdevSubsys *subsys = &hostdev->source.subsys;
-
- if (qemuDomainDeviceHostdevDefPostParseRestoreSecAlias(hostdev, parseFlags) < 0)
- return -1;
-
- if (qemuDomainDeviceHostdevDefPostParseRestoreBackendAlias(hostdev, parseFlags) < 0)
- return -1;
-
- if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV &&
- qemuDomainHostdevDefMdevPostParse(&subsys->u.mdev) < 0)
- return -1;
-
- return 0;
-}
-
-
-static int
-qemuDomainTPMDefPostParse(virDomainTPMDef *tpm,
- const virDomainDef *def)
-{
- if (tpm->model == VIR_DOMAIN_TPM_MODEL_DEFAULT) {
- if (ARCH_IS_PPC64(def->os.arch))
- tpm->model = VIR_DOMAIN_TPM_MODEL_SPAPR;
- else
- tpm->model = VIR_DOMAIN_TPM_MODEL_TIS;
- }
-
- /* TPM 1.2 and 2 are not compatible, so we choose a specific version here */
- if (tpm->type == VIR_DOMAIN_TPM_TYPE_EMULATOR &&
- tpm->data.emulator.version == VIR_DOMAIN_TPM_VERSION_DEFAULT) {
- /* tpm-tis on x86 defaults to TPM 1.2 to preserve the
- * historical behavior, but in all other scenarios we want
- * TPM 2.0 instead */
- if (tpm->model == VIR_DOMAIN_TPM_MODEL_TIS &&
- ARCH_IS_X86(def->os.arch)) {
- tpm->data.emulator.version = VIR_DOMAIN_TPM_VERSION_1_2;
- } else {
- tpm->data.emulator.version = VIR_DOMAIN_TPM_VERSION_2_0;
- }
- }
-
- return 0;
-}
-
-
-static int
qemuDomainNVDimmAlignSizePseries(virDomainMemoryDef *mem)
{
/* For NVDIMMs in ppc64 in we want to align down the guest
@@ -6418,194 +4743,6 @@ qemuDomainNVDimmAlignSizePseries(virDomainMemoryDef *mem)
}
-static int
-qemuDomainMemoryDefPostParse(virDomainMemoryDef *mem, virArch arch,
- unsigned int parseFlags)
-{
- /* Memory alignment can't be done for migration or snapshot
- * scenarios. This logic was defined by commit c7d7ba85a624.
- *
- * There is no easy way to replicate at this point the same conditions
- * used to call qemuDomainAlignMemorySizes(), which means checking if
- * we're not migrating and not in a snapshot.
- *
- * We can use the PARSE_ABI_UPDATE flag, which is more strict -
- * existing guests will not activate the flag to avoid breaking
- * boot ABI. This means that any alignment done here will be replicated
- * later on by qemuDomainAlignMemorySizes() to contemplate existing
- * guests as well. */
- if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE) {
- if (ARCH_IS_PPC64(arch)) {
- unsigned long long ppc64MemModuleAlign = 256 * 1024;
-
- if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
- if (qemuDomainNVDimmAlignSizePseries(mem) < 0)
- return -1;
- } else {
- mem->size = VIR_ROUND_UP(mem->size, ppc64MemModuleAlign);
- }
- }
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainPstoreDefPostParse(virDomainPstoreDef *pstore,
- const virDomainDef *def,
- virQEMUDriver *driver)
-{
- g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
-
- switch (pstore->backend) {
- case VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST:
- if (!pstore->path)
- pstore->path = g_strdup_printf("%s/%s_PSTORE.raw",
- cfg->nvramDir, def->name);
- break;
-
- case VIR_DOMAIN_PSTORE_BACKEND_LAST:
- break;
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainIOMMUDefPostParse(virDomainIOMMUDef *iommu,
- const virDomainDef *def,
- virQEMUCaps *qemuCaps,
- unsigned int parseFlags)
-{
- /* In case domain has huge number of vCPUS and Extended Interrupt Mode
- * (EIM) is not explicitly turned off, let's enable it. If we didn't then
- * guest will have troubles with interrupts. */
- if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE &&
- ARCH_IS_X86(def->os.arch) &&
- virDomainDefGetVcpusMax(def) > QEMU_MAX_VCPUS_WITHOUT_EIM &&
- qemuDomainIsQ35(def) &&
- iommu && iommu->model == VIR_DOMAIN_IOMMU_MODEL_INTEL) {
-
- /* eim requires intremap. */
- if (iommu->intremap == VIR_TRISTATE_SWITCH_ABSENT &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_INTREMAP)) {
- iommu->intremap = VIR_TRISTATE_SWITCH_ON;
- }
-
- if (iommu->eim == VIR_TRISTATE_SWITCH_ABSENT &&
- virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_EIM)) {
- iommu->eim = VIR_TRISTATE_SWITCH_ON;
- }
- }
-
- return 0;
-}
-
-
-static int
-qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
- const virDomainDef *def,
- unsigned int parseFlags,
- void *opaque,
- void *parseOpaque)
-{
- virQEMUDriver *driver = opaque;
- /* Note that qemuCaps may be NULL when this function is called. This
- * function shall not fail in that case. It will be re-run on VM startup
- * with the capabilities populated. */
- virQEMUCaps *qemuCaps = parseOpaque;
- int ret = -1;
-
- switch (dev->type) {
- case VIR_DOMAIN_DEVICE_NET:
- ret = qemuDomainDeviceNetDefPostParse(dev->data.net, def, qemuCaps);
- break;
-
- case VIR_DOMAIN_DEVICE_DISK:
- ret = qemuDomainDeviceDiskDefPostParse(dev->data.disk, parseFlags);
- break;
-
- case VIR_DOMAIN_DEVICE_VIDEO:
- ret = qemuDomainDeviceVideoDefPostParse(dev->data.video, def, qemuCaps);
- break;
-
- case VIR_DOMAIN_DEVICE_PANIC:
- ret = qemuDomainDevicePanicDefPostParse(dev->data.panic, def);
- break;
-
- case VIR_DOMAIN_DEVICE_CONTROLLER:
- ret = qemuDomainControllerDefPostParse(dev->data.controller, def,
- qemuCaps, parseFlags);
- break;
-
- case VIR_DOMAIN_DEVICE_SHMEM:
- ret = qemuDomainShmemDefPostParse(dev->data.shmem);
- break;
-
- case VIR_DOMAIN_DEVICE_CHR:
- ret = qemuDomainChrDefPostParse(dev->data.chr, def, driver, parseFlags);
- break;
-
- case VIR_DOMAIN_DEVICE_VSOCK:
- ret = qemuDomainVsockDefPostParse(dev->data.vsock);
- break;
-
- case VIR_DOMAIN_DEVICE_HOSTDEV:
- ret = qemuDomainHostdevDefPostParse(dev->data.hostdev, parseFlags);
- break;
-
- case VIR_DOMAIN_DEVICE_TPM:
- ret = qemuDomainTPMDefPostParse(dev->data.tpm, def);
- break;
-
- case VIR_DOMAIN_DEVICE_MEMORY:
- ret = qemuDomainMemoryDefPostParse(dev->data.memory, def->os.arch,
- parseFlags);
- break;
-
- case VIR_DOMAIN_DEVICE_PSTORE:
- ret = qemuDomainPstoreDefPostParse(dev->data.pstore, def, driver);
- break;
-
- case VIR_DOMAIN_DEVICE_IOMMU:
- ret = qemuDomainIOMMUDefPostParse(dev->data.iommu, def,
- qemuCaps, parseFlags);
- break;
-
- case VIR_DOMAIN_DEVICE_LEASE:
- case VIR_DOMAIN_DEVICE_FS:
- case VIR_DOMAIN_DEVICE_INPUT:
- case VIR_DOMAIN_DEVICE_SOUND:
- case VIR_DOMAIN_DEVICE_WATCHDOG:
- case VIR_DOMAIN_DEVICE_GRAPHICS:
- case VIR_DOMAIN_DEVICE_HUB:
- case VIR_DOMAIN_DEVICE_REDIRDEV:
- case VIR_DOMAIN_DEVICE_SMARTCARD:
- case VIR_DOMAIN_DEVICE_MEMBALLOON:
- case VIR_DOMAIN_DEVICE_NVRAM:
- case VIR_DOMAIN_DEVICE_RNG:
- case VIR_DOMAIN_DEVICE_AUDIO:
- case VIR_DOMAIN_DEVICE_CRYPTO:
- ret = 0;
- break;
-
- case VIR_DOMAIN_DEVICE_NONE:
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected VIR_DOMAIN_DEVICE_NONE"));
- break;
-
- case VIR_DOMAIN_DEVICE_LAST:
- default:
- virReportEnumRangeError(virDomainDeviceType, dev->type);
- break;
- }
-
- return ret;
-}
-
-
static int
qemuDomainDefAssignAddresses(virDomainDef *def,
unsigned int parseFlags G_GNUC_UNUSED,
@@ -6630,31 +4767,6 @@ qemuDomainDefAssignAddresses(virDomainDef *def,
}
-static int
-qemuDomainPostParseDataAlloc(const virDomainDef *def,
- unsigned int parseFlags G_GNUC_UNUSED,
- void *opaque,
- void **parseOpaque)
-{
- virQEMUDriver *driver = opaque;
-
- if (!(*parseOpaque = virQEMUCapsCacheLookup(driver->qemuCapsCache,
- def->emulator)))
- return 1;
-
- return 0;
-}
-
-
-static void
-qemuDomainPostParseDataFree(void *parseOpaque)
-{
- virQEMUCaps *qemuCaps = parseOpaque;
-
- virObjectUnref(qemuCaps);
-}
-
-
virDomainDefParserConfig virQEMUDriverDomainDefParserConfig = {
.domainPostParseBasicCallback = qemuDomainDefPostParseBasic,
.domainPostParseDataAlloc = qemuDomainPostParseDataAlloc,
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 047a11b7fe..1ae421e5f2 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -780,6 +780,9 @@ void qemuDomainCleanupRun(virQEMUDriver *driver,
void qemuDomainObjPrivateDataClear(qemuDomainObjPrivate *priv);
+int qemuStorageSourcePrivateDataAssignSecinfo(qemuDomainSecretInfo **secinfo,
+ char **alias);
+
extern virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks;
extern virXMLNamespace virQEMUDriverDomainXMLNamespace;
extern virDomainDefParserConfig virQEMUDriverDomainDefParserConfig;
@@ -849,6 +852,11 @@ int qemuDomainGetSCSIControllerModel(const virDomainDef *def,
const virDomainControllerDef *cont,
virQEMUCaps *qemuCaps);
+int qemuDomainDefAddDefaultAudioBackend(virQEMUDriver *driver,
+ virDomainDef *def);
+
+virDomainPanicModel qemuDomainDefaultPanicModel(const virDomainDef *def);
+
void qemuDomainUpdateCurrentMemorySize(virDomainObj *vm);
unsigned long long qemuDomainGetMemLockLimitBytes(virDomainDef *def);
@@ -938,8 +946,12 @@ int qemuDomainSecretPrepare(virQEMUDriver *driver,
virDomainObj *vm)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int qemuDomainDeviceDiskDefPostParse(virDomainDiskDef *disk,
- unsigned int parseFlags);
+void
+qemuDomainChrDefDropDefaultPath(virDomainChrDef *chr,
+ virQEMUDriver *driver);
+
+int
+qemuDomainNVDimmAlignSizePseries(virDomainMemoryDef *mem);
int qemuDomainPrepareChannel(virDomainChrDef *chr,
const char *domainChannelTargetDir)
diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c
new file mode 100644
index 0000000000..11134fb030
--- /dev/null
+++ b/src/qemu/qemu_postparse.c
@@ -0,0 +1,1925 @@
+/*
+ * qemu_postparse.c: QEMU domain PostParse functions
+ *
+ * Copyright (C) 2006-2024 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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_postparse.h"
+#include "qemu_alias.h"
+#include "qemu_block.h"
+#include "qemu_domain.h"
+#include "qemu_firmware.h"
+#include "qemu_security.h"
+#include "qemu_validate.h"
+#include "domain_conf.h"
+#include "viralloc.h"
+#include "virlog.h"
+
+#define QEMU_QXL_VGAMEM_DEFAULT 16 * 1024
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu.qemu_postparse");
+
+
+/**
+ * qemuDomainDefaultNetModel:
+ * @def: domain definition
+ * @qemuCaps: qemu capabilities
+ *
+ * Returns the default network model for a given domain. Note that if @qemuCaps
+ * is NULL this function may return NULL if the default model depends on the
+ * capabilities.
+ */
+static int
+qemuDomainDefaultNetModel(const virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ /* When there are no backwards compatibility concerns getting in
+ * the way, virtio is a good default */
+ if (ARCH_IS_S390(def->os.arch) ||
+ qemuDomainIsLoongArchVirt(def) ||
+ qemuDomainIsRISCVVirt(def)) {
+ return VIR_DOMAIN_NET_MODEL_VIRTIO;
+ }
+
+ if (ARCH_IS_ARM(def->os.arch)) {
+ if (STREQ(def->os.machine, "versatilepb"))
+ return VIR_DOMAIN_NET_MODEL_SMC91C111;
+
+ if (qemuDomainIsARMVirt(def))
+ return VIR_DOMAIN_NET_MODEL_VIRTIO;
+
+ /* Incomplete. vexpress (and a few others) use this, but not all
+ * arm boards */
+ return VIR_DOMAIN_NET_MODEL_LAN9118;
+ }
+
+ /* In all other cases the model depends on the capabilities. If they were
+ * not provided don't report any default. */
+ if (!qemuCaps)
+ return VIR_DOMAIN_NET_MODEL_UNKNOWN;
+
+ /* Try several network devices in turn; each of these devices is
+ * less likely be supported out-of-the-box by the guest operating
+ * system than the previous one */
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_RTL8139))
+ return VIR_DOMAIN_NET_MODEL_RTL8139;
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_E1000))
+ return VIR_DOMAIN_NET_MODEL_E1000;
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_NET))
+ return VIR_DOMAIN_NET_MODEL_VIRTIO;
+
+ /* We've had no luck detecting support for any network device,
+ * but we have to return something: might as well be rtl8139 */
+ return VIR_DOMAIN_NET_MODEL_RTL8139;
+}
+
+
+static int
+qemuDomainDeviceNetDefPostParse(virDomainNetDef *net,
+ const virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ if (net->type == VIR_DOMAIN_NET_TYPE_VDPA &&
+ !virDomainNetGetModelString(net)) {
+ net->model = VIR_DOMAIN_NET_MODEL_VIRTIO;
+ } else if (net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
+ !virDomainNetGetModelString(net) &&
+ virDomainNetResolveActualType(net) != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+ net->model = qemuDomainDefaultNetModel(def, qemuCaps);
+ }
+
+ if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+ net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT) {
+ virDomainCapsDeviceNet netCaps = { };
+
+ virQEMUCapsFillDomainDeviceNetCaps(qemuCaps, &netCaps);
+
+ if (!VIR_DOMAIN_CAPS_ENUM_IS_SET(netCaps.backendType, VIR_DOMAIN_NET_BACKEND_DEFAULT) &&
+ VIR_DOMAIN_CAPS_ENUM_IS_SET(netCaps.backendType, VIR_DOMAIN_NET_BACKEND_PASST)) {
+ net->backend.type = VIR_DOMAIN_NET_BACKEND_PASST;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * qemuDomainDeviceDiskDefPostParseRestoreSecAlias:
+ *
+ * Re-generate aliases for objects related to the storage source if they
+ * were not stored in the status XML by an older libvirt.
+ *
+ * Note that qemuCaps should be always present for a status XML.
+ */
+static int
+qemuDomainDeviceDiskDefPostParseRestoreSecAlias(virDomainDiskDef *disk,
+ unsigned int parseFlags)
+{
+ qemuDomainStorageSourcePrivate *priv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
+ bool restoreAuthSecret = false;
+ bool restoreEncSecret = false;
+ g_autofree char *authalias = NULL;
+ g_autofree char *encalias = NULL;
+
+ if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS) ||
+ virStorageSourceIsEmpty(disk->src))
+ return 0;
+
+ /* network storage authentication secret */
+ if (disk->src->auth &&
+ (!priv || !priv->secinfo)) {
+
+ /* only RBD and iSCSI (with capability) were supporting authentication
+ * using secret object at the time we did not format the alias into the
+ * status XML */
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_NETWORK &&
+ (disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD ||
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI))
+ restoreAuthSecret = true;
+ }
+
+ /* disk encryption secret */
+ if (disk->src->encryption &&
+ disk->src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS &&
+ (!priv || !priv->encinfo))
+ restoreEncSecret = true;
+
+ if (!restoreAuthSecret && !restoreEncSecret)
+ return 0;
+
+ if (!priv) {
+ if (!(disk->src->privateData = qemuDomainStorageSourcePrivateNew()))
+ return -1;
+
+ priv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
+ }
+
+ if (restoreAuthSecret) {
+ authalias = g_strdup_printf("%s-secret0", disk->info.alias);
+
+ if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->secinfo, &authalias) < 0)
+ return -1;
+ }
+
+ if (restoreEncSecret) {
+ if (!priv->encinfo) {
+ priv->enccount = 1;
+ priv->encinfo = g_new0(qemuDomainSecretInfo *, 1);
+ }
+
+ encalias = g_strdup_printf("%s-luks-secret0", disk->info.alias);
+
+ if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo[0], &encalias) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+qemuDomainDeviceDiskDefPostParse(virDomainDiskDef *disk,
+ unsigned int parseFlags)
+{
+ virStorageSource *n;
+
+ /* set default disk types and drivers */
+ if (!virDomainDiskGetDriver(disk))
+ virDomainDiskSetDriver(disk, "qemu");
+
+ /* default disk format for drives */
+ if (virDomainDiskGetFormat(disk) == VIR_STORAGE_FILE_NONE &&
+ virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_VOLUME)
+ virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
+
+ /* default disk format for mirrored drive */
+ if (disk->mirror &&
+ disk->mirror->format == VIR_STORAGE_FILE_NONE)
+ disk->mirror->format = VIR_STORAGE_FILE_RAW;
+
+ /* default disk encryption engine */
+ for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) {
+ if (n->encryption && n->encryption->engine == VIR_STORAGE_ENCRYPTION_ENGINE_DEFAULT)
+ n->encryption->engine = VIR_STORAGE_ENCRYPTION_ENGINE_QEMU;
+ }
+
+ if (qemuDomainDeviceDiskDefPostParseRestoreSecAlias(disk, parseFlags) < 0)
+ return -1;
+
+ /* regenerate TLS alias for old status XMLs */
+ if (parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS &&
+ disk->src->haveTLS == VIR_TRISTATE_BOOL_YES &&
+ !disk->src->tlsAlias &&
+ !(disk->src->tlsAlias = qemuAliasTLSObjFromSrcAlias(disk->info.alias)))
+ return -1;
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefaultVideoDevice(const virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ if (ARCH_IS_PPC64(def->os.arch))
+ return VIR_DOMAIN_VIDEO_TYPE_VGA;
+ if (qemuDomainIsARMVirt(def) ||
+ qemuDomainIsLoongArchVirt(def) ||
+ qemuDomainIsRISCVVirt(def) ||
+ ARCH_IS_S390(def->os.arch)) {
+ return VIR_DOMAIN_VIDEO_TYPE_VIRTIO;
+ }
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_CIRRUS_VGA))
+ return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VGA))
+ return VIR_DOMAIN_VIDEO_TYPE_VGA;
+ return VIR_DOMAIN_VIDEO_TYPE_DEFAULT;
+}
+
+
+static int
+qemuDomainDeviceVideoDefPostParse(virDomainVideoDef *video,
+ const virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ if (video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT)
+ video->type = qemuDomainDefaultVideoDevice(def, qemuCaps);
+
+ if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL &&
+ !video->vgamem) {
+ video->vgamem = QEMU_QXL_VGAMEM_DEFAULT;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDevicePanicDefPostParse(virDomainPanicDef *panic,
+ const virDomainDef *def)
+{
+ if (panic->model == VIR_DOMAIN_PANIC_MODEL_DEFAULT)
+ panic->model = qemuDomainDefaultPanicModel(def);
+
+ return 0;
+}
+
+
+#define QEMU_USB_XHCI_MAXPORTS 15
+
+static int
+qemuDomainControllerDefPostParse(virDomainControllerDef *cont,
+ const virDomainDef *def,
+ virQEMUCaps *qemuCaps,
+ unsigned int parseFlags)
+{
+ switch (cont->type) {
+ case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
+ /* Set the default SCSI controller model if not already set */
+ cont->model = qemuDomainGetSCSIControllerModel(def, cont, qemuCaps);
+
+ if (cont->model < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_CONTROLLER_TYPE_USB:
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_DEFAULT && qemuCaps) {
+ /* Pick a suitable default model for the USB controller if none
+ * has been selected by the user and we have the qemuCaps for
+ * figuring out which controllers are supported.
+ *
+ * We rely on device availability instead of setting the model
+ * unconditionally because, for some machine types, there's a
+ * chance we will get away with using the legacy USB controller
+ * when the relevant device is not available.
+ *
+ * See qemuBuildControllersCommandLine() */
+
+ /* Default USB controller is piix3-uhci if available. Fall back to
+ * 'pci-ohci' otherwise which is the default for non-x86 machines
+ * which honour -usb */
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI))
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
+ else if (!ARCH_IS_X86(def->os.arch) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_OHCI))
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
+
+ if (ARCH_IS_S390(def->os.arch)) {
+ if (cont->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+ /* set the default USB model to none for s390 unless an
+ * address is found */
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE;
+ }
+ } else if (ARCH_IS_PPC64(def->os.arch)) {
+ /* To not break migration we need to set default USB controller
+ * for ppc64 to pci-ohci if we cannot change ABI of the VM.
+ * The nec-usb-xhci or qemu-xhci controller is used as default
+ * only for newly defined domains or devices. */
+ if ((parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI)) {
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
+ } else if ((parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI)) {
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI;
+ } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_OHCI)) {
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
+ } else {
+ /* Explicitly fallback to legacy USB controller for PPC64. */
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_DEFAULT;
+ }
+ } else if (def->os.arch == VIR_ARCH_AARCH64) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI))
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
+ else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI))
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI;
+ } else if (ARCH_IS_LOONGARCH(def->os.arch)) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI))
+ cont->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
+ }
+ }
+ /* forbid usb model 'qusb1' and 'qusb2' in this kind of hyperviosr */
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1 ||
+ cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("USB controller model type 'qusb1' or 'qusb2' is not supported in %1$s"),
+ virDomainVirtTypeToString(def->virtType));
+ return -1;
+ }
+ if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI ||
+ cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI) &&
+ cont->opts.usbopts.ports > QEMU_USB_XHCI_MAXPORTS) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("'%1$s' controller only supports up to '%2$u' ports"),
+ virDomainControllerModelUSBTypeToString(cont->model),
+ QEMU_USB_XHCI_MAXPORTS);
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+
+ /* pSeries guests can have multiple pci-root controllers,
+ * but other machine types only support a single one */
+ if (!qemuDomainIsPSeries(def) &&
+ (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
+ cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) &&
+ cont->idx != 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("pci-root and pcie-root controllers should have index 0"));
+ return -1;
+ }
+
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS &&
+ !qemuDomainIsI440FX(def)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("pci-expander-bus controllers are only supported on 440fx-based machinetypes"));
+ return -1;
+ }
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS &&
+ !(qemuDomainIsQ35(def) || qemuDomainIsARMVirt(def))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("pcie-expander-bus controllers are not supported with this machine type"));
+ return -1;
+ }
+
+ /* if a PCI expander bus or pci-root on Pseries has a NUMA node
+ * set, make sure that NUMA node is configured in the guest
+ * <cpu><numa> array. NUMA cell id's in this array are numbered
+ * from 0 .. size-1.
+ */
+ if (cont->opts.pciopts.numaNode >= 0 &&
+ cont->opts.pciopts.numaNode >=
+ (int)virDomainNumaGetNodeCount(def->numa)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("%1$s with index %2$d is configured for a NUMA node (%3$d) not present in the domain's <cpu><numa> array (%4$zu)"),
+ virDomainControllerModelPCITypeToString(cont->model),
+ cont->idx, cont->opts.pciopts.numaNode,
+ virDomainNumaGetNodeCount(def->numa));
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
+ case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
+ case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
+ case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
+ case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
+ case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS:
+ case VIR_DOMAIN_CONTROLLER_TYPE_ISA:
+ case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
+ break;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainShmemDefPostParse(virDomainShmemDef *shm)
+{
+ /* This was the default since the introduction of this device. */
+ if (shm->model != VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL && !shm->size)
+ shm->size = 4 << 20;
+
+ /* Nothing more to check/change for IVSHMEM */
+ if (shm->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM)
+ return 0;
+
+ if (!shm->server.enabled) {
+ if (shm->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shmem model '%1$s' is supported only with server option enabled"),
+ virDomainShmemModelTypeToString(shm->model));
+ return -1;
+ }
+
+ if (shm->msi.enabled) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shmem model '%1$s' doesn't support msi"),
+ virDomainShmemModelTypeToString(shm->model));
+ }
+ } else {
+ if (shm->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shmem model '%1$s' is supported only with server option disabled"),
+ virDomainShmemModelTypeToString(shm->model));
+ return -1;
+ }
+
+ if (shm->size) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shmem model '%1$s' does not support size setting"),
+ virDomainShmemModelTypeToString(shm->model));
+ return -1;
+ }
+ shm->msi.enabled = true;
+ if (!shm->msi.ioeventfd)
+ shm->msi.ioeventfd = VIR_TRISTATE_SWITCH_ON;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainChrDefPostParse(virDomainChrDef *chr,
+ const virDomainDef *def,
+ virQEMUDriver *driver,
+ unsigned int parseFlags)
+{
+ /* Historically, isa-serial and the default matched, so in order to
+ * maintain backwards compatibility we map them here. The actual default
+ * will be picked below based on the architecture and machine type. */
+ if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
+ chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA) {
+ chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE;
+ }
+
+ /* Set the default serial type */
+ if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
+ chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE) {
+ if (ARCH_IS_X86(def->os.arch)) {
+ chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
+ } else if (qemuDomainIsPSeries(def)) {
+ chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO;
+ } else if (qemuDomainIsARMVirt(def) ||
+ qemuDomainIsLoongArchVirt(def) ||
+ qemuDomainIsRISCVVirt(def)) {
+ chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM;
+ } else if (ARCH_IS_S390(def->os.arch)) {
+ chr->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP;
+ }
+ }
+
+ /* Set the default target model */
+ if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
+ chr->targetModel == VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_NONE) {
+ switch ((virDomainChrSerialTargetType)chr->targetType) {
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA:
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_ISA_SERIAL;
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB:
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_USB_SERIAL;
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI:
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PCI_SERIAL;
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SPAPR_VIO:
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SPAPR_VTY;
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SYSTEM:
+ if (qemuDomainIsARMVirt(def)) {
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_PL011;
+ } else if (qemuDomainIsLoongArchVirt(def) ||
+ qemuDomainIsRISCVVirt(def)) {
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_16550A;
+ }
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_SCLP:
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_SCLPCONSOLE;
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA_DEBUG:
+ chr->targetModel = VIR_DOMAIN_CHR_SERIAL_TARGET_MODEL_ISA_DEBUGCON;
+ break;
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_NONE:
+ case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST:
+ /* Nothing to do */
+ break;
+ }
+ }
+
+ /* clear auto generated unix socket path for inactive definitions */
+ if (parseFlags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
+ qemuDomainChrDefDropDefaultPath(chr, driver);
+
+ /* For UNIX chardev if no path is provided we generate one.
+ * This also implies that the mode is 'bind'. */
+ if (chr->source &&
+ chr->source->type == VIR_DOMAIN_CHR_TYPE_UNIX &&
+ !chr->source->data.nix.path) {
+ chr->source->data.nix.listen = true;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainVsockDefPostParse(virDomainVsockDef *vsock)
+{
+ if (vsock->model == VIR_DOMAIN_VSOCK_MODEL_DEFAULT)
+ vsock->model = VIR_DOMAIN_VSOCK_MODEL_VIRTIO;
+
+ return 0;
+}
+
+
+/**
+ * qemuDomainDeviceHostdevDefPostParseRestoreSecAlias:
+ *
+ * Re-generate aliases for objects related to the storage source if they
+ * were not stored in the status XML by an older libvirt.
+ *
+ * Note that qemuCaps should be always present for a status XML.
+ */
+static int
+qemuDomainDeviceHostdevDefPostParseRestoreSecAlias(virDomainHostdevDef *hostdev,
+ unsigned int parseFlags)
+{
+ qemuDomainStorageSourcePrivate *priv;
+ virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
+ virDomainHostdevSubsysSCSIiSCSI *iscsisrc = &scsisrc->u.iscsi;
+ g_autofree char *authalias = NULL;
+
+ if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS))
+ return 0;
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+ hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI ||
+ scsisrc->protocol != VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI ||
+ !iscsisrc->src->auth)
+ return 0;
+
+ if (!(priv = qemuDomainStorageSourcePrivateFetch(iscsisrc->src)))
+ return -1;
+
+ if (priv->secinfo)
+ return 0;
+
+ authalias = g_strdup_printf("%s-secret0", hostdev->info->alias);
+
+ if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->secinfo, &authalias) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+/**
+ * qemuDomainDeviceHostdevDefPostParseRestoreBackendAlias:
+ *
+ * Re-generate backend alias if it wasn't stored in the status XML by an older
+ * libvirtd.
+ *
+ * Note that qemuCaps should be always present for a status XML.
+ */
+static int
+qemuDomainDeviceHostdevDefPostParseRestoreBackendAlias(virDomainHostdevDef *hostdev,
+ unsigned int parseFlags)
+{
+ virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
+ virStorageSource *src;
+
+ if (!(parseFlags & VIR_DOMAIN_DEF_PARSE_STATUS))
+ return 0;
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+ hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
+ return 0;
+
+ switch (scsisrc->protocol) {
+ case VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_NONE:
+ if (!scsisrc->u.host.src)
+ scsisrc->u.host.src = virStorageSourceNew();
+
+ src = scsisrc->u.host.src;
+ break;
+
+ case VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI:
+ src = scsisrc->u.iscsi.src;
+ break;
+
+ case VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_LAST:
+ default:
+ virReportEnumRangeError(virDomainHostdevSCSIProtocolType, scsisrc->protocol);
+ return -1;
+ }
+
+ if (!qemuBlockStorageSourceGetStorageNodename(src))
+ qemuBlockStorageSourceSetStorageNodename(src, g_strdup_printf("libvirt-%s-backend", hostdev->info->alias));
+
+ return 0;
+}
+
+
+static int
+qemuDomainHostdevDefMdevPostParse(virDomainHostdevSubsysMediatedDev *mdevsrc)
+{
+ /* QEMU 2.12 added support for vfio-pci display type, we default to
+ * 'display=off' to stay safe from future changes */
+ if (mdevsrc->model == VIR_MDEV_MODEL_TYPE_VFIO_PCI &&
+ mdevsrc->display == VIR_TRISTATE_SWITCH_ABSENT)
+ mdevsrc->display = VIR_TRISTATE_SWITCH_OFF;
+
+ return 0;
+}
+
+
+static int
+qemuDomainHostdevDefPostParse(virDomainHostdevDef *hostdev,
+ unsigned int parseFlags)
+{
+ virDomainHostdevSubsys *subsys = &hostdev->source.subsys;
+
+ if (qemuDomainDeviceHostdevDefPostParseRestoreSecAlias(hostdev, parseFlags) < 0)
+ return -1;
+
+ if (qemuDomainDeviceHostdevDefPostParseRestoreBackendAlias(hostdev, parseFlags) < 0)
+ return -1;
+
+ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV &&
+ qemuDomainHostdevDefMdevPostParse(&subsys->u.mdev) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+qemuDomainTPMDefPostParse(virDomainTPMDef *tpm,
+ const virDomainDef *def)
+{
+ if (tpm->model == VIR_DOMAIN_TPM_MODEL_DEFAULT) {
+ if (ARCH_IS_PPC64(def->os.arch))
+ tpm->model = VIR_DOMAIN_TPM_MODEL_SPAPR;
+ else
+ tpm->model = VIR_DOMAIN_TPM_MODEL_TIS;
+ }
+
+ /* TPM 1.2 and 2 are not compatible, so we choose a specific version here */
+ if (tpm->type == VIR_DOMAIN_TPM_TYPE_EMULATOR &&
+ tpm->data.emulator.version == VIR_DOMAIN_TPM_VERSION_DEFAULT) {
+ /* tpm-tis on x86 defaults to TPM 1.2 to preserve the
+ * historical behavior, but in all other scenarios we want
+ * TPM 2.0 instead */
+ if (tpm->model == VIR_DOMAIN_TPM_MODEL_TIS &&
+ ARCH_IS_X86(def->os.arch)) {
+ tpm->data.emulator.version = VIR_DOMAIN_TPM_VERSION_1_2;
+ } else {
+ tpm->data.emulator.version = VIR_DOMAIN_TPM_VERSION_2_0;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainMemoryDefPostParse(virDomainMemoryDef *mem, virArch arch,
+ unsigned int parseFlags)
+{
+ /* Memory alignment can't be done for migration or snapshot
+ * scenarios. This logic was defined by commit c7d7ba85a624.
+ *
+ * There is no easy way to replicate at this point the same conditions
+ * used to call qemuDomainAlignMemorySizes(), which means checking if
+ * we're not migrating and not in a snapshot.
+ *
+ * We can use the PARSE_ABI_UPDATE flag, which is more strict -
+ * existing guests will not activate the flag to avoid breaking
+ * boot ABI. This means that any alignment done here will be replicated
+ * later on by qemuDomainAlignMemorySizes() to contemplate existing
+ * guests as well. */
+ if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE) {
+ if (ARCH_IS_PPC64(arch)) {
+ unsigned long long ppc64MemModuleAlign = 256 * 1024;
+
+ if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
+ if (qemuDomainNVDimmAlignSizePseries(mem) < 0)
+ return -1;
+ } else {
+ mem->size = VIR_ROUND_UP(mem->size, ppc64MemModuleAlign);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainPstoreDefPostParse(virDomainPstoreDef *pstore,
+ const virDomainDef *def,
+ virQEMUDriver *driver)
+{
+ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+
+ switch (pstore->backend) {
+ case VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST:
+ if (!pstore->path)
+ pstore->path = g_strdup_printf("%s/%s_PSTORE.raw",
+ cfg->nvramDir, def->name);
+ break;
+
+ case VIR_DOMAIN_PSTORE_BACKEND_LAST:
+ break;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainIOMMUDefPostParse(virDomainIOMMUDef *iommu,
+ const virDomainDef *def,
+ virQEMUCaps *qemuCaps,
+ unsigned int parseFlags)
+{
+ /* In case domain has huge number of vCPUS and Extended Interrupt Mode
+ * (EIM) is not explicitly turned off, let's enable it. If we didn't then
+ * guest will have troubles with interrupts. */
+ if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE &&
+ ARCH_IS_X86(def->os.arch) &&
+ virDomainDefGetVcpusMax(def) > QEMU_MAX_VCPUS_WITHOUT_EIM &&
+ qemuDomainIsQ35(def) &&
+ iommu && iommu->model == VIR_DOMAIN_IOMMU_MODEL_INTEL) {
+
+ /* eim requires intremap. */
+ if (iommu->intremap == VIR_TRISTATE_SWITCH_ABSENT &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_INTREMAP)) {
+ iommu->intremap = VIR_TRISTATE_SWITCH_ON;
+ }
+
+ if (iommu->eim == VIR_TRISTATE_SWITCH_ABSENT &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_EIM)) {
+ iommu->eim = VIR_TRISTATE_SWITCH_ON;
+ }
+ }
+
+ return 0;
+}
+
+
+int
+qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
+ const virDomainDef *def,
+ unsigned int parseFlags,
+ void *opaque,
+ void *parseOpaque)
+{
+ virQEMUDriver *driver = opaque;
+ /* Note that qemuCaps may be NULL when this function is called. This
+ * function shall not fail in that case. It will be re-run on VM startup
+ * with the capabilities populated. */
+ virQEMUCaps *qemuCaps = parseOpaque;
+ int ret = -1;
+
+ switch (dev->type) {
+ case VIR_DOMAIN_DEVICE_NET:
+ ret = qemuDomainDeviceNetDefPostParse(dev->data.net, def, qemuCaps);
+ break;
+
+ case VIR_DOMAIN_DEVICE_DISK:
+ ret = qemuDomainDeviceDiskDefPostParse(dev->data.disk, parseFlags);
+ break;
+
+ case VIR_DOMAIN_DEVICE_VIDEO:
+ ret = qemuDomainDeviceVideoDefPostParse(dev->data.video, def, qemuCaps);
+ break;
+
+ case VIR_DOMAIN_DEVICE_PANIC:
+ ret = qemuDomainDevicePanicDefPostParse(dev->data.panic, def);
+ break;
+
+ case VIR_DOMAIN_DEVICE_CONTROLLER:
+ ret = qemuDomainControllerDefPostParse(dev->data.controller, def,
+ qemuCaps, parseFlags);
+ break;
+
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ ret = qemuDomainShmemDefPostParse(dev->data.shmem);
+ break;
+
+ case VIR_DOMAIN_DEVICE_CHR:
+ ret = qemuDomainChrDefPostParse(dev->data.chr, def, driver, parseFlags);
+ break;
+
+ case VIR_DOMAIN_DEVICE_VSOCK:
+ ret = qemuDomainVsockDefPostParse(dev->data.vsock);
+ break;
+
+ case VIR_DOMAIN_DEVICE_HOSTDEV:
+ ret = qemuDomainHostdevDefPostParse(dev->data.hostdev, parseFlags);
+ break;
+
+ case VIR_DOMAIN_DEVICE_TPM:
+ ret = qemuDomainTPMDefPostParse(dev->data.tpm, def);
+ break;
+
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ ret = qemuDomainMemoryDefPostParse(dev->data.memory, def->os.arch,
+ parseFlags);
+ break;
+
+ case VIR_DOMAIN_DEVICE_PSTORE:
+ ret = qemuDomainPstoreDefPostParse(dev->data.pstore, def, driver);
+ break;
+
+ case VIR_DOMAIN_DEVICE_IOMMU:
+ ret = qemuDomainIOMMUDefPostParse(dev->data.iommu, def,
+ qemuCaps, parseFlags);
+ break;
+
+ case VIR_DOMAIN_DEVICE_LEASE:
+ case VIR_DOMAIN_DEVICE_FS:
+ case VIR_DOMAIN_DEVICE_INPUT:
+ case VIR_DOMAIN_DEVICE_SOUND:
+ case VIR_DOMAIN_DEVICE_WATCHDOG:
+ case VIR_DOMAIN_DEVICE_GRAPHICS:
+ case VIR_DOMAIN_DEVICE_HUB:
+ case VIR_DOMAIN_DEVICE_REDIRDEV:
+ case VIR_DOMAIN_DEVICE_SMARTCARD:
+ case VIR_DOMAIN_DEVICE_MEMBALLOON:
+ case VIR_DOMAIN_DEVICE_NVRAM:
+ case VIR_DOMAIN_DEVICE_RNG:
+ case VIR_DOMAIN_DEVICE_AUDIO:
+ case VIR_DOMAIN_DEVICE_CRYPTO:
+ ret = 0;
+ break;
+
+ case VIR_DOMAIN_DEVICE_NONE:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected VIR_DOMAIN_DEVICE_NONE"));
+ break;
+
+ case VIR_DOMAIN_DEVICE_LAST:
+ default:
+ virReportEnumRangeError(virDomainDeviceType, dev->type);
+ break;
+ }
+
+ return ret;
+}
+
+
+int
+qemuDomainDefPostParseBasic(virDomainDef *def,
+ void *opaque G_GNUC_UNUSED)
+{
+ virQEMUDriver *driver = opaque;
+
+ /* check for emulator and create a default one if needed */
+ if (!def->emulator) {
+ if (!(def->emulator = virQEMUCapsGetDefaultEmulator(
+ driver->hostarch, def->os.arch))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("No emulator found for arch '%1$s'"),
+ virArchToString(def->os.arch));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+qemuCanonicalizeMachine(virDomainDef *def, virQEMUCaps *qemuCaps)
+{
+ const char *canon;
+
+ if (!(canon = virQEMUCapsGetCanonicalMachine(qemuCaps, def->virtType,
+ def->os.machine)))
+ return 0;
+
+ if (STRNEQ(canon, def->os.machine)) {
+ char *tmp;
+ tmp = g_strdup(canon);
+ VIR_FREE(def->os.machine);
+ def->os.machine = tmp;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefMachinePostParse(virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ if (!def->os.machine) {
+ const char *machine = virQEMUCapsGetPreferredMachine(qemuCaps,
+ def->virtType);
+ if (!machine) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("could not get preferred machine for %1$s type=%2$s"),
+ def->emulator,
+ virDomainVirtTypeToString(def->virtType));
+ return -1;
+ }
+
+ def->os.machine = g_strdup(machine);
+ }
+
+ if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+/**
+ * qemuDomainDefACPIPostParse:
+ * @def: domain definition
+ * @qemuCaps: qemu capabilities object
+ *
+ * Fixup the use of ACPI flag on certain architectures that never supported it
+ * and users for some reason used it, which would break migration to newer
+ * libvirt versions which check whether given machine type supports ACPI.
+ *
+ * The fixup is done in post-parse as it's hard to update the ABI stability
+ * check on source of the migration.
+ */
+static void
+qemuDomainDefACPIPostParse(virDomainDef *def,
+ virQEMUCaps *qemuCaps,
+ unsigned int parseFlags)
+{
+ /* Only cases when ACPI is enabled need to be fixed up */
+ if (def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON)
+ return;
+
+ /* Strip the <acpi/> feature only for non-fresh configs, in order to still
+ * produce an error if the feature is present in a newly defined one.
+ *
+ * The use of the VIR_DOMAIN_DEF_PARSE_ABI_UPDATE looks counter-intuitive,
+ * but it's used only in qemuDomainCreateXML/qemuDomainDefineXMLFlags APIs
+ * */
+ if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE)
+ return;
+
+ /* This fixup is applicable _only_ on architectures which were present as of
+ * libvirt-9.2 and *never* supported ACPI. The fixup is currently done only
+ * for existing users of s390(x) to fix migration for configs which had
+ * <acpi/> despite being ignored.
+ */
+ if (def->os.arch != VIR_ARCH_S390 &&
+ def->os.arch != VIR_ARCH_S390X)
+ return;
+
+ /* To be sure, we only strip ACPI if given machine type doesn't support it */
+ if (virQEMUCapsMachineSupportsACPI(qemuCaps, def->virtType, def->os.machine) != VIR_TRISTATE_BOOL_NO)
+ return;
+
+ def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ABSENT;
+}
+
+
+static int
+qemuDomainDefBootPostParse(virDomainDef *def,
+ virQEMUDriver *driver,
+ unsigned int parseFlags)
+{
+ bool abiUpdate = !!(parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE);
+
+ /* If we're loading an existing configuration from disk, we
+ * should try as hard as possible to preserve historical
+ * behavior. In particular, firmware autoselection being enabled
+ * could never have resulted, before libvirt 9.2.0, in anything
+ * but a raw firmware image being selected.
+ *
+ * In order to ensure that existing domains keep working even if
+ * a firmware descriptor for a build with a different format is
+ * given higher priority, explicitly add this requirement to the
+ * definition before performing firmware selection */
+ if (!abiUpdate && def->os.firmware) {
+ if (!def->os.loader)
+ def->os.loader = virDomainLoaderDefNew();
+ if (!def->os.loader->format)
+ def->os.loader->format = VIR_STORAGE_FILE_RAW;
+ }
+
+ /* Firmware selection can fail for a number of reasons, but the
+ * most likely one is that the requested configuration contains
+ * mistakes or includes constraints that are impossible to
+ * satisfy on the current system.
+ *
+ * If that happens, we have to react differently based on the
+ * situation: if we're defining a new domain or updating its ABI,
+ * we should let the user know immediately so that they can
+ * change the requested configuration, hopefully into one that we
+ * can work with; if we're loading the configuration of an
+ * existing domain from disk, however, we absolutely cannot error
+ * out here, or the domain will disappear.
+ *
+ * To handle the second case gracefully, we clear any reported
+ * errors and continue as if nothing had happened. When it's time
+ * to start the domain, qemuFirmwareFillDomain() will be run
+ * again, fail in the same way, and at that point we'll have a
+ * chance to inform the user of any issues */
+ if (qemuFirmwareFillDomain(driver, def, abiUpdate) < 0) {
+ if (abiUpdate) {
+ return -1;
+ } else {
+ virResetLastError();
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefAddImplicitInputDevice(virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ if (virQEMUCapsSupportsI8042(qemuCaps, def) &&
+ def->features[VIR_DOMAIN_FEATURE_PS2] != VIR_TRISTATE_SWITCH_OFF) {
+ if (virDomainDefMaybeAddInput(def,
+ VIR_DOMAIN_INPUT_TYPE_MOUSE,
+ VIR_DOMAIN_INPUT_BUS_PS2) < 0)
+ return -1;
+
+ if (virDomainDefMaybeAddInput(def,
+ VIR_DOMAIN_INPUT_TYPE_KBD,
+ VIR_DOMAIN_INPUT_BUS_PS2) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefSetDefaultCPU(virDomainDef *def,
+ virArch hostarch,
+ virQEMUCaps *qemuCaps)
+{
+ const char *model;
+
+ if (def->cpu &&
+ (def->cpu->mode != VIR_CPU_MODE_CUSTOM ||
+ def->cpu->model))
+ return 0;
+
+ if (!virCPUArchIsSupported(def->os.arch))
+ return 0;
+
+ /* Default CPU model info from QEMU is usable for TCG only except for
+ * x86, s390, and ppc64. */
+ if (!ARCH_IS_X86(def->os.arch) &&
+ !ARCH_IS_S390(def->os.arch) &&
+ !ARCH_IS_PPC64(def->os.arch) &&
+ def->virtType != VIR_DOMAIN_VIRT_QEMU)
+ return 0;
+
+ model = virQEMUCapsGetMachineDefaultCPU(qemuCaps, def->os.machine, def->virtType);
+ if (!model) {
+ VIR_DEBUG("Unknown default CPU model for domain '%s'", def->name);
+ return 0;
+ }
+
+ if (STREQ(model, "host") && def->virtType != VIR_DOMAIN_VIRT_KVM) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("QEMU reports invalid default CPU model \"host\" for non-kvm domain virt type"));
+ return -1;
+ }
+
+ if (!def->cpu)
+ def->cpu = virCPUDefNew();
+
+ def->cpu->type = VIR_CPU_TYPE_GUEST;
+
+ if (STREQ(model, "host")) {
+ if (ARCH_IS_S390(def->os.arch) &&
+ virQEMUCapsIsCPUModeSupported(qemuCaps, hostarch, def->virtType,
+ VIR_CPU_MODE_HOST_MODEL,
+ def->os.machine)) {
+ def->cpu->mode = VIR_CPU_MODE_HOST_MODEL;
+ } else {
+ def->cpu->mode = VIR_CPU_MODE_HOST_PASSTHROUGH;
+ }
+
+ VIR_DEBUG("Setting default CPU mode for domain '%s' to %s",
+ def->name, virCPUModeTypeToString(def->cpu->mode));
+ } else {
+ /* We need to turn off all CPU checks when the domain is started
+ * because the default CPU (e.g., qemu64) may not be runnable on any
+ * host. QEMU will just disable the unavailable features and we will
+ * update the CPU definition accordingly and set check to FULL when
+ * starting the domain. */
+ def->cpu->check = VIR_CPU_CHECK_NONE;
+ def->cpu->mode = VIR_CPU_MODE_CUSTOM;
+ def->cpu->match = VIR_CPU_MATCH_EXACT;
+ def->cpu->fallback = VIR_CPU_FALLBACK_FORBID;
+ def->cpu->model = g_strdup(model);
+
+ VIR_DEBUG("Setting default CPU model for domain '%s' to %s",
+ def->name, model);
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefAddDefaultDevices(virQEMUDriver *driver,
+ virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ bool addDefaultUSB = false;
+ int usbModel = -1; /* "default for machinetype" */
+ int pciRoot; /* index within def->controllers */
+ bool addImplicitSATA = false;
+ bool addPCIRoot = false;
+ bool addPCIeRoot = false;
+ bool addDefaultMemballoon = false;
+ bool addDefaultUSBKBD = false;
+ bool addDefaultUSBMouse = false;
+ bool addPanicDevice = false;
+ bool addITCOWatchdog = false;
+ bool addIOMMU = false;
+
+ /* add implicit input devices */
+ if (qemuDomainDefAddImplicitInputDevice(def, qemuCaps) < 0)
+ return -1;
+
+ /* Add implicit PCI root controller if the machine has one */
+ switch (def->os.arch) {
+ case VIR_ARCH_I686:
+ case VIR_ARCH_X86_64:
+ addDefaultMemballoon = true;
+
+ if (STREQ(def->os.machine, "isapc")) {
+ break;
+ }
+
+ addDefaultUSB = true;
+
+ if (qemuDomainIsQ35(def)) {
+ addPCIeRoot = true;
+ addImplicitSATA = true;
+ addITCOWatchdog = true;
+
+ if (virDomainDefGetVcpusMax(def) > QEMU_MAX_VCPUS_WITHOUT_EIM) {
+ addIOMMU = true;
+ }
+
+ /* Prefer adding a USB3 controller if supported, fall back
+ * to USB2 if there is no USB3 available, and if that's
+ * unavailable don't add anything.
+ */
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QEMU_XHCI))
+ usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_QEMU_XHCI;
+ else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI))
+ usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI;
+ else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_USB_EHCI1))
+ usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1;
+ else
+ addDefaultUSB = false;
+ break;
+ }
+ if (qemuDomainIsI440FX(def))
+ addPCIRoot = true;
+ break;
+
+ case VIR_ARCH_ARMV6L:
+ case VIR_ARCH_ARMV7L:
+ case VIR_ARCH_ARMV7B:
+ case VIR_ARCH_AARCH64:
+ if (STREQ(def->os.machine, "versatilepb"))
+ addPCIRoot = true;
+
+ /* Add default USB for the two machine types which historically
+ * supported -usb */
+ if (STREQ(def->os.machine, "versatilepb") ||
+ STRPREFIX(def->os.machine, "realview")) {
+ addDefaultUSB = true;
+ usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
+ }
+
+ if (qemuDomainIsARMVirt(def))
+ addPCIeRoot = true;
+
+ break;
+
+ case VIR_ARCH_PPC64:
+ case VIR_ARCH_PPC64LE:
+ addPCIRoot = true;
+ addDefaultUSB = true;
+ addDefaultUSBKBD = true;
+ addDefaultUSBMouse = true;
+ addDefaultMemballoon = true;
+ /* For pSeries guests, the firmware provides the same
+ * functionality as the pvpanic device, so automatically
+ * add the definition if not already present */
+ if (qemuDomainIsPSeries(def))
+ addPanicDevice = true;
+ break;
+
+ case VIR_ARCH_ALPHA:
+ case VIR_ARCH_PPC:
+ case VIR_ARCH_PPCEMB:
+ case VIR_ARCH_SH4:
+ case VIR_ARCH_SH4EB:
+ addDefaultUSB = true;
+ addDefaultMemballoon = true;
+ addPCIRoot = true;
+ break;
+
+ case VIR_ARCH_RISCV32:
+ case VIR_ARCH_RISCV64:
+ addDefaultMemballoon = true;
+ if (qemuDomainIsRISCVVirt(def))
+ addPCIeRoot = true;
+ break;
+
+ case VIR_ARCH_S390:
+ case VIR_ARCH_S390X:
+ addDefaultMemballoon = true;
+ addPanicDevice = true;
+ addPCIRoot = virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ZPCI);
+ break;
+
+ case VIR_ARCH_SPARC64:
+ addDefaultUSB = true;
+ addDefaultMemballoon = true;
+ addPCIRoot = true;
+ break;
+
+ case VIR_ARCH_MIPS:
+ case VIR_ARCH_MIPSEL:
+ case VIR_ARCH_MIPS64:
+ case VIR_ARCH_MIPS64EL:
+ addDefaultUSB = true;
+ addDefaultMemballoon = true;
+ if (qemuDomainIsMipsMalta(def))
+ addPCIRoot = true;
+ break;
+
+ case VIR_ARCH_LOONGARCH64:
+ addPCIeRoot = true;
+ break;
+
+ case VIR_ARCH_CRIS:
+ case VIR_ARCH_ITANIUM:
+ case VIR_ARCH_LM32:
+ case VIR_ARCH_M68K:
+ case VIR_ARCH_MICROBLAZE:
+ case VIR_ARCH_MICROBLAZEEL:
+ case VIR_ARCH_OR32:
+ case VIR_ARCH_PARISC:
+ case VIR_ARCH_PARISC64:
+ case VIR_ARCH_PPCLE:
+ case VIR_ARCH_SPARC:
+ case VIR_ARCH_UNICORE32:
+ case VIR_ARCH_XTENSA:
+ case VIR_ARCH_XTENSAEB:
+ case VIR_ARCH_NONE:
+ case VIR_ARCH_LAST:
+ default:
+ break;
+ }
+
+ if (addDefaultUSB &&
+ virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_USB, 0) < 0 &&
+ virDomainDefAddUSBController(def, 0, usbModel) < 0)
+ return -1;
+
+ if (addImplicitSATA &&
+ virDomainDefMaybeAddController(
+ def, VIR_DOMAIN_CONTROLLER_TYPE_SATA, 0, -1) < 0)
+ return -1;
+
+ pciRoot = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0);
+
+ /* NB: any machine that sets addPCIRoot to true must also return
+ * true from the function qemuDomainSupportsPCI().
+ */
+ if (addPCIRoot) {
+ if (pciRoot >= 0) {
+ if (def->controllers[pciRoot]->model != VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("The PCI controller with index='0' must be model='pci-root' for this machine type, but model='%1$s' was found instead"),
+ virDomainControllerModelPCITypeToString(def->controllers[pciRoot]->model));
+ return -1;
+ }
+ } else if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)) {
+ return -1;
+ }
+ }
+
+ /* When a machine has a pcie-root, make sure that there is always
+ * a dmi-to-pci-bridge controller added as bus 1, and a pci-bridge
+ * as bus 2, so that standard PCI devices can be connected
+ *
+ * NB: any machine that sets addPCIeRoot to true must also return
+ * true from the function qemuDomainSupportsPCI().
+ */
+ if (addPCIeRoot) {
+ if (pciRoot >= 0) {
+ if (def->controllers[pciRoot]->model != VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("The PCI controller with index='0' must be model='pcie-root' for this machine type, but model='%1$s' was found instead"),
+ virDomainControllerModelPCITypeToString(def->controllers[pciRoot]->model));
+ return -1;
+ }
+ } else if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
+ VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)) {
+ return -1;
+ }
+ }
+
+ if (addDefaultMemballoon && !def->memballoon) {
+ virDomainMemballoonDef *memballoon;
+ memballoon = g_new0(virDomainMemballoonDef, 1);
+
+ memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
+ def->memballoon = memballoon;
+ }
+
+ if (addDefaultUSBMouse) {
+ bool hasUSBTablet = false;
+ size_t j;
+
+ for (j = 0; j < def->ninputs; j++) {
+ if (def->inputs[j]->type == VIR_DOMAIN_INPUT_TYPE_TABLET &&
+ def->inputs[j]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
+ hasUSBTablet = true;
+ break;
+ }
+ }
+
+ /* Historically, we have automatically added USB keyboard and
+ * mouse to some guests. While the former device is generally
+ * safe to have, adding the latter is undesiderable if a USB
+ * tablet is already present in the guest */
+ if (hasUSBTablet)
+ addDefaultUSBMouse = false;
+ }
+
+ if (addDefaultUSBKBD &&
+ def->ngraphics > 0 &&
+ virDomainDefMaybeAddInput(def,
+ VIR_DOMAIN_INPUT_TYPE_KBD,
+ VIR_DOMAIN_INPUT_BUS_USB) < 0)
+ return -1;
+
+ if (addDefaultUSBMouse &&
+ def->ngraphics > 0 &&
+ virDomainDefMaybeAddInput(def,
+ VIR_DOMAIN_INPUT_TYPE_MOUSE,
+ VIR_DOMAIN_INPUT_BUS_USB) < 0)
+ return -1;
+
+ if (addPanicDevice) {
+ virDomainPanicModel defaultModel = qemuDomainDefaultPanicModel(def);
+ size_t j;
+
+ for (j = 0; j < def->npanics; j++) {
+ if (def->panics[j]->model == VIR_DOMAIN_PANIC_MODEL_DEFAULT ||
+ def->panics[j]->model == defaultModel)
+ break;
+ }
+
+ if (j == def->npanics) {
+ virDomainPanicDef *panic = g_new0(virDomainPanicDef, 1);
+
+ VIR_APPEND_ELEMENT_COPY(def->panics, def->npanics, panic);
+ }
+ }
+
+ if (addITCOWatchdog) {
+ size_t i = 0;
+
+ for (i = 0; i < def->nwatchdogs; i++) {
+ if (def->watchdogs[i]->model == VIR_DOMAIN_WATCHDOG_MODEL_ITCO)
+ break;
+ }
+
+ if (i == def->nwatchdogs) {
+ virDomainWatchdogDef *watchdog = g_new0(virDomainWatchdogDef, 1);
+
+ watchdog->model = VIR_DOMAIN_WATCHDOG_MODEL_ITCO;
+ if (def->nwatchdogs)
+ watchdog->action = def->watchdogs[0]->action;
+ else
+ watchdog->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
+
+ VIR_APPEND_ELEMENT(def->watchdogs, def->nwatchdogs, watchdog);
+ }
+ }
+
+ if (addIOMMU && !def->iommu &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_INTEL_IOMMU) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_INTREMAP) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_EIM)) {
+ g_autoptr(virDomainIOMMUDef) iommu = NULL;
+
+ iommu = virDomainIOMMUDefNew();
+ iommu->model = VIR_DOMAIN_IOMMU_MODEL_INTEL;
+ /* eim requires intremap. */
+ iommu->intremap = VIR_TRISTATE_SWITCH_ON;
+ iommu->eim = VIR_TRISTATE_SWITCH_ON;
+
+ def->iommu = g_steal_pointer(&iommu);
+ }
+
+ if (qemuDomainDefAddDefaultAudioBackend(driver, def) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+/**
+ * qemuDomainDefEnableDefaultFeatures:
+ * @def: domain definition
+ * @qemuCaps: QEMU capabilities
+ *
+ * Make sure that features that should be enabled by default are actually
+ * enabled and configure default values related to those features.
+ */
+static void
+qemuDomainDefEnableDefaultFeatures(virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ /* The virt machine type always uses GIC: if the relevant information
+ * was not included in the domain XML, we need to choose a suitable
+ * GIC version ourselves */
+ if ((def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ABSENT &&
+ qemuDomainIsARMVirt(def)) ||
+ (def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ON &&
+ def->gic_version == VIR_GIC_VERSION_NONE)) {
+ virGICVersion version;
+
+ VIR_DEBUG("Looking for usable GIC version in domain capabilities");
+ for (version = VIR_GIC_VERSION_LAST - 1;
+ version > VIR_GIC_VERSION_NONE;
+ version--) {
+
+ /* We want to use the highest available GIC version for guests;
+ * however, the emulated GICv3 is currently lacking a MSI controller,
+ * making it unsuitable for the pure PCIe topology we aim for.
+ *
+ * For that reason, we skip this step entirely for TCG guests,
+ * and rely on the code below to pick the default version, GICv2,
+ * which supports all the features we need.
+ *
+ * See https://bugzilla.redhat.com/show_bug.cgi?id=1414081 */
+ if (version == VIR_GIC_VERSION_3 &&
+ def->virtType == VIR_DOMAIN_VIRT_QEMU) {
+ continue;
+ }
+
+ if (virQEMUCapsSupportsGICVersion(qemuCaps,
+ def->virtType,
+ version)) {
+ VIR_DEBUG("Using GIC version %s",
+ virGICVersionTypeToString(version));
+ def->gic_version = version;
+ break;
+ }
+ }
+
+ /* Use the default GIC version (GICv2) as a last-ditch attempt
+ * if no match could be found above */
+ if (def->gic_version == VIR_GIC_VERSION_NONE) {
+ VIR_DEBUG("Using GIC version 2 (default)");
+ def->gic_version = VIR_GIC_VERSION_2;
+ }
+
+ /* Even if we haven't found a usable GIC version in the domain
+ * capabilities, we still want to enable this */
+ def->features[VIR_DOMAIN_FEATURE_GIC] = VIR_TRISTATE_SWITCH_ON;
+ }
+}
+
+
+static int
+qemuDomainRecheckInternalPaths(virDomainDef *def,
+ virQEMUDriverConfig *cfg,
+ unsigned int flags)
+{
+ size_t i = 0;
+ size_t j = 0;
+
+ for (i = 0; i < def->ngraphics; ++i) {
+ virDomainGraphicsDef *graphics = def->graphics[i];
+
+ for (j = 0; j < graphics->nListens; ++j) {
+ virDomainGraphicsListenDef *glisten = &graphics->listens[j];
+
+ /* This will happen only if we parse XML from old libvirts where
+ * unix socket was available only for VNC graphics. In this
+ * particular case we should follow the behavior and if we remove
+ * the auto-generated socket based on config option from qemu.conf
+ * we need to change the listen type to address. */
+ if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+ glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET &&
+ glisten->socket &&
+ !glisten->autoGenerated &&
+ STRPREFIX(glisten->socket, cfg->libDir)) {
+ if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
+ VIR_FREE(glisten->socket);
+ glisten->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;
+ } else {
+ glisten->fromConfig = true;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefVcpusPostParse(virDomainDef *def)
+{
+ unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
+ virDomainVcpuDef *vcpu;
+ virDomainVcpuDef *prevvcpu;
+ size_t i;
+ bool has_order = false;
+
+ /* vcpu 0 needs to be present, first, and non-hotpluggable */
+ vcpu = virDomainDefGetVcpu(def, 0);
+ if (!vcpu->online) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("vcpu 0 can't be offline"));
+ return -1;
+ }
+ if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("vcpu0 can't be hotpluggable"));
+ return -1;
+ }
+ if (vcpu->order != 0 && vcpu->order != 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("vcpu0 must be enabled first"));
+ return -1;
+ }
+
+ if (vcpu->order != 0)
+ has_order = true;
+
+ prevvcpu = vcpu;
+
+ /* all online vcpus or non online vcpu need to have order set */
+ for (i = 1; i < maxvcpus; i++) {
+ vcpu = virDomainDefGetVcpu(def, i);
+
+ if (vcpu->online &&
+ (vcpu->order != 0) != has_order) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("all vcpus must have either set or unset order"));
+ return -1;
+ }
+
+ /* few conditions for non-hotpluggable (thus online) vcpus */
+ if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_NO) {
+ /* they can be ordered only at the beginning */
+ if (prevvcpu->hotpluggable == VIR_TRISTATE_BOOL_YES) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("online non-hotpluggable vcpus need to be ordered prior to hotplugable vcpus"));
+ return -1;
+ }
+
+ /* they need to be in order (qemu doesn't support any order yet).
+ * Also note that multiple vcpus may share order on some platforms */
+ if (prevvcpu->order > vcpu->order) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("online non-hotpluggable vcpus must be ordered in ascending order"));
+ return -1;
+ }
+ }
+
+ prevvcpu = vcpu;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefCPUPostParse(virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ virCPUFeatureDef *sveFeature = NULL;
+ bool sveVectorLengthsProvided = false;
+ size_t i;
+
+ if (!def->cpu)
+ return 0;
+
+ for (i = 0; i < def->cpu->nfeatures; i++) {
+ virCPUFeatureDef *feature = &def->cpu->features[i];
+
+ if (STREQ(feature->name, "sve")) {
+ sveFeature = feature;
+ } else if (STRPREFIX(feature->name, "sve")) {
+ sveVectorLengthsProvided = true;
+ }
+ }
+
+ if (sveVectorLengthsProvided) {
+ if (sveFeature) {
+ if (sveFeature->policy == VIR_CPU_FEATURE_DISABLE ||
+ sveFeature->policy == VIR_CPU_FEATURE_FORBID) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("SVE disabled, but SVE vector lengths provided"));
+ return -1;
+ } else {
+ sveFeature->policy = VIR_CPU_FEATURE_REQUIRE;
+ }
+ } else {
+ VIR_RESIZE_N(def->cpu->features, def->cpu->nfeatures_max,
+ def->cpu->nfeatures, 1);
+
+ def->cpu->features[def->cpu->nfeatures].name = g_strdup("sve");
+ def->cpu->features[def->cpu->nfeatures].policy = VIR_CPU_FEATURE_REQUIRE;
+
+ def->cpu->nfeatures++;
+ }
+ }
+
+ /* Running domains were either started before QEMU_CAPS_CPU_MIGRATABLE was
+ * introduced and thus we can't rely on it or they already have the
+ * migratable default set. */
+ if (def->id == -1 &&
+ qemuCaps &&
+ def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH &&
+ def->cpu->migratable == VIR_TRISTATE_SWITCH_ABSENT) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_MIGRATABLE))
+ def->cpu->migratable = VIR_TRISTATE_SWITCH_ON;
+ else if (ARCH_IS_X86(def->os.arch))
+ def->cpu->migratable = VIR_TRISTATE_SWITCH_OFF;
+ }
+
+ /* Nothing to be done if only CPU topology is specified. */
+ if (def->cpu->mode == VIR_CPU_MODE_CUSTOM &&
+ !def->cpu->model)
+ return 0;
+
+ if (def->cpu->check != VIR_CPU_CHECK_DEFAULT)
+ return 0;
+
+ switch ((virCPUMode) def->cpu->mode) {
+ case VIR_CPU_MODE_HOST_PASSTHROUGH:
+ case VIR_CPU_MODE_MAXIMUM:
+ def->cpu->check = VIR_CPU_CHECK_NONE;
+ break;
+
+ case VIR_CPU_MODE_HOST_MODEL:
+ def->cpu->check = VIR_CPU_CHECK_PARTIAL;
+ break;
+
+ case VIR_CPU_MODE_CUSTOM:
+ /* Custom CPUs in TCG mode are not compared to host CPU by default. */
+ if (def->virtType == VIR_DOMAIN_VIRT_QEMU)
+ def->cpu->check = VIR_CPU_CHECK_NONE;
+ else
+ def->cpu->check = VIR_CPU_CHECK_PARTIAL;
+ break;
+
+ case VIR_CPU_MODE_LAST:
+ break;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefTsegPostParse(virDomainDef *def,
+ virQEMUCaps *qemuCaps)
+{
+ if (def->features[VIR_DOMAIN_FEATURE_SMM] != VIR_TRISTATE_SWITCH_ON)
+ return 0;
+
+ if (!def->tseg_specified)
+ return 0;
+
+ if (!qemuDomainIsQ35(def)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("SMM TSEG is only supported with q35 machine type"));
+ return -1;
+ }
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MCH_EXTENDED_TSEG_MBYTES)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Setting TSEG size is not supported with this QEMU binary"));
+ return -1;
+ }
+
+ if (def->tseg_size & ((1 << 20) - 1)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("SMM TSEG size must be divisible by 1 MiB"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefNumaAutoAdd(virDomainDef *def,
+ unsigned int parseFlags)
+{
+ bool abiUpdate = !!(parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE);
+ unsigned long long nodeMem;
+ size_t i;
+
+ if (!abiUpdate ||
+ !virDomainDefHasMemoryHotplug(def) ||
+ virDomainNumaGetNodeCount(def->numa) > 0) {
+ return 0;
+ }
+
+ nodeMem = virDomainDefGetMemoryTotal(def);
+
+ if (!def->numa)
+ def->numa = virDomainNumaNew();
+
+ virDomainNumaSetNodeCount(def->numa, 1);
+
+ for (i = 0; i < def->nmems; i++) {
+ virDomainMemoryDef *mem = def->mems[i];
+
+ if (mem->size > nodeMem) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Total size of memory devices exceeds the total memory size"));
+ return -1;
+ }
+
+ nodeMem -= mem->size;
+
+ switch (mem->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+ case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+ if (mem->targetNode == -1)
+ mem->targetNode = 0;
+ break;
+
+ case VIR_DOMAIN_MEMORY_MODEL_NONE:
+ case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+ case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+ case VIR_DOMAIN_MEMORY_MODEL_LAST:
+ break;
+ }
+ }
+
+ virDomainNumaSetNodeMemorySize(def->numa, 0, nodeMem);
+
+ return 0;
+}
+
+
+static int
+qemuDomainDefNumaCPUsPostParse(virDomainDef *def,
+ virQEMUCaps *qemuCaps,
+ unsigned int parseFlags)
+{
+ if (qemuDomainDefNumaAutoAdd(def, parseFlags) < 0)
+ return -1;
+
+ return qemuDomainDefNumaCPUsRectify(def, qemuCaps);
+}
+
+
+int
+qemuDomainDefPostParse(virDomainDef *def,
+ unsigned int parseFlags,
+ void *opaque,
+ void *parseOpaque)
+{
+ virQEMUDriver *driver = opaque;
+ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+ virQEMUCaps *qemuCaps = parseOpaque;
+
+ /* Note that qemuCaps may be NULL when this function is called. This
+ * function shall not fail in that case. It will be re-run on VM startup
+ * with the capabilities populated.
+ */
+ if (!qemuCaps)
+ return 1;
+
+ if (qemuDomainDefMachinePostParse(def, qemuCaps) < 0)
+ return -1;
+
+ qemuDomainDefACPIPostParse(def, qemuCaps, parseFlags);
+
+ if (qemuDomainDefBootPostParse(def, driver, parseFlags) < 0)
+ return -1;
+
+ if (qemuDomainDefAddDefaultDevices(driver, def, qemuCaps) < 0)
+ return -1;
+
+ if (qemuDomainDefSetDefaultCPU(def, driver->hostarch, qemuCaps) < 0)
+ return -1;
+
+ qemuDomainDefEnableDefaultFeatures(def, qemuCaps);
+
+ if (qemuDomainRecheckInternalPaths(def, cfg, parseFlags) < 0)
+ return -1;
+
+ if (qemuSecurityVerify(driver->securityManager, def) < 0)
+ return -1;
+
+ if (qemuDomainDefVcpusPostParse(def) < 0)
+ return -1;
+
+ if (qemuDomainDefCPUPostParse(def, qemuCaps) < 0)
+ return -1;
+
+ if (qemuDomainDefTsegPostParse(def, qemuCaps) < 0)
+ return -1;
+
+ if (qemuDomainDefNumaCPUsPostParse(def, qemuCaps, parseFlags) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+int
+qemuDomainPostParseDataAlloc(const virDomainDef *def,
+ unsigned int parseFlags G_GNUC_UNUSED,
+ void *opaque,
+ void **parseOpaque)
+{
+ virQEMUDriver *driver = opaque;
+
+ if (!(*parseOpaque = virQEMUCapsCacheLookup(driver->qemuCapsCache,
+ def->emulator)))
+ return 1;
+
+ return 0;
+}
+
+
+void
+qemuDomainPostParseDataFree(void *parseOpaque)
+{
+ virQEMUCaps *qemuCaps = parseOpaque;
+
+ virObjectUnref(qemuCaps);
+}
diff --git a/src/qemu/qemu_postparse.h b/src/qemu/qemu_postparse.h
new file mode 100644
index 0000000000..ac69c14604
--- /dev/null
+++ b/src/qemu/qemu_postparse.h
@@ -0,0 +1,54 @@
+/*
+ * qemu_postparse.h: QEMU domain PostParse functions
+ *
+ * Copyright (C) 2006-2024 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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 "virconftypes.h"
+
+int
+qemuDomainDeviceDiskDefPostParse(virDomainDiskDef *disk,
+ unsigned int parseFlags);
+
+int
+qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
+ const virDomainDef *def,
+ unsigned int parseFlags,
+ void *opaque,
+ void *parseOpaque);
+
+int
+qemuDomainDefPostParseBasic(virDomainDef *def,
+ void *opaque);
+
+int
+qemuDomainDefPostParse(virDomainDef *def,
+ unsigned int parseFlags,
+ void *opaque,
+ void *parseOpaque);
+
+int
+qemuDomainPostParseDataAlloc(const virDomainDef *def,
+ unsigned int parseFlags,
+ void *opaque,
+ void **parseOpaque);
+
+void
+qemuDomainPostParseDataFree(void *parseOpaque);
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
index 7ffa445c37..ac4d87b527 100644
--- a/tests/qemublocktest.c
+++ b/tests/qemublocktest.c
@@ -27,6 +27,7 @@
#include "qemu/qemu_monitor_json.h"
#include "qemu/qemu_backup.h"
#include "qemu/qemu_checkpoint.h"
+#include "qemu/qemu_postparse.h"
#include "qemu/qemu_validate.h"
#define LIBVIRT_SNAPSHOT_CONF_PRIV_H_ALLOW
--
2.45.2
2 months, 1 week
[PATCH v1 0/5] Allow Guest CPU Model with Deprecated Features Disabled
by Collin Walling
Add support for libvirt to query and cache an array of deprecated CPU features
(aka CPU properties) for the host-model. This data is queried via a full
query-cpu-model-expansion and cached in the QEMU capabilities file. This
model expansion will depend on the availability of the "deprecated-props" field
resulting from a query-cpu-model-expansion command. Currently, only s390x
supports this field.
The purpose of these patches is to make it easy for users to create guests with
a CPU model that will be compatible & migratable with future hardware.
An updated host CPU model with deprecated features paired with the policy "disable"
may be visable via an update to the virsh domcapabilities command with the
--disable-deprecated-features flag. An example is shown below.
Note: other CPU model queries (e.g. baseline and comparison) currently do not
consider deprecated features, as their outputs do not consider feature policy.
If implementation is desired, it will require a discussion on how these
commands should report policies.
Examples:
virsh domcapabilities --disable-deprecated-features
e.g. output (trimmed):
<mode name='host-model' supported='yes'>
<model fallback='forbid'>z14.2-base</model>
<feature policy='require' name='aen'/>
<feature policy='require' name='cmmnt'/>
<feature policy='require' name='aefsi'/>
<feature policy='require' name='diag318'/>
<feature policy='require' name='mepoch'/>
<feature policy='require' name='msa8'/>
<feature policy='require' name='msa7'/>
<feature policy='require' name='msa6'/>
<feature policy='require' name='msa5'/>
<feature policy='require' name='msa4'/>
<feature policy='require' name='msa3'/>
<feature policy='require' name='msa2'/>
<feature policy='require' name='msa1'/>
<feature policy='require' name='sthyi'/>
<feature policy='require' name='edat'/>
<feature policy='require' name='ri'/>
<feature policy='require' name='edat2'/>
<feature policy='require' name='etoken'/>
<feature policy='require' name='vx'/>
<feature policy='require' name='ipter'/>
<feature policy='require' name='mepochptff'/>
<feature policy='require' name='ap'/>
<feature policy='require' name='vxeh'/>
<feature policy='require' name='vxpd'/>
<feature policy='require' name='esop'/>
<feature policy='require' name='apqi'/>
<feature policy='require' name='apft'/>
<feature policy='require' name='els'/>
<feature policy='require' name='iep'/>
<feature policy='require' name='apqci'/>
<feature policy='disable' name='cte'/>
<feature policy='require' name='ais'/>
<feature policy='disable' name='bpb'/>
<feature policy='require' name='ctop'/>
<feature policy='require' name='gs'/>
<feature policy='require' name='ppa15'/>
<feature policy='require' name='zpci'/>
<feature policy='require' name='sea_esop2'/>
<feature policy='disable' name='te'/>
<feature policy='require' name='cmm'/>
<feature policy='disable' name='csske'/>
</mode>
A domain may be defined with a new <cpu> XML attribute, deprecated_features='on|off':
<cpu mode='host-model' check='partial' deprecated_features='off'/>
e.g. after guest has started (trimmed):
<cpu mode='custom' match='exact' check='partial' deprecated_features='off'>
<model fallback='forbid'>z14.2-base</model>
<feature policy='require' name='aen'/>
<feature policy='require' name='cmmnt'/>
<feature policy='require' name='aefsi'/>
<feature policy='require' name='diag318'/>
<feature policy='require' name='mepoch'/>
<feature policy='require' name='msa8'/>
<feature policy='require' name='msa7'/>
<feature policy='require' name='msa6'/>
<feature policy='require' name='msa5'/>
<feature policy='require' name='msa4'/>
<feature policy='require' name='msa3'/>
<feature policy='require' name='msa2'/>
<feature policy='require' name='msa1'/>
<feature policy='require' name='sthyi'/>
<feature policy='require' name='edat'/>
<feature policy='require' name='ri'/>
<feature policy='require' name='edat2'/>
<feature policy='require' name='etoken'/>
<feature policy='require' name='vx'/>
<feature policy='require' name='ipter'/>
<feature policy='require' name='mepochptff'/>
<feature policy='require' name='ap'/>
<feature policy='require' name='vxeh'/>
<feature policy='require' name='vxpd'/>
<feature policy='require' name='esop'/>
<feature policy='require' name='apqi'/>
<feature policy='require' name='apft'/>
<feature policy='require' name='els'/>
<feature policy='require' name='iep'/>
<feature policy='require' name='apqci'/>
<feature policy='disable' name='cte'/>
<feature policy='require' name='ais'/>
<feature policy='disable' name='bpb'/>
<feature policy='require' name='ctop'/>
<feature policy='require' name='gs'/>
<feature policy='require' name='ppa15'/>
<feature policy='require' name='zpci'/>
<feature policy='require' name='sea_esop2'/>
<feature policy='disable' name='te'/>
<feature policy='require' name='cmm'/>
<feature policy='disable' name='csske'/>
</cpu>
Collin Walling (5):
qemuMonitorJSONGetCPUModelExpansion: refactor parsing functions
qemu: parse deprecated-props from query-cpu-model-expansion response
qemu_capabilities: query deprecated features for host-model
virsh: add --disable-deprecated-features flag to domcapabilities
conf: add deprecated_features attribute
docs/manpages/virsh.rst | 6 +
include/libvirt/libvirt-domain.h | 12 +
src/conf/cpu_conf.c | 10 +
src/conf/cpu_conf.h | 1 +
src/conf/schemas/cputypes.rng | 12 +
src/libvirt-domain.c | 2 +-
src/qemu/qemu_capabilities.c | 89 +++++
src/qemu/qemu_capabilities.h | 4 +
src/qemu/qemu_driver.c | 8 +-
src/qemu/qemu_monitor.c | 10 +
src/qemu/qemu_monitor.h | 1 +
src/qemu/qemu_monitor_json.c | 64 +++-
src/qemu/qemu_process.c | 4 +
.../caps_9.1.0_s390x.replies | 348 +++++++++++++++++-
.../qemucapabilitiesdata/caps_9.1.0_s390x.xml | 13 +
.../caps_9.2.0_s390x.replies | 348 +++++++++++++++++-
.../qemucapabilitiesdata/caps_9.2.0_s390x.xml | 13 +
tools/virsh-host.c | 9 +-
18 files changed, 940 insertions(+), 14 deletions(-)
--
2.45.1
2 months, 1 week
[PATCH] Drop unused function declarations
by Michal Privoznik
When moving function and/or renaming them sometimes corresponding
change to corresponding header file is not done. This leaves us
with functions that are declared in header files, but nowhere
implemented. Drop such declarations.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
These were identified by a bash oneliner which basically tried to list
every "function" in every header file (function was matched as '\w\+(')
and for every function from the list, git grep was done to see if it
lives in a .c file.
It's nowhere exhaustive or perfect, but if found at least something.
src/ch/ch_monitor.h | 4 ----
src/conf/device_conf.h | 1 -
src/conf/virinterfaceobj.h | 3 ---
src/conf/virstorageobj.h | 3 ---
src/libxl/libxl_domain.h | 3 ---
src/logging/log_handler.h | 2 --
src/lxc/lxc_cgroup.h | 1 -
src/lxc/lxc_hostdev.h | 6 ------
src/lxc/lxc_monitor.h | 3 ---
src/lxc/lxc_process.h | 9 ---------
src/qemu/qemu_command.h | 3 ---
src/qemu/qemu_domain.h | 12 ------------
src/qemu/qemu_monitor.h | 4 ----
src/qemu/qemu_monitor_json.h | 29 -----------------------------
src/qemu/qemu_process.h | 3 ---
src/rpc/virnetlibsshsession.h | 1 -
src/rpc/virnetserverclient.h | 2 --
src/util/virmdev.h | 3 ---
src/util/virnetdev.h | 10 ----------
src/vz/vz_utils.h | 8 --------
tests/testutilsqemu.h | 3 ---
21 files changed, 113 deletions(-)
diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h
index b35f5ea027..9ec58e5b20 100644
--- a/src/ch/ch_monitor.h
+++ b/src/ch/ch_monitor.h
@@ -118,10 +118,6 @@ int virCHMonitorSaveVM(virCHMonitor *mon,
const char *to);
int virCHMonitorGetInfo(virCHMonitor *mon, virJSONValue **info);
-void virCHMonitorCPUInfoFree(virCHMonitorCPUInfo *cpus);
-int virCHMonitorGetCPUInfo(virCHMonitor *mon,
- virCHMonitorCPUInfo **vcpus,
- size_t maxvcpus);
size_t virCHMonitorGetThreadInfo(virCHMonitor *mon, bool refresh,
virCHMonitorThreadInfo **threads);
int virCHMonitorGetIOThreads(virCHMonitor *mon,
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index 2d674ecd85..2d97410f6e 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -193,7 +193,6 @@ int virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node,
int virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf,
const virDeviceHostdevPCIDriverInfo *driver);
-void virDeviceHostdevPCIDriverInfoPostParse(virDeviceHostdevPCIDriverInfo *driver);
void virDeviceHostdevPCIDriverInfoClear(virDeviceHostdevPCIDriverInfo *driver);
void virDomainDeviceInfoClear(virDomainDeviceInfo *info);
diff --git a/src/conf/virinterfaceobj.h b/src/conf/virinterfaceobj.h
index 5927484167..c59dac28d3 100644
--- a/src/conf/virinterfaceobj.h
+++ b/src/conf/virinterfaceobj.h
@@ -51,9 +51,6 @@ virInterfaceObj *
virInterfaceObjListFindByName(virInterfaceObjList *interfaces,
const char *name);
-void
-virInterfaceObjFree(virInterfaceObj *obj);
-
virInterfaceObjList *
virInterfaceObjListClone(virInterfaceObjList *interfaces);
diff --git a/src/conf/virstorageobj.h b/src/conf/virstorageobj.h
index d9dae9ceb9..e1eabfdb3a 100644
--- a/src/conf/virstorageobj.h
+++ b/src/conf/virstorageobj.h
@@ -229,9 +229,6 @@ virStoragePoolObjGetNames(virStoragePoolObjList *pools,
char **const names,
int maxnames);
-void
-virStoragePoolObjFree(virStoragePoolObj *obj);
-
typedef void
(*virStoragePoolObjListIterator)(virStoragePoolObj *obj,
const void *opaque);
diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h
index 94b693e477..a35d121323 100644
--- a/src/libxl/libxl_domain.h
+++ b/src/libxl/libxl_domain.h
@@ -46,9 +46,6 @@ extern virDomainDefParserConfig libxlDomainDefParserConfig;
extern virXMLNamespace libxlDriverDomainXMLNamespace;
extern const struct libxl_event_hooks ev_hooks;
-int
-libxlDomainObjPrivateInitCtx(virDomainObj *vm);
-
int
libxlDomainJobGetTimeElapsed(virDomainJobObj *job,
unsigned long long *timeElapsed);
diff --git a/src/logging/log_handler.h b/src/logging/log_handler.h
index 97dad27eda..38c300289e 100644
--- a/src/logging/log_handler.h
+++ b/src/logging/log_handler.h
@@ -67,8 +67,6 @@ virLogHandler *virLogHandlerNewPostExecRestart(virJSONValue *child,
virLogHandlerShutdownInhibitor inhibitor,
void *opaque);
-void virLogHandlerFree(virLogHandler *handler);
-
int virLogHandlerDomainOpenLogFile(virLogHandler *handler,
const char *driver,
const unsigned char *domuuid,
diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h
index 64d0c51175..83f342c08c 100644
--- a/src/lxc/lxc_cgroup.h
+++ b/src/lxc/lxc_cgroup.h
@@ -29,7 +29,6 @@ virCgroup *virLXCCgroupCreate(virDomainDef *def,
pid_t initpid,
size_t nnicindexes,
int *nicindexes);
-virCgroup *virLXCCgroupJoin(virDomainDef *def);
int virLXCCgroupSetup(virDomainDef *def,
virCgroup *cgroup,
virBitmap *nodemask);
diff --git a/src/lxc/lxc_hostdev.h b/src/lxc/lxc_hostdev.h
index 34b813e3e9..4aa124c660 100644
--- a/src/lxc/lxc_hostdev.h
+++ b/src/lxc/lxc_hostdev.h
@@ -26,12 +26,6 @@
int virLXCUpdateActiveUSBHostdevs(virLXCDriver *driver,
virDomainDef *def);
-int virLXCFindHostdevUSBDevice(virDomainHostdevDef *hostdev,
- bool mandatory,
- virUSBDevice **usb);
-int virLXCPrepareHostdevUSBDevices(virLXCDriver *driver,
- const char *name,
- virUSBDeviceList *list);
int virLXCPrepareHostDevices(virLXCDriver *driver,
virDomainDef *def);
void virLXCDomainReAttachHostDevices(virLXCDriver *driver,
diff --git a/src/lxc/lxc_monitor.h b/src/lxc/lxc_monitor.h
index 5b5954f8e9..0a10768452 100644
--- a/src/lxc/lxc_monitor.h
+++ b/src/lxc/lxc_monitor.h
@@ -53,6 +53,3 @@ virLXCMonitor *virLXCMonitorNew(virDomainObj *vm,
virLXCMonitorCallbacks *cb);
void virLXCMonitorClose(virLXCMonitor *mon);
-
-void virLXCMonitorLock(virLXCMonitor *mon);
-void virLXCMonitorUnlock(virLXCMonitor *mon);
diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h
index 4b84e31fef..95eacdd1e5 100644
--- a/src/lxc/lxc_process.h
+++ b/src/lxc/lxc_process.h
@@ -33,15 +33,6 @@ int virLXCProcessStop(virLXCDriver *driver,
virDomainShutoffReason reason,
unsigned int cleanupFlags);
-void virLXCProcessAutoDestroyRun(virLXCDriver *driver,
- virConnectPtr conn);
-void virLXCProcessAutoDestroyShutdown(virLXCDriver *driver);
-int virLXCProcessAutoDestroyAdd(virLXCDriver *driver,
- virDomainObj *vm,
- virConnectPtr conn);
-int virLXCProcessAutoDestroyRemove(virLXCDriver *driver,
- virDomainObj *vm);
-
void virLXCProcessAutostartAll(virLXCDriver *driver);
int virLXCProcessReconnectAll(virLXCDriver *driver,
virDomainObjList *doms);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index fb4551a7d0..76c514b5f7 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -93,7 +93,6 @@ qemuBuildNicDevProps(virDomainDef *def,
virDomainNetDef *net,
virQEMUCaps *qemuCaps);
-char *qemuDeviceDriveHostAlias(virDomainDiskDef *disk);
bool qemuDiskBusIsSD(int bus);
int
@@ -208,8 +207,6 @@ qemuBuildRedirdevDevProps(const virDomainDef *def,
virJSONValue *
qemuBuildZPCIDevProps(virDomainDeviceInfo *dev);
-int qemuNetworkPrepareDevices(virDomainDef *def);
-
bool
qemuDiskConfigBlkdeviotuneEnabled(const virDomainDiskDef *disk);
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index a19314b48b..047a11b7fe 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -588,8 +588,6 @@ virDomainObj *qemuDomainObjFromDomain(virDomainPtr domain);
qemuDomainSaveCookie *qemuDomainSaveCookieNew(virDomainObj *vm);
-void qemuDomainEventFlush(int timer, void *opaque);
-
qemuMonitor *qemuDomainGetMonitor(virDomainObj *vm)
ATTRIBUTE_NONNULL(1);
void qemuDomainObjEnterMonitor(virDomainObj *obj)
@@ -645,9 +643,6 @@ void qemuDomainObjTaint(virQEMUDriver *driver,
virDomainTaintFlags taint,
qemuLogContext *logCtxt);
-char **qemuDomainObjGetTainting(virQEMUDriver *driver,
- virDomainObj *obj);
-
void qemuDomainObjCheckTaint(virQEMUDriver *driver,
virDomainObj *obj,
qemuLogContext *logCtxt,
@@ -716,10 +711,6 @@ int qemuDomainCheckDiskStartupPolicy(virQEMUDriver *driver,
size_t diskIndex,
bool cold_boot);
-int qemuDomainCheckDiskPresence(virQEMUDriver *driver,
- virDomainObj *vm,
- unsigned int flags);
-
int qemuDomainStorageSourceValidateDepth(virStorageSource *src,
int add,
const char *diskdst);
@@ -947,9 +938,6 @@ int qemuDomainSecretPrepare(virQEMUDriver *driver,
virDomainObj *vm)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int qemuDomainDeviceDefValidateDisk(const virDomainDiskDef *disk,
- virQEMUCaps *qemuCaps);
-
int qemuDomainDeviceDiskDefPostParse(virDomainDiskDef *disk,
unsigned int parseFlags);
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4341519cfe..035c9a7e3c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -939,10 +939,6 @@ void qemuMonitorChardevInfoFree(void *data);
int qemuMonitorGetChardevInfo(qemuMonitor *mon,
GHashTable **retinfo);
-int qemuMonitorAttachPCIDiskController(qemuMonitor *mon,
- const char *bus,
- virPCIDeviceAddress *guestAddr);
-
int qemuMonitorAddDeviceProps(qemuMonitor *mon,
virJSONValue **props);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 10491b809b..ab3c2cb7c8 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -175,10 +175,6 @@ qemuMonitorJSONMigrate(qemuMonitor *mon,
int
qemuMonitorJSONGetMigrationBlockers(qemuMonitor *mon,
char ***blockers);
-int
-qemuMonitorJSONGetSpiceMigrationStatus(qemuMonitor *mon,
- bool *spice_migrated);
-
int
qemuMonitorJSONMigrateCancel(qemuMonitor *mon);
@@ -208,26 +204,6 @@ qemuMonitorJSONGraphicsRelocate(qemuMonitor *mon,
int tlsPort,
const char *tlsSubject);
-int
-qemuMonitorJSONAddPCIHostDevice(qemuMonitor *mon,
- virPCIDeviceAddress *hostAddr,
- virPCIDeviceAddress *guestAddr);
-
-int
-qemuMonitorJSONAddPCIDisk(qemuMonitor *mon,
- const char *path,
- const char *bus,
- virPCIDeviceAddress *guestAddr);
-
-int
-qemuMonitorJSONAddPCINetwork(qemuMonitor *mon,
- const char *nicstr,
- virPCIDeviceAddress *guestAddr);
-
-int
-qemuMonitorJSONRemovePCIDevice(qemuMonitor *mon,
- virPCIDeviceAddress *guestAddr);
-
int
qemuMonitorJSONAddFileHandleToSet(qemuMonitor *mon,
int fd,
@@ -268,11 +244,6 @@ int
qemuMonitorJSONGetChardevInfo(qemuMonitor *mon,
GHashTable *info);
-int
-qemuMonitorJSONAttachPCIDiskController(qemuMonitor *mon,
- const char *bus,
- virPCIDeviceAddress *guestAddr);
-
int
qemuMonitorJSONAddDeviceProps(qemuMonitor *mon,
virJSONValue **props);
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index 878c522d82..12781673c5 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -189,9 +189,6 @@ void qemuProcessShutdownOrReboot(virDomainObj *vm);
void qemuProcessAutoDestroy(virDomainObj *dom,
virConnectPtr conn);
-int qemuProcessSetSchedParams(int id, pid_t pid, size_t nsp,
- virDomainThreadSchedParam *sp);
-
virDomainDiskDef *qemuProcessFindDomainDiskByAliasOrQOM(virDomainObj *vm,
const char *alias,
const char *qomid);
diff --git a/src/rpc/virnetlibsshsession.h b/src/rpc/virnetlibsshsession.h
index 7f94fd15dc..949680035c 100644
--- a/src/rpc/virnetlibsshsession.h
+++ b/src/rpc/virnetlibsshsession.h
@@ -26,7 +26,6 @@
typedef struct _virNetLibsshSession virNetLibsshSession;
virNetLibsshSession *virNetLibsshSessionNew(const char *username);
-void virNetLibsshSessionFree(virNetLibsshSession *sess);
typedef enum {
VIR_NET_LIBSSH_HOSTKEY_VERIFY_NORMAL,
diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h
index 2ae6c85b20..0a1ddd6f28 100644
--- a/src/rpc/virnetserverclient.h
+++ b/src/rpc/virnetserverclient.h
@@ -152,8 +152,6 @@ int virNetServerClientInit(virNetServerClient *client);
int virNetServerClientInitKeepAlive(virNetServerClient *client,
int interval,
unsigned int count);
-bool virNetServerClientCheckKeepAlive(virNetServerClient *client,
- virNetMessage *msg);
int virNetServerClientStartKeepAlive(virNetServerClient *client);
const char *virNetServerClientLocalAddrStringSASL(virNetServerClient *client);
diff --git a/src/util/virmdev.h b/src/util/virmdev.h
index e8e69040e5..75853bc0ff 100644
--- a/src/util/virmdev.h
+++ b/src/util/virmdev.h
@@ -72,9 +72,6 @@ typedef int (*virMediatedDeviceCallback)(virMediatedDevice *dev,
virMediatedDevice *
virMediatedDeviceNew(const char *uuidstr, virMediatedDeviceModelType model);
-virMediatedDevice *
-virMediatedDeviceCopy(virMediatedDevice *dev);
-
void
virMediatedDeviceFree(virMediatedDevice *dev);
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index c287a7b272..99fe761c1d 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -185,16 +185,6 @@ int virNetDevGetMAC(const char *ifname,
virMacAddr *macaddr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
-int virNetDevReplaceMacAddress(const char *linkdev,
- const virMacAddr *macaddress,
- const char *stateDir)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
- G_GNUC_WARN_UNUSED_RESULT;
-
-int virNetDevRestoreMacAddress(const char *linkdev,
- const char *stateDir)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
-
int virNetDevSetCoalesce(const char *ifname,
virNetDevCoalesce *coalesce,
bool update)
diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h
index 7a797953a5..a7003a5370 100644
--- a/src/vz/vz_utils.h
+++ b/src/vz/vz_utils.h
@@ -39,14 +39,6 @@
#define IS_CT(def) (def->os.type == VIR_DOMAIN_OSTYPE_EXE)
-#define vzDomNotFoundError(domain) \
- do { \
- char uuidstr[VIR_UUID_STRING_BUFLEN]; \
- virUUIDFormat(domain->uuid, uuidstr); \
- virReportError(VIR_ERR_NO_DOMAIN, \
- _("no domain with matching uuid '%1$s'"), uuidstr); \
- } while (0)
-
#define PARALLELS_DOMAIN_ROUTED_NETWORK_NAME "host-routed"
#define VIRTUOZZO_VER_7 ((unsigned long)7000000)
diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h
index 90632031ff..74e307d653 100644
--- a/tests/testutilsqemu.h
+++ b/tests/testutilsqemu.h
@@ -126,9 +126,6 @@ typedef struct _testQemuInfo testQemuInfo;
void testQemuInfoFree(testQemuInfo *info);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(testQemuInfo, testQemuInfoFree);
-virDomainXMLOption *testQemuXMLConfInit(void);
-
-
virQEMUCaps *qemuTestParseCapabilitiesArch(virArch arch,
const char *capsFile);
virCPUDef *qemuTestGetCPUDef(qemuTestCPUDef d);
--
2.45.2
2 months, 1 week
[PATCH] virnetserverclient.h: Fix typo in comment of virNetServerClientPrivPreExecRestart()
by Michal Privoznik
The function the comment is referring to is
virNetServerClientPrivNew() not virNetServerClintPrivNew(). The
latter doesn't even exist.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/rpc/virnetserverclient.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h
index 0d585eb2ce..2ae6c85b20 100644
--- a/src/rpc/virnetserverclient.h
+++ b/src/rpc/virnetserverclient.h
@@ -48,7 +48,7 @@ typedef int (*virNetServerClientFilterFunc)(virNetServerClient *client,
void *opaque);
/*
- * @data: value allocated by virNetServerClintPrivNew(PostExecRestart) callback
+ * @data: value allocated by virNetServerClientPrivNew(PostExecRestart) callback
*/
typedef virJSONValue *(*virNetServerClientPrivPreExecRestart)(virNetServerClient *client,
void *data);
--
2.45.2
2 months, 1 week
[PATCH v3] qemu_hotplug: Do not report unknown error when hot-unplugging non-existing device
by Martin Kletzander
When qemuDomainDeleteDevice() gets "DeviceNotFound" error it is a
special case as we're trying to remove a device which does not exists
any more. Such occasion is indicated by the return value -2.
Callers of the aforementioned function ought to base their behaviour on
the return value. However not all callers take as much care for the
return value as one could realistically anticipate.
Follow the usual direction of removing possible backend object (in case
of character devices), remove the device from its XML without waiting
for the device removal from QEMU (since it is already not there) and
basically follow the same algorithm as there is when the device was
removed, skipping over the wait for the device removal.
The overall return value also needs to be adjusted since
qemuDomainDeleteDevice() does not set an error on the -2 return value
and would otherwise trigger an unknown error being reported to the user
or management application.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
v3:
- Skip qemuDomainWaitForDeviceRemoval() when the vCPU does not exist, as
written in the commit message
- Do all the other necessary things when the vCPU is missing
v2:
- Adjust for -2 return value in callers
src/qemu/qemu_hotplug.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 8361d3d9c1b7..bddd553c88a5 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -6090,8 +6090,12 @@ qemuDomainDetachDeviceChr(virQEMUDriver *driver,
if (rc < 0)
goto cleanup;
} else {
- if (qemuDomainDeleteDevice(vm, tmpChr->info.alias) < 0)
+ ret = qemuDomainDeleteDevice(vm, tmpChr->info.alias);
+ if (ret < 0) {
+ if (ret == -2)
+ ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, true);
goto cleanup;
+ }
}
if (guestfwd) {
@@ -6595,18 +6599,20 @@ qemuDomainHotplugDelVcpu(virQEMUDriver *driver,
qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);
- if (qemuDomainDeleteDevice(vm, vcpupriv->alias) < 0) {
- if (virDomainObjIsActive(vm))
- virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
- goto cleanup;
- }
-
- if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
- if (rc == 0)
- virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
- _("vcpu unplug request timed out. Unplug result must be manually inspected in the domain"));
-
- goto cleanup;
+ rc = qemuDomainDeleteDevice(vm, vcpupriv->alias);
+ if (rc < 0) {
+ if (rc != -2) {
+ if (virDomainObjIsActive(vm))
+ virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
+ goto cleanup;
+ }
+ } else {
+ if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
+ if (rc == 0)
+ virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
+ _("vcpu unplug request timed out. Unplug result must be manually inspected in the domain"));
+ goto cleanup;
+ }
}
if (qemuDomainRemoveVcpu(vm, vcpu) < 0)
--
2.47.0
2 months, 1 week
[PATCH v2] qemu_hotplug: Do not report unknown error when hot-unplugging non-existing device
by Martin Kletzander
When qemuDomainDeleteDevice() gets "DeviceNotFound" error it is a
special case as we're trying to remove a device which does not exists
any more. Such occasion is indicated by the return value -2.
Callers of the aforementioned function ought to base their behaviour on
the return value. However not all callers take as much care for the
return value as one could realistically anticipate.
Follow the usual direction of removing possible backend object (in case
of character devices), remove the device from its XML without waiting
for the device removal from QEMU (since it is already not there) and
basically follow the same algorithm as there is when the device was
removed, skipping over the wait for the device removal.
The overall return value also needs to be adjusted since
qemuDomainDeleteDevice() does not set an error on the -2 return value
and would otherwise trigger an unknown error being reported to the user
or management application.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/qemu/qemu_hotplug.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 8361d3d9c1b7..1b6ecb1cd1f9 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -6090,8 +6090,12 @@ qemuDomainDetachDeviceChr(virQEMUDriver *driver,
if (rc < 0)
goto cleanup;
} else {
- if (qemuDomainDeleteDevice(vm, tmpChr->info.alias) < 0)
+ ret = qemuDomainDeleteDevice(vm, tmpChr->info.alias);
+ if (ret < 0) {
+ if (ret == -2)
+ ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, true);
goto cleanup;
+ }
}
if (guestfwd) {
@@ -6595,18 +6599,19 @@ qemuDomainHotplugDelVcpu(virQEMUDriver *driver,
qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);
- if (qemuDomainDeleteDevice(vm, vcpupriv->alias) < 0) {
- if (virDomainObjIsActive(vm))
+ rc = qemuDomainDeleteDevice(vm, vcpupriv->alias);
+ if (rc < 0) {
+ if (rc == -1 && virDomainObjIsActive(vm))
virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
goto cleanup;
- }
-
- if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
- if (rc == 0)
- virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
- _("vcpu unplug request timed out. Unplug result must be manually inspected in the domain"));
+ } else {
+ if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
+ if (rc == 0)
+ virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
+ _("vcpu unplug request timed out. Unplug result must be manually inspected in the domain"));
- goto cleanup;
+ goto cleanup;
+ }
}
if (qemuDomainRemoveVcpu(vm, vcpu) < 0)
--
2.47.0
2 months, 1 week
[PATCH] security_apparmor: store dynamically generated rules
by Georgia Garcia
Some rules are generated dynamically during boot and added to the
AppArmor policy. An example of that is macvtap devices that call the
AppArmorSetFDLabel hook to add a rule for the tap device path.
Since this information is dynamic, it is not available in the xml
config, therefore whenever a "Restore" hook is called, the entire
profile is regenerated by virt-aa-helper based only the information
from the VM definition, so the dynamic information is lost.
This patch stores the dynamically generated rules while the domain is
running and reloads them whenever there's a restore operation.
Note that there are no hooks for restoring FD labels, so that
information is not removed from the set of rules while the domain is
running.
Closes: https://gitlab.com/libvirt/libvirt/-/issues/692
Signed-off-by: Georgia Garcia <georgia.garcia(a)canonical.com>
---
src/security/security_apparmor.c | 208 +++++++++++++++++++++++++++++--
1 file changed, 200 insertions(+), 8 deletions(-)
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index 07e95ec81d..ae5815fb0d 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -60,6 +60,24 @@ struct SDPDOP {
virDomainDef *def;
};
+typedef struct _virSecurityAppArmorLabel virSecurityAppArmorLabel;
+struct _virSecurityAppArmorLabel {
+ GPtrArray *paths;
+ char *name;
+};
+
+typedef struct _virSecurityAppArmorLabelList virSecurityAppArmorLabelList;
+struct _virSecurityAppArmorLabelList {
+ GPtrArray *labels;
+ virMutex lock;
+};
+
+virSecurityAppArmorLabelList *labelList = NULL;
+
+static int AppArmorRestorePolicy(virSecurityManager *mgr,
+ virDomainDef *def,
+ char *seclabel);
+
/*
* profile_status returns '-2' on error, '-1' if not loaded, '0' if loaded
*
@@ -273,6 +291,119 @@ reload_profile(virSecurityManager *mgr,
secdef->imagelabel);
return -1;
}
+ if (!append) {
+ if (AppArmorRestorePolicy(mgr, def, secdef->imagelabel) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot restore rules from AppArmor profile \'%1$s\'"),
+ secdef->imagelabel);
+ return -1;
+ }
+ }
+
+ }
+ return 0;
+}
+
+static int
+AppArmorInitLabelList(void)
+{
+ if (labelList)
+ return 0;
+
+ labelList = g_new0(virSecurityAppArmorLabelList, 1);
+ labelList->labels = g_ptr_array_new();
+ if (virMutexInit(&labelList->lock) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Failed to initialize AppArmor mutex"));
+ return -1;
+ }
+ return 0;
+}
+
+static void
+AppArmorFreeLabelList(void)
+{
+ size_t i;
+ if (!labelList)
+ return;
+
+ VIR_WITH_MUTEX_LOCK_GUARD(&labelList->lock) {
+ for (i = 0; i < labelList->labels->len; i++) {
+ virSecurityAppArmorLabel *label = g_ptr_array_index(labelList->labels, i);
+ g_ptr_array_free(label->paths, TRUE);
+ g_free(label->name);
+ }
+ g_ptr_array_free(labelList->labels, TRUE);
+ }
+ virMutexDestroy(&labelList->lock);
+ g_free(labelList);
+ labelList = NULL;
+}
+
+static int
+AppArmorAppendPathToLabelList(char *seclabel,
+ const char *path)
+{
+ size_t i;
+ char *new;
+
+ if (!path)
+ return 0;
+
+ if (!labelList) {
+ if (AppArmorInitLabelList() < 0)
+ return -1;
+ }
+
+ VIR_WITH_MUTEX_LOCK_GUARD(&labelList->lock) {
+ for (i = 0; i < labelList->labels->len; i++) {
+ virSecurityAppArmorLabel *label = g_ptr_array_index(labelList->labels, i);
+ if (STREQ(seclabel, label->name)) {
+ new = g_strdup(path);
+ g_ptr_array_add(label->paths, new);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+AppArmorLoadStoredPath(virSecurityAppArmorLabel *label,
+ virSecurityManager *mgr,
+ virDomainDef *def,
+ char *seclabel)
+{
+ size_t i;
+ for (i = 0; i < label->paths->len; i++) {
+ if (load_profile(mgr, seclabel, def, g_ptr_array_index(label->paths, i), true) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot update AppArmor profile \'%1$s\' \'%2$s\'"),
+ seclabel, (char *)g_ptr_array_index(label->paths, i));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+AppArmorRestorePolicy(virSecurityManager *mgr,
+ virDomainDef *def,
+ char *seclabel)
+{
+ size_t i;
+
+ if (!labelList) {
+ return 0;
+ }
+
+ VIR_WITH_MUTEX_LOCK_GUARD(&labelList->lock) {
+ for (i = 0; i < labelList->labels->len; i++) {
+ virSecurityAppArmorLabel *label = g_ptr_array_index(labelList->labels, i);
+ if (STREQ(seclabel, label->name)) {
+ if (AppArmorLoadStoredPath(label, mgr, def, seclabel) < 0)
+ return -1;
+ }
+ }
}
return 0;
}
@@ -330,12 +461,13 @@ AppArmorSecurityManagerProbe(const char *virtDriver G_GNUC_UNUSED)
static int
AppArmorSecurityManagerOpen(virSecurityManager *mgr G_GNUC_UNUSED)
{
- return 0;
+ return AppArmorInitLabelList();
}
static int
AppArmorSecurityManagerClose(virSecurityManager *mgr G_GNUC_UNUSED)
{
+ AppArmorFreeLabelList();
return 0;
}
@@ -364,6 +496,7 @@ AppArmorGenSecurityLabel(virSecurityManager *mgr G_GNUC_UNUSED,
g_autofree char *profile_name = NULL;
virSecurityLabelDef *secdef = virDomainDefGetSecurityLabelDef(def,
SECURITY_APPARMOR_NAME);
+ virSecurityAppArmorLabel *label;
if (!secdef)
return 0;
@@ -404,6 +537,18 @@ AppArmorGenSecurityLabel(virSecurityManager *mgr G_GNUC_UNUSED,
goto err;
}
+ if (!labelList) {
+ if (AppArmorInitLabelList() < 0)
+ goto err;
+ }
+
+ label = g_new0(virSecurityAppArmorLabel, 1);
+ label->paths = g_ptr_array_new();
+ label->name = g_strdup(profile_name);
+ VIR_WITH_MUTEX_LOCK_GUARD(&labelList->lock) {
+ g_ptr_array_add(labelList->labels, label);
+ }
+
return 0;
err:
@@ -421,6 +566,7 @@ AppArmorSetSecurityAllLabel(virSecurityManager *mgr,
bool chardevStdioLogd G_GNUC_UNUSED,
bool migrated G_GNUC_UNUSED)
{
+ int rc;
virSecurityLabelDef *secdef = virDomainDefGetSecurityLabelDef(def,
SECURITY_APPARMOR_NAME);
if (!secdef || !secdef->relabel)
@@ -428,8 +574,15 @@ AppArmorSetSecurityAllLabel(virSecurityManager *mgr,
/* Reload the profile if incomingPath is specified. Note that
GenSecurityLabel() will have already been run. */
- if (incomingPath)
- return reload_profile(mgr, def, incomingPath, true);
+ if (incomingPath) {
+ rc = reload_profile(mgr, def, incomingPath, true);
+ if (AppArmorAppendPathToLabelList(secdef->imagelabel, incomingPath) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Could not store path"));
+ return -1;
+ }
+ return rc;
+ }
return 0;
}
@@ -495,6 +648,7 @@ AppArmorRestoreSecurityAllLabel(virSecurityManager *mgr G_GNUC_UNUSED,
bool migrated G_GNUC_UNUSED,
bool chardevStdioLogd G_GNUC_UNUSED)
{
+ size_t i;
int rc = 0;
virSecurityLabelDef *secdef =
virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
@@ -508,6 +662,21 @@ AppArmorRestoreSecurityAllLabel(virSecurityManager *mgr G_GNUC_UNUSED,
_("could not remove profile for \'%1$s\'"),
secdef->label);
}
+ if (labelList) {
+ VIR_WITH_MUTEX_LOCK_GUARD(&labelList->lock) {
+ for (i = 0; i < labelList->labels->len; i++) {
+ virSecurityAppArmorLabel *label;
+ label = g_ptr_array_index(labelList->labels, i);
+ if (STREQ(secdef->label, label->name)) {
+ g_free(label->name);
+ g_ptr_array_free(label->paths, TRUE);
+ g_ptr_array_remove_index(labelList->labels, i);
+ break;
+ }
+ }
+ }
+ }
+
}
return rc;
}
@@ -1082,15 +1251,26 @@ AppArmorSetPathLabel(virSecurityManager *mgr,
{
int rc = -1;
char *full_path = NULL;
+ virSecurityLabelDef *secdef;
+
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
if (allowSubtree) {
full_path = g_strdup_printf("%s/{,**}", path);
- rc = reload_profile(mgr, def, full_path, true);
- VIR_FREE(full_path);
} else {
- rc = reload_profile(mgr, def, path, true);
+ full_path = g_strdup(path);
+ }
+
+ rc = reload_profile(mgr, def, full_path, true);
+ if (rc == 0) {
+ if (AppArmorAppendPathToLabelList(secdef->imagelabel, full_path) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Could not store path"));
+ rc = -1;
+ }
}
+ VIR_FREE(full_path);
return rc;
}
@@ -1107,6 +1287,7 @@ AppArmorSetFDLabel(virSecurityManager *mgr,
virDomainDef *def,
int fd)
{
+ int rc = 0;
char *proc = NULL;
char *fd_path = NULL;
@@ -1121,10 +1302,21 @@ AppArmorSetFDLabel(virSecurityManager *mgr,
if (virFileResolveLink(proc, &fd_path) < 0) {
/* it's a deleted file, presumably. Ignore? */
VIR_WARN("could not find path for descriptor %s, skipping", proc);
- return 0;
+ goto err;
}
- return reload_profile(mgr, def, fd_path, true);
+ rc = reload_profile(mgr, def, fd_path, true);
+ if (rc == 0) {
+ if (AppArmorAppendPathToLabelList(secdef->imagelabel, fd_path) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Could not store path"));
+ rc = -1;
+ }
+ }
+ g_free(fd_path);
+ err:
+ g_free(proc);
+ return rc;
}
static char *
--
2.34.1
2 months, 1 week
[PATCH v2] docs: Recommend virtio instead of virtio-(non-)transitional
by Andrea Bolognani
When virtio-(non-)transitional models were introduced, the
documentation was updated to include them; at the same time,
language was introduced indicating that using the existing
virtio model is no longer recommended.
This is unnecessarily harsh, and has resulted in people
incorrectly believing (through no fault of their own) that the
virtio model has been deprecated.
In reality, it's perfectly fine to use the virtio model as the
stress-free option that, while often not producing the ideal
PCI topology, will generally get the job done and work reliably
across libvirt versions and machine types.
Tweak the documentation so that it hopefully carries the
desired message across.
Signed-off-by: Andrea Bolognani <abologna(a)redhat.com>
---
docs/formatdomain.rst | 55 ++++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 27 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index c50744b57b..75dff5a153 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -2756,8 +2756,8 @@ paravirtualized driver is specified via the ``disk`` element.
``model``
Indicates the emulated device model of the disk. Typically this is
indicated solely by the ``bus`` property but for ``bus`` "virtio" the
- model can be specified further with "virtio-transitional",
- "virtio-non-transitional", or "virtio". See `Virtio transitional devices`_
+ model can be specified further with "virtio", "virtio-transitional" or
+ "virtio-non-transitional". See `virtio device models`_
for more details. :since:`Since 5.2.0`
``rawio``
Indicates whether the disk needs rawio capability. Valid settings are
@@ -3680,9 +3680,8 @@ A directory on the host that can be accessed directly from the guest.
info <https://lists.gnu.org/archive/html/qemu-devel/2010-09/msg00121.html>`__
:since:`Since 5.2.0`, the filesystem element has an optional attribute
- ``model`` with supported values "virtio-transitional",
- "virtio-non-transitional", or "virtio". See `Virtio transitional devices`_
- for more details.
+ ``model`` with supported values "virtio", "virtio-transitional" or
+ "virtio-non-transitional". See `virtio device models`_ for more details.
The filesystem element has optional attributes ``fmode`` and ``dmode``.
These two attributes control the creation mode for files and directories
@@ -3910,11 +3909,20 @@ Note: In general you should leave this option alone, unless you are very certain
you know what you are doing.
-Virtio transitional devices
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Virtio device models
+~~~~~~~~~~~~~~~~~~~~
+
+Virtio devices come in several variants, some of which are only applicable to
+certain machine types or scenarios. The variant can be chosen via the ``model``
+attribute, which supports the following values:
-:since:`Since 5.2.0`, some of QEMU's virtio devices, when used with PCI/PCIe
-machine types, accept the following ``model`` values:
+``virtio``
+ This is the recommended choice in the absence of guest OS specific
+ constraints, as it will will generally work correctly across a large range
+ of architectures, machine types and libvirt versions.
+
+:since:`Since 5.2.0`, the following values can additionally be used with machine
+types based on PCI (either conventional PCI or PCI Express):
``virtio-transitional``
This device can work both with virtio 0.9 and virtio 1.0 guest drivers, so
@@ -3926,12 +3934,6 @@ machine types, accept the following ``model`` values:
necessary. libvirt will plug the device into either a PCI Express slot or a
conventional PCI slot based on the machine type, resulting in a more
optimized PCI topology.
-``virtio``
- This device will work like a ``virtio-non-transitional`` device when plugged
- into a PCI Express slot, and like a ``virtio-transitional`` device otherwise;
- libvirt will pick one or the other based on the machine type. This is the
- best choice when compatibility with libvirt versions older than 5.2.0 is
- necessary, but it's otherwise not recommended to use it.
While the information outlined above applies to most virtio devices, there are a
few exceptions:
@@ -3992,14 +3994,14 @@ specific features, such as:
The ``virtio-serial`` controller has two additional optional attributes
``ports`` and ``vectors``, which control how many devices can be connected
through the controller. :since:`Since 5.2.0`, it supports an optional
- attribute ``model`` which can be 'virtio', 'virtio-transitional', or
- 'virtio-non-transitional'. See `Virtio transitional devices`_ for more details.
+ attribute ``model`` which can be 'virtio', 'virtio-transitional' or
+ 'virtio-non-transitional'. See `virtio device models`_ for more details.
``scsi``
A ``scsi`` controller has an optional attribute ``model``, which is one of
'auto', 'buslogic', 'ibmvscsi', 'lsilogic', 'lsisas1068', 'lsisas1078',
'virtio-scsi', 'vmpvscsi', 'virtio-transitional', 'virtio-non-transitional',
'ncr53c90' (as builtin implicit controller only), 'am53c974', 'dc390'.
- See `Virtio transitional devices`_ for more details.
+ See `virtio device models`_ for more details.
``usb``
A ``usb`` controller has an optional attribute ``model``, which is one of
"piix3-uhci", "piix4-uhci", "ehci", "ich9-ehci1", "ich9-uhci1", "ich9-uhci2",
@@ -4452,9 +4454,8 @@ or:
:since:`since 2.5.0` For SCSI devices, user is responsible to make sure
the device is not used by host. This ``type`` passes all LUNs presented by
a single HBA to the guest. :since:`Since 5.2.0`, the ``model`` attribute
- can be specified further with "virtio-transitional",
- "virtio-non-transitional", or "virtio". `Virtio transitional devices`_
- for more details.
+ can be specified further with "virtio", "virtio-transitional" or
+ "virtio-non-transitional". See `virtio device models`_ for more details.
``mdev``
For mediated devices ( :since:`Since 3.2.0` ) the ``model`` attribute
specifies the device API which determines how the host's vfio driver will
@@ -6300,8 +6301,8 @@ value 'all' which when enabled grabs all input devices instead of just one,
change the grab key combination.
``input`` type ``evdev`` is currently supported only on linux devices.
(KVM only) :since:`Since 5.2.0`, the ``input`` element accepts a
-``model`` attribute which has the values 'virtio', 'virtio-transitional' and
-'virtio-non-transitional'. See `Virtio transitional devices`_ for more details.
+``model`` attribute which has the values 'virtio', 'virtio-transitional' or
+'virtio-non-transitional'. See `virtio device models`_ for more details.
The subelement ``driver`` can be used to tune the virtio options of the device:
`Virtio-related options`_ can also be set. ( :since:`Since 3.5.0` )
@@ -7982,7 +7983,7 @@ Example: manually added device with static PCI slot 2 requested
- 'virtio-non-transitional' :since:`Since 5.2.0`
- 'xen' - default with Xen
- See `Virtio transitional devices`_ for more details.
+ See `virtio device models`_ for more details.
``autodeflate``
The optional ``autodeflate`` attribute allows to enable/disable (values
@@ -8048,7 +8049,7 @@ Example: usage of the RNG device:
- 'virtio-transitional' :since:`Since 5.2.0`
- 'virtio-non-transitional' :since:`Since 5.2.0`
- See `Virtio transitional devices`_ for more details.
+ See `virtio device models`_ for more details.
``rate``
The optional ``rate`` element allows limiting the rate at which entropy can
@@ -8673,8 +8674,8 @@ Vsock
~~~~~
A vsock host/guest interface. The ``model`` attribute defaults to ``virtio``.
-:since:`Since 5.2.0` ``model`` can also be 'virtio-transitional' and
-'virtio-non-transitional', see `Virtio transitional devices`_ for more details.
+:since:`Since 5.2.0` ``model`` can also be 'virtio-transitional' or
+'virtio-non-transitional', see `virtio device models`_ for more details.
The optional attribute ``address`` of the ``cid`` element specifies the CID
assigned to the guest. If the attribute ``auto`` is set to ``yes``, libvirt will
assign a free CID automatically on domain startup. :since:`Since 4.4.0`
--
2.47.0
2 months, 1 week
[PATCH] ci: Update with newer lcitool
by Martin Kletzander
This switches to newer freebsd 14.1 and implements the new RUN_PIPELINE
behaviour introduced by Daniel.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
As far as I understand this does not need any change in the CI/CD settings in
gitlab, but I do not have access to those.
ci/cirrus/freebsd-14.vars | 2 +-
ci/gitlab.yml | 13 +++++++---
ci/gitlab/build-templates.yml | 46 ++++++++++++++++++++++++++---------
ci/gitlab/builds.yml | 2 +-
ci/gitlab/sanity-checks.yml | 8 ++++--
5 files changed, 51 insertions(+), 20 deletions(-)
diff --git a/ci/cirrus/freebsd-14.vars b/ci/cirrus/freebsd-14.vars
index fbcd6130956f..3002987cbdd8 100644
--- a/ci/cirrus/freebsd-14.vars
+++ b/ci/cirrus/freebsd-14.vars
@@ -10,7 +10,7 @@ CROSS_PKGS=''
MAKE='/usr/local/bin/gmake'
NINJA='/usr/local/bin/ninja'
PACKAGING_COMMAND='pkg'
-PIP3='/usr/local/bin/pip-3.8'
+PIP3='/usr/local/bin/pip'
PKGS='augeas bash-completion ca_root_nss ccache codespell cppi curl cyrus-sasl diffutils fusefs-libs gettext git glib gmake gnugrep gnutls gsed json-c libpcap libpciaccess libssh libssh2 libxml2 libxslt meson ninja perl5 pkgconf polkit py311-black py311-docutils py311-flake8 py311-pytest python3 qemu readline'
PYPI_PKGS=''
PYTHON='/usr/local/bin/python3'
diff --git a/ci/gitlab.yml b/ci/gitlab.yml
index 7bb68b848c73..0daab1267668 100644
--- a/ci/gitlab.yml
+++ b/ci/gitlab.yml
@@ -11,8 +11,11 @@
# - RUN_PIPELINE - force creation of a CI pipeline when
# pushing to a branch in a forked repository. Official
# CI pipelines are triggered when merge requests are
-# created/updated. Setting this variable to a non-empty
-# value allows CI testing prior to opening a merge request.
+# created/updated. Setting this variable allows CI
+# testing prior to opening a merge request. A value
+# of "0" will create the pipeline but leave all jobs
+# to be manually started, while "1" will immediately
+# run all default jobs.
#
# - RUN_PIPELINE_UPSTREAM_ENV - same semantics as RUN_PIPELINE,
# but uses the CI environment (containers) from the upstream project
@@ -38,11 +41,13 @@
#
# Aliases can be set for common usage
#
-# $ git config --local alias.push-ci "push -o ci.variable=RUN_PIPELINE=1"
+# $ git config --local alias.push-ci "push -o ci.variable=RUN_PIPELINE=0"
+# $ git config --local alias.push-ci-now "push -o ci.variable=RUN_PIPELINE=1"
#
# Allowing the less verbose invocation
#
-# $ git push-ci
+# $ git push-ci (create pipeline but don't start jobs)
+# $ git push-ci-now (create pipeline and start default jobs)
#
# Pipeline variables can also be set in the repository
# pipeline config globally, or set against scheduled pipelines
diff --git a/ci/gitlab/build-templates.yml b/ci/gitlab/build-templates.yml
index b1e41b0783d9..5ba91ffc673d 100644
--- a/ci/gitlab/build-templates.yml
+++ b/ci/gitlab/build-templates.yml
@@ -47,19 +47,27 @@
when: on_success
# forks: pushes to a branch when a pipeline run in upstream env is explicitly requested
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV && $JOB_OPTIONAL'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "0"'
when: manual
allow_failure: true
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "1" && $JOB_OPTIONAL'
+ when: manual
+ allow_failure: true
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "1"'
when: on_success
# forks: pushes to branches with pipeline requested
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE && $JOB_OPTIONAL'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "0"'
+ when: manual
+ allow_failure: true
+ variables:
+ IMAGE: $TARGET_BASE_IMAGE
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "1" && $JOB_OPTIONAL'
when: manual
allow_failure: true
variables:
IMAGE: $TARGET_BASE_IMAGE
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "1"'
when: on_success
variables:
IMAGE: $TARGET_BASE_IMAGE
@@ -183,19 +191,27 @@
when: on_success
# forks: pushes to a branch when a pipeline run in upstream env is explicitly requested
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV && $JOB_OPTIONAL'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "0"'
+ when: manual
+ allow_failure: true
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "1" && $JOB_OPTIONAL'
when: manual
allow_failure: true
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "1"'
when: on_success
# forks: pushes to branches with pipeline requested
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE && $JOB_OPTIONAL'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "0"'
when: manual
allow_failure: true
variables:
IMAGE: $TARGET_BASE_IMAGE
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "1" && $JOB_OPTIONAL'
+ when: manual
+ allow_failure: true
+ variables:
+ IMAGE: $TARGET_BASE_IMAGE
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "1"'
when: on_success
variables:
IMAGE: $TARGET_BASE_IMAGE
@@ -302,15 +318,21 @@
when: on_success
# forks: pushes to branches with pipeline requested (including pipeline in upstream environment)
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE && $JOB_OPTIONAL'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "0"'
when: manual
allow_failure: true
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "1" && $JOB_OPTIONAL'
+ when: manual
+ allow_failure: true
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE == "1"'
when: on_success
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV && $JOB_OPTIONAL'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "0"'
+ when: manual
+ allow_failure: true
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "1" && $JOB_OPTIONAL'
when: manual
allow_failure: true
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $RUN_PIPELINE_UPSTREAM_ENV == "1"'
when: on_success
# upstream+forks: Run pipelines on MR, web, api & scheduled
diff --git a/ci/gitlab/builds.yml b/ci/gitlab/builds.yml
index c24421378c51..3e7f36802e15 100644
--- a/ci/gitlab/builds.yml
+++ b/ci/gitlab/builds.yml
@@ -617,7 +617,7 @@ x86_64-freebsd-14:
allow_failure:
exit_codes: 3
variables:
- CIRRUS_VM_IMAGE_NAME: freebsd-14-0
+ CIRRUS_VM_IMAGE_NAME: freebsd-14-1
CIRRUS_VM_IMAGE_SELECTOR: image_family
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
INSTALL_COMMAND: pkg install -y
diff --git a/ci/gitlab/sanity-checks.yml b/ci/gitlab/sanity-checks.yml
index d2b1768e266d..b568015db930 100644
--- a/ci/gitlab/sanity-checks.yml
+++ b/ci/gitlab/sanity-checks.yml
@@ -18,9 +18,13 @@ check-dco:
when: on_success
# forks: pushes to branches with pipeline requested (including upstream env pipelines)
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE == "0"'
+ when: manual
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE == "1"'
when: on_success
- - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV'
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV == "0"'
+ when: manual
+ - if: '$CI_PROJECT_NAMESPACE != $RUN_UPSTREAM_NAMESPACE && $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $RUN_PIPELINE_UPSTREAM_ENV == "1"'
when: on_success
# upstream+forks: that's all folks
--
2.47.0
2 months, 1 week