[libvirt] [PATCH 1/8] qemu: Add support for unavailable-features

Pavel Hrdina phrdina at redhat.com
Thu Nov 3 10:36:17 UTC 2016


On Wed, Nov 02, 2016 at 10:22:30AM +0100, Jiri Denemark wrote:
> QEMU 2.8.0 adds support for unavailable-features in
> query-cpu-definitions reply. The unavailable-features array lists CPU
> features which prevent a corresponding CPU model from being usable on
> current host. It can only be used when all the unavailable features are
> disabled. Empty array means the CPU model can be used without
> modifications.
> 
> We can use unavailable-features for providing CPU model usability info
> in domain capabilities XML:
> 
>     <domainCapabilities>
>       ...
>       <cpu>
>         <mode name='host-passthrough' supported='yes'/>
>         <mode name='host-model' supported='yes'>
>           <model fallback='allow'>Skylake-Client</model>
>           ...
>         </mode>
>         <mode name='custom' supported='yes'>
>           <model usable='yes'>qemu64</model>
>           <model usable='yes'>qemu32</model>
>           <model usable='no'>phenom</model>
>           <model usable='yes'>pentium3</model>
>           <model usable='yes'>pentium2</model>
>           <model usable='yes'>pentium</model>
>           <model usable='yes'>n270</model>
>           <model usable='yes'>kvm64</model>
>           <model usable='yes'>kvm32</model>
>           <model usable='yes'>coreduo</model>
>           <model usable='yes'>core2duo</model>
>           <model usable='no'>athlon</model>
>           <model usable='yes'>Westmere</model>
>           <model usable='yes'>Skylake-Client</model>
>           ...
>         </mode>
>       </cpu>
>       ...
>     </domainCapabilities>
> 
> Signed-off-by: Jiri Denemark <jdenemar at redhat.com>
> ---
>  src/qemu/qemu_capabilities.c | 53 ++++++++++++++++++++++++++++++++++----------
>  src/qemu/qemu_capabilities.h |  6 +++--
>  src/qemu/qemu_monitor.h      |  1 +
>  src/qemu/qemu_monitor_json.c | 27 ++++++++++++++++------
>  src/qemu/qemu_process.c      |  2 +-
>  tests/qemumonitorjsontest.c  | 25 +++++++++++++++++----
>  tests/qemuxml2argvtest.c     | 12 ++++++----
>  7 files changed, 96 insertions(+), 30 deletions(-)
> 
> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> index 7a8202a..9fce7a6 100644
> --- a/src/qemu/qemu_capabilities.c
> +++ b/src/qemu/qemu_capabilities.c
> @@ -2306,7 +2306,8 @@ const char *virQEMUCapsGetPackage(virQEMUCapsPtr qemuCaps)
>  int
>  virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps,
>                               const char **name,
> -                             size_t count)
> +                             size_t count,
> +                             virDomainCapsCPUUsable usable)
>  {
>      size_t i;
>  
> @@ -2316,7 +2317,7 @@ virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps,
>  
>      for (i = 0; i < count; i++) {
>          if (virDomainCapsCPUModelsAdd(qemuCaps->cpuDefinitions, name[i], -1,
> -                                      VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0)
> +                                      usable) < 0)
>              return -1;
>      }
>  
> @@ -2327,10 +2328,12 @@ virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps,
>  int
>  virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps,
>                               char ***names,
> -                             size_t *count)
> +                             size_t *count,
> +                             bool usable)
>  {
>      size_t i;
>      char **models = NULL;
> +    size_t n = 0;
>  
>      *count = 0;
>      if (names)
> @@ -2344,17 +2347,21 @@ virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps,
>  
>      for (i = 0; i < qemuCaps->cpuDefinitions->nmodels; i++) {
>          virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i;
> -        if (models && VIR_STRDUP(models[i], cpu->name) < 0)
> -            goto error;
> +        if (!usable ||
> +            cpu->usable == VIR_DOMCAPS_CPU_USABLE_YES) {
> +            if (models && VIR_STRDUP(models[n], cpu->name) < 0)
> +                goto error;
> +            n++;
> +        }

This function is called only on one place and the argument *usable* is always
false and it's not used in any of the following patches in this series so there
is no need to modify this function at all.

>      }
>  
>      if (names)
>          *names = models;
> -    *count = qemuCaps->cpuDefinitions->nmodels;
> +    *count = n;
>      return 0;
>  
>   error:
> -    virStringFreeListCount(models, i);
> +    virStringFreeListCount(models, n);
>      return -1;
>  }
>  
> @@ -2713,9 +2720,15 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps,
>          goto cleanup;
>  
>      for (i = 0; i < ncpus; i++) {
> +        virDomainCapsCPUUsable usable = VIR_DOMCAPS_CPU_USABLE_UNKNOWN;
> +
> +        if (cpus[i]->usable == VIR_TRISTATE_BOOL_YES)
> +            usable = VIR_DOMCAPS_CPU_USABLE_YES;
> +        else if (cpus[i]->usable == VIR_TRISTATE_BOOL_NO)
> +            usable = VIR_DOMCAPS_CPU_USABLE_NO;
> +
>          if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions,
> -                                           &cpus[i]->name,
> -                                           VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0)
> +                                           &cpus[i]->name, usable) < 0)
>              goto cleanup;
>      }
>  
> @@ -3128,6 +3141,17 @@ virQEMUCapsLoadCache(virCapsPtr caps,
>              goto cleanup;
>  
>          for (i = 0; i < n; i++) {
> +            int usable = VIR_DOMCAPS_CPU_USABLE_UNKNOWN;
> +
> +            if ((str = virXMLPropString(nodes[i], "usable")) &&
> +                (usable = virDomainCapsCPUUsableTypeFromString(str)) < 0) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR,
> +                               _("unknown value '%s' in attribute 'usable'"),
> +                               str);
> +                goto cleanup;
> +            }
> +            VIR_FREE(str);
> +
>              if (!(str = virXMLPropString(nodes[i], "name"))) {
>                  virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>                                 _("missing cpu name in QEMU capabilities cache"));
> @@ -3135,8 +3159,7 @@ virQEMUCapsLoadCache(virCapsPtr caps,
>              }
>  
>              if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions,
> -                                               &str,
> -                                               VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0)
> +                                               &str, usable) < 0)
>                  goto cleanup;
>          }
>      }
> @@ -3301,7 +3324,13 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps,
>      if (qemuCaps->cpuDefinitions) {
>          for (i = 0; i < qemuCaps->cpuDefinitions->nmodels; i++) {
>              virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i;
> -            virBufferEscapeString(&buf, "<cpu name='%s'/>\n", cpu->name);
> +            virBufferEscapeString(&buf, "<cpu name='%s'", cpu->name);
> +            if (cpu->usable) {
> +                const char *usable;
> +                usable = virDomainCapsCPUUsableTypeToString(cpu->usable);
> +                virBufferAsprintf(&buf, " usable='%s'", usable);
> +            }
> +            virBufferAddLit(&buf, "/>\n");
>          }
>      }
>  
> diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
> index 6e7a855..c77ba13 100644
> --- a/src/qemu/qemu_capabilities.h
> +++ b/src/qemu/qemu_capabilities.h
> @@ -428,10 +428,12 @@ const char *virQEMUCapsGetPackage(virQEMUCapsPtr qemuCaps);
>  unsigned int virQEMUCapsGetKVMVersion(virQEMUCapsPtr qemuCaps);
>  int virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps,
>                                   const char **name,
> -                                 size_t count);
> +                                 size_t count,
> +                                 virDomainCapsCPUUsable usable);
>  int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps,
>                                   char ***names,
> -                                 size_t *count);
> +                                 size_t *count,
> +                                 bool usable);
>  virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps);
>  bool virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps,
>                                     virCapsPtr caps,
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index c3133c4..f81de68 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -913,6 +913,7 @@ typedef struct _qemuMonitorCPUDefInfo qemuMonitorCPUDefInfo;
>  typedef qemuMonitorCPUDefInfo *qemuMonitorCPUDefInfoPtr;
>  
>  struct _qemuMonitorCPUDefInfo {
> +    virTristateBool usable;
>      char *name;
>  };
>  
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 6c13832..e2dfb34 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -4925,13 +4925,8 @@ qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon,
>      if (qemuMonitorJSONCheckError(cmd, reply) < 0)
>          goto cleanup;
>  
> -    if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                       _("query-cpu-definitions reply was missing return data"));
> -        goto cleanup;
> -    }
> -
> -    if ((n = virJSONValueArraySize(data)) < 0) {
> +    if (!(data = virJSONValueObjectGetArray(reply, "return")) ||
> +        (n = virJSONValueArraySize(data)) < 0) {

This change is unrelated, it would be probably better to put in into separate
patch.

>          virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>                         _("query-cpu-definitions reply data was not an array"));
>          goto cleanup;
> @@ -4958,6 +4953,24 @@ qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon,
>  
>          if (VIR_STRDUP(cpu->name, tmp) < 0)
>              goto cleanup;
> +
> +        if (virJSONValueObjectHasKey(child, "unavailable-features")) {
> +            virJSONValuePtr blockers;
> +
> +            blockers = virJSONValueObjectGetArray(child,
> +                                                  "unavailable-features");
> +            if (!blockers) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("unavailable-features in query-cpu-definitions "
> +                                 "reply data was not an array"));
> +                goto cleanup;
> +            }
> +
> +            if (virJSONValueArraySize(blockers) > 0)
> +                cpu->usable = VIR_TRISTATE_BOOL_NO;
> +            else
> +                cpu->usable = VIR_TRISTATE_BOOL_YES;
> +        }
>      }
>  
>      ret = n;
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 1b67aee..50fb3de 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -5057,7 +5057,7 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
>                       virQEMUCapsGetHostModel(qemuCaps)) < 0)
>          goto cleanup;
>  
> -    if (virQEMUCapsGetCPUDefinitions(qemuCaps, &models, &nmodels) < 0 ||
> +    if (virQEMUCapsGetCPUDefinitions(qemuCaps, &models, &nmodels, false) < 0 ||
>          virCPUTranslate(def->os.arch, def->cpu, models, nmodels) < 0)
>          goto cleanup;
>  
> diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
> index d8fd958..7111bc8 100644
> --- a/tests/qemumonitorjsontest.c
> +++ b/tests/qemumonitorjsontest.c
> @@ -432,10 +432,12 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data)
>                                 "     \"name\": \"qemu64\" "
>                                 "   }, "
>                                 "   { "
> -                               "     \"name\": \"Opteron_G4\" "
> +                               "     \"name\": \"Opteron_G4\", "
> +                               "     \"unavailable-features\": [\"vme\"]"
>                                 "   }, "
>                                 "   { "
> -                               "     \"name\": \"Westmere\" "
> +                               "     \"name\": \"Westmere\", "
> +                               "     \"unavailable-features\": []"
>                                 "   } "
>                                 "  ]"
>                                 "}") < 0)
> @@ -452,6 +454,13 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data)
>      }
>  
>  #define CHECK(i, wantname)                                              \
> +    CHECK_FULL(i, wantname, VIR_TRISTATE_BOOL_ABSENT)
> +
> +#define CHECK_USABLE(i, wantname, usable)                               \
> +    CHECK_FULL(i, wantname,                                             \
> +               usable ? VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO)
> +

The ordering of macros is strange.  The above macros uses CHECK_FULL so I would
rather move them after the CHECK_FULL macro.

ACK with the issues fixed.

Pavel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20161103/5af794e7/attachment-0001.sig>


More information about the libvir-list mailing list