diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 40f49a8d9e..f1771522e5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4555,6 +4555,124 @@ virQEMUCapsCacheLookupByArch(virFileCachePtr cache, } +/** + * virQEMUCapsCacheLookupDefault: + * @cache: QEMU capabilities cache + * @binary: optional path to QEMU binary + * @archStr: optional guest architecture + * @virttypeStr: optional virt type + * @machine: optional machine type + * @retArch: if non-NULL, guest architecture will be returned here + * @retVirttype: if non-NULL, domain virt type will be returned here + * @retMachine: if non-NULL, canonical machine type will be returned here + * + * Looks up the QEMU binary specified by @binary and @archStr, checks it can + * provide the required @virttypeStr and @machine and returns its capabilities. + * Sensible defaults are used for any argument which is NULL (the function can + * even be called with all NULL arguments). + * + * Returns QEMU capabilities matching the requirements, NULL on error. + */ +virQEMUCapsPtr +virQEMUCapsCacheLookupDefault(virFileCachePtr cache, + const char *binary, + const char *archStr, + const char *virttypeStr, + const char *machine, + virArch *retArch, + virDomainVirtType *retVirttype, + const char **retMachine) +{ + int virttype = VIR_DOMAIN_VIRT_NONE; + int arch = virArchFromHost(); + virDomainVirtType capsType; + virQEMUCapsPtr qemuCaps = NULL; + virQEMUCapsPtr ret = NULL; + + if (virttypeStr && + (virttype = virDomainVirtTypeFromString(virttypeStr)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), virttypeStr); + goto cleanup; + } + + if (archStr && + (arch = virArchFromString(archStr)) == VIR_ARCH_NONE) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown architecture: %s"), archStr); + goto cleanup; + } + + if (binary) { + virArch arch_from_caps; + + if (!(qemuCaps = virQEMUCapsCacheLookup(cache, binary))) + goto cleanup; + + arch_from_caps = virQEMUCapsGetArch(qemuCaps); + + if (arch_from_caps != arch && + !((ARCH_IS_X86(arch) && ARCH_IS_X86(arch_from_caps)) || + (ARCH_IS_PPC(arch) && ARCH_IS_PPC(arch_from_caps)) || + (ARCH_IS_ARM(arch) && ARCH_IS_ARM(arch_from_caps)) || + (ARCH_IS_S390(arch) && ARCH_IS_S390(arch_from_caps)))) { + virReportError(VIR_ERR_INVALID_ARG, + _("architecture from emulator '%s' doesn't " + "match given architecture '%s'"), + virArchToString(arch_from_caps), + virArchToString(arch)); + goto cleanup; + } + } else { + if (!(qemuCaps = virQEMUCapsCacheLookupByArch(cache, arch))) + goto cleanup; + + binary = virQEMUCapsGetBinary(qemuCaps); + } + + if (machine) { + /* Turn @machine into canonical name */ + machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine); + + if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) { + virReportError(VIR_ERR_INVALID_ARG, + _("the machine '%s' is not supported by emulator '%s'"), + machine, binary); + goto cleanup; + } + } else { + machine = virQEMUCapsGetDefaultMachine(qemuCaps); + } + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) + capsType = VIR_DOMAIN_VIRT_KVM; + else + capsType = VIR_DOMAIN_VIRT_QEMU; + + if (virttype == VIR_DOMAIN_VIRT_NONE) + virttype = capsType; + + if (virttype == VIR_DOMAIN_VIRT_KVM && capsType == VIR_DOMAIN_VIRT_QEMU) { + virReportError(VIR_ERR_INVALID_ARG, + _("KVM is not supported by '%s' on this host"), + binary); + goto cleanup; + } + + if (retArch) + *retArch = arch; + if (retVirttype) + *retVirttype = virttype; + if (retMachine) + *retMachine = machine; + + VIR_STEAL_PTR(ret, qemuCaps); + + cleanup: + virObjectUnref(qemuCaps); + return ret; +} + bool virQEMUCapsSupportsVmport(virQEMUCapsPtr qemuCaps, const virDomainDef *def) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index bff2b4ed95..fa4d241d7b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -563,6 +563,14 @@ virQEMUCapsPtr virQEMUCapsCacheLookupCopy(virFileCachePtr cache, const char *machineType); virQEMUCapsPtr virQEMUCapsCacheLookupByArch(virFileCachePtr cache, virArch arch); +virQEMUCapsPtr virQEMUCapsCacheLookupDefault(virFileCachePtr cache, + const char *binary, + const char *archStr, + const char *virttypeStr, + const char *machine, + virArch *retArch, + virDomainVirtType *retVirttype, + const char **retMachine); virCapsPtr virQEMUCapsInit(virFileCachePtr cache); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9d8b943ee6..cb2504e7db 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -19393,10 +19393,9 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, char *ret = NULL; virQEMUDriverPtr driver = conn->privateData; virQEMUCapsPtr qemuCaps = NULL; - int virttype = VIR_DOMAIN_VIRT_NONE; - virDomainVirtType capsType; + virArch arch; + virDomainVirtType virttype; virDomainCapsPtr domCaps = NULL; - int arch = virArchFromHost(); /* virArch */ virQEMUDriverConfigPtr cfg = NULL; virCapsPtr caps = NULL; @@ -19410,80 +19409,17 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; - if (virttype_str && - (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown virttype: %s"), - virttype_str); + qemuCaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + emulatorbin, + arch_str, + virttype_str, + machine, + &arch, &virttype, &machine); + if (!qemuCaps) goto cleanup; - } - if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown architecture: %s"), - arch_str); - goto cleanup; - } - - if (emulatorbin) { - virArch arch_from_caps; - - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, - emulatorbin))) - goto cleanup; - - arch_from_caps = virQEMUCapsGetArch(qemuCaps); - - if (arch_from_caps != arch && - !((ARCH_IS_X86(arch) && ARCH_IS_X86(arch_from_caps)) || - (ARCH_IS_PPC(arch) && ARCH_IS_PPC(arch_from_caps)) || - (ARCH_IS_ARM(arch) && ARCH_IS_ARM(arch_from_caps)) || - (ARCH_IS_S390(arch) && ARCH_IS_S390(arch_from_caps)))) { - virReportError(VIR_ERR_INVALID_ARG, - _("architecture from emulator '%s' doesn't " - "match given architecture '%s'"), - virArchToString(arch_from_caps), - virArchToString(arch)); - goto cleanup; - } - } else { - if (!(qemuCaps = virQEMUCapsCacheLookupByArch(driver->qemuCapsCache, - arch))) - goto cleanup; - - emulatorbin = virQEMUCapsGetBinary(qemuCaps); - } - - if (machine) { - /* Turn @machine into canonical name */ - machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine); - - if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) { - virReportError(VIR_ERR_INVALID_ARG, - _("the machine '%s' is not supported by emulator '%s'"), - machine, emulatorbin); - goto cleanup; - } - } else { - machine = virQEMUCapsGetDefaultMachine(qemuCaps); - } - - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) - capsType = VIR_DOMAIN_VIRT_KVM; - else - capsType = VIR_DOMAIN_VIRT_QEMU; - - if (virttype == VIR_DOMAIN_VIRT_NONE) - virttype = capsType; - - if (virttype == VIR_DOMAIN_VIRT_KVM && capsType == VIR_DOMAIN_VIRT_QEMU) { - virReportError(VIR_ERR_INVALID_ARG, - _("KVM is not supported by '%s' on this host"), - emulatorbin); - goto cleanup; - } - - if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) + if (!(domCaps = virDomainCapsNew(virQEMUCapsGetBinary(qemuCaps), machine, + arch, virttype))) goto cleanup; if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps,