[PATCH v2 00/35] qemu: Add infrastructure to prevent accidental disk shrink via 'virDomainBlockResize' (part 2)
v2: - possibility to query flags for every API at once A comment in v1 suggested that polling flags one by one is ineffective. It was also limited to virDomainBlockResize. This version adds an API 'virConnectGetIntrospection' which allows to probe for every flag of every API at once via the introspection XML which also informs users about supported typed parameters. Patches 1-34 are new in the series. Patch 35 is adapted to use the new introspection API. This is partially a RFC: - documentation and schema for the new XML will be contributed later - I've contemplated adding typed parameters as input for the new API if we'd want to extend it to e.g. allow probing supported stuff for e.g. a hypervisor version Breakdown of patches: Semi-unrelated refactors/fixes: remote_protocol-structs: fix mis-aligned 'remote_domain_set_throttle_group_args' qemu: driver: Unify coding style util: typedparam: Convert VIR_TYPED_PARAM_CHECK_TYPE into a function util: virTypedParamValidateType: Don't report unknown typed parameter type as '(null)' util: Replace open-coded internals of VIR_TYPED_PARAMS_DEBUG with 'virTypedParamDebugstr' util: typedparam: Unexport virTypedParameterTypeFromString/virTypedParameterTypeToString util: typedparam: Refactor and fix typed param validation scripts: check-symfile: Allow also symbols in 'readonly' section virHostCPUGet(Map|Stats): Remove unused 'flags' virHostMemGet(Stats|Parameters): Remove unused 'flags' virNodeSuspend: Remove unused 'flags' Changes to allow the introspection script to parse flags: qemu: backup: Move 'virCheckFlags' to top level functions qemu: attach/detach device: Move 'virCheckFlags' to top level functions qemu: dump: Move 'virCheckFlags' to top level functions qemu: checkpoint: Move 'virCheckFlags' to top level functions qemuDomainRestore(Flags|Params): Refactor flag checking qemu: snapshot: Move flag checks to top level functions qemuDomainGetLaunchSecurityInfo: Move flag check to top level qemuDomainDetachDeviceAlias: Move 'flags' validation to top level qemuDomainManagedSaveDefineXML: Add top-level flag validation qemuDomainQemuMonitorCommand: Add top-level flag validation qemuConnectDomainQemuMonitorEventRegister: Add top-level flag validation qemuDomainGetMetadata: Add top-level flag validation API addition and implementation of the introspection api supporting flag introspection: API: Introduce 'virConnectGetIntrospection' virsh: Introduce 'introspection' command which uses 'virConnectGetIntrospection' scripts: Introduce 'getintrospection' script qemu: Implement 'virConnectGetIntrospection' Cleanups needed in order to support typed parameter introspection util: typedparam: Introduce 'virTypedParamsValidateTemplate' qemu: migration: Use 'virTypedParamsValidateTemplate' for migration params qemu: Reimplement 'qemuDomainValidateBlockIoTune' using 'virTypedParamsValidateTemplate' util: hostmem: Make parameters for 'virHostMemSetParameters' introspectable qemuDomainSetSchedulerParameters: Make typed parameters introspectable qemuDomainSetIOThreadParams: Move typed parameter validation to top level Implementation of typed parameter introspection: introspection: Add introspection of input typed parameters Original patch to prevent shrink in virsh: virsh: blockresize: Use VIR_DOMAIN_BLOCK_RESIZE_EXTEND when available and introduce --allow-shrink docs/manpages/virsh.rst | 30 +- include/libvirt/libvirt-host.h | 3 + scripts/check-symfile.py | 2 +- scripts/genintrospection.py | 347 ++++++++++++++++++++ scripts/meson.build | 1 + src/bhyve/bhyve_driver.c | 20 +- src/ch/ch_driver.c | 11 +- src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 4 + src/conf/domain_event.c | 4 +- src/conf/domain_event.h | 5 + src/driver-hypervisor.h | 5 + src/libvirt-host.c | 40 +++ src/libvirt_private.syms | 10 +- src/libvirt_public.syms | 5 + src/lxc/lxc_driver.c | 24 +- src/openvz/openvz_driver.c | 12 +- src/qemu/meson.build | 18 ++ src/qemu/qemu_backup.c | 8 +- src/qemu/qemu_backup.h | 3 +- src/qemu/qemu_checkpoint.c | 11 - src/qemu/qemu_driver.c | 543 ++++++++++++++++++++------------ src/qemu/qemu_migration.c | 29 ++ src/qemu/qemu_migration.h | 32 +- src/qemu/qemu_snapshot.c | 27 -- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 +- src/remote_protocol-structs | 21 +- src/util/meson.build | 1 + src/util/virhostcpu.c | 10 +- src/util/virhostcpu.h | 6 +- src/util/virhostmem.c | 53 ++-- src/util/virhostmem.h | 11 +- src/util/virintrospection.c | 82 +++++ src/util/virintrospection.h | 20 ++ src/util/virnodesuspend.c | 5 +- src/util/virnodesuspend.h | 3 +- src/util/virtypedparam-public.c | 54 ++-- src/util/virtypedparam.c | 222 +++++++++---- src/util/virtypedparam.h | 26 +- src/vz/vz_driver.c | 12 +- tests/virhostcputest.c | 2 +- tools/virsh-domain.c | 59 ++++ tools/virsh-host.c | 43 +++ 44 files changed, 1384 insertions(+), 459 deletions(-) create mode 100644 scripts/genintrospection.py create mode 100644 src/util/virintrospection.c create mode 100644 src/util/virintrospection.h -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Fixes: a10b3ffebb6c498b357fd546c737d152cdf3e77d Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/remote_protocol-structs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 0f87d13a5a..d11a8f91a9 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1051,13 +1051,13 @@ struct remote_domain_get_block_io_tune_ret { int nparams; }; struct remote_domain_set_throttle_group_args { - remote_nonnull_domain dom; - remote_nonnull_string group; - struct { - u_int params_len; - remote_typed_param * params_val; - } params; - u_int flags; + remote_nonnull_domain dom; + remote_nonnull_string group; + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; }; struct remote_domain_del_throttle_group_args { remote_nonnull_domain dom; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Reformat qemu_driver.c to use the contemporary coding style. It will help also for the upcoming script for generating list of supported flags for APIs. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 212 +++++++++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 70 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d227ac58cd..80b21d4650 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1078,10 +1078,11 @@ qemuConnectURIProbe(char **uri) return 0; } -static virDrvOpenStatus qemuConnectOpen(virConnectPtr conn, - virConnectAuthPtr auth G_GNUC_UNUSED, - virConf *conf G_GNUC_UNUSED, - unsigned int flags) +static virDrvOpenStatus +qemuConnectOpen(virConnectPtr conn, + virConnectAuthPtr auth G_GNUC_UNUSED, + virConf *conf G_GNUC_UNUSED, + unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); @@ -1123,7 +1124,8 @@ static virDrvOpenStatus qemuConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_SUCCESS; } -static int qemuConnectClose(virConnectPtr conn) +static int +qemuConnectClose(virConnectPtr conn) { virQEMUDriver *driver = conn->privateData; @@ -1172,7 +1174,9 @@ qemuConnectSupportsFeature(virConnectPtr conn, int feature) } } -static const char *qemuConnectGetType(virConnectPtr conn) { +static const char * +qemuConnectGetType(virConnectPtr conn) +{ if (virConnectGetTypeEnsureACL(conn) < 0) return NULL; @@ -1180,19 +1184,22 @@ static const char *qemuConnectGetType(virConnectPtr conn) { } -static int qemuConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED) +static int +qemuConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED) { /* Trivially secure, since always inside the daemon */ return 1; } -static int qemuConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED) +static int +qemuConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED) { /* Not encrypted, but remote driver takes care of that */ return 0; } -static int qemuConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED) +static int +qemuConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED) { return 1; } @@ -1221,7 +1228,8 @@ qemuConnectGetSysinfo(virConnectPtr conn, unsigned int flags) } static int -qemuConnectGetMaxVcpus(virConnectPtr conn G_GNUC_UNUSED, const char *type) +qemuConnectGetMaxVcpus(virConnectPtr conn G_GNUC_UNUSED, + const char *type) { if (virConnectGetMaxVcpusEnsureACL(conn) < 0) return -1; @@ -1241,7 +1249,9 @@ qemuConnectGetMaxVcpus(virConnectPtr conn G_GNUC_UNUSED, const char *type) } -static char *qemuConnectGetCapabilities(virConnectPtr conn) { +static char * +qemuConnectGetCapabilities(virConnectPtr conn) +{ virQEMUDriver *driver = conn->privateData; g_autoptr(virCaps) caps = NULL; @@ -1361,8 +1371,9 @@ qemuDomainHelperGetVcpus(virDomainObj *vm, } -static virDomainPtr qemuDomainLookupByID(virConnectPtr conn, - int id) +static virDomainPtr +qemuDomainLookupByID(virConnectPtr conn, + int id) { virQEMUDriver *driver = conn->privateData; virDomainObj *vm; @@ -1386,8 +1397,9 @@ static virDomainPtr qemuDomainLookupByID(virConnectPtr conn, return dom; } -static virDomainPtr qemuDomainLookupByUUID(virConnectPtr conn, - const unsigned char *uuid) +static virDomainPtr +qemuDomainLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) { virQEMUDriver *driver = conn->privateData; virDomainObj *vm; @@ -1413,8 +1425,9 @@ static virDomainPtr qemuDomainLookupByUUID(virConnectPtr conn, return dom; } -static virDomainPtr qemuDomainLookupByName(virConnectPtr conn, - const char *name) +static virDomainPtr +qemuDomainLookupByName(virConnectPtr conn, + const char *name) { virQEMUDriver *driver = conn->privateData; virDomainObj *vm; @@ -1439,7 +1452,8 @@ static virDomainPtr qemuDomainLookupByName(virConnectPtr conn, } -static int qemuDomainIsActive(virDomainPtr dom) +static int +qemuDomainIsActive(virDomainPtr dom) { virDomainObj *obj; int ret = -1; @@ -1457,7 +1471,8 @@ static int qemuDomainIsActive(virDomainPtr dom) return ret; } -static int qemuDomainIsPersistent(virDomainPtr dom) +static int +qemuDomainIsPersistent(virDomainPtr dom) { virDomainObj *obj; int ret = -1; @@ -1475,7 +1490,8 @@ static int qemuDomainIsPersistent(virDomainPtr dom) return ret; } -static int qemuDomainIsUpdated(virDomainPtr dom) +static int +qemuDomainIsUpdated(virDomainPtr dom) { virDomainObj *obj; int ret = -1; @@ -1493,7 +1509,9 @@ static int qemuDomainIsUpdated(virDomainPtr dom) return ret; } -static int qemuConnectGetVersion(virConnectPtr conn, unsigned long *version) +static int +qemuConnectGetVersion(virConnectPtr conn, + unsigned long *version) { virQEMUDriver *driver = conn->privateData; unsigned int qemuVersion = 0; @@ -1515,7 +1533,8 @@ static int qemuConnectGetVersion(virConnectPtr conn, unsigned long *version) } -static char *qemuConnectGetHostname(virConnectPtr conn) +static char * +qemuConnectGetHostname(virConnectPtr conn) { if (virConnectGetHostnameEnsureACL(conn) < 0) return NULL; @@ -1524,7 +1543,10 @@ static char *qemuConnectGetHostname(virConnectPtr conn) } -static int qemuConnectListDomains(virConnectPtr conn, int *ids, int nids) +static int +qemuConnectListDomains(virConnectPtr conn, + int *ids, + int nids) { virQEMUDriver *driver = conn->privateData; @@ -1535,7 +1557,9 @@ static int qemuConnectListDomains(virConnectPtr conn, int *ids, int nids) virConnectListDomainsCheckACL, conn); } -static int qemuConnectNumOfDomains(virConnectPtr conn) + +static int +qemuConnectNumOfDomains(virConnectPtr conn) { virQEMUDriver *driver = conn->privateData; @@ -1547,9 +1571,10 @@ static int qemuConnectNumOfDomains(virConnectPtr conn) } -static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, - const char *xml, - unsigned int flags) +static virDomainPtr +qemuDomainCreateXML(virConnectPtr conn, + const char *xml, + unsigned int flags) { virQEMUDriver *driver = conn->privateData; g_autoptr(virDomainDef) def = NULL; @@ -1637,7 +1662,8 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, } -static int qemuDomainSuspend(virDomainPtr dom) +static int +qemuDomainSuspend(virDomainPtr dom) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -1687,7 +1713,8 @@ static int qemuDomainSuspend(virDomainPtr dom) } -static int qemuDomainResume(virDomainPtr dom) +static int +qemuDomainResume(virDomainPtr dom) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -1804,7 +1831,9 @@ qemuDomainShutdownFlagsMonitor(virDomainObj *vm, } -static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) +static int +qemuDomainShutdownFlags(virDomainPtr dom, + unsigned int flags) { virDomainObj *vm; int ret = -1; @@ -1862,7 +1891,9 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) return ret; } -static int qemuDomainShutdown(virDomainPtr dom) + +static int +qemuDomainShutdown(virDomainPtr dom) { return qemuDomainShutdownFlags(dom, 0); } @@ -2112,7 +2143,10 @@ qemuDomainDestroy(virDomainPtr dom) return qemuDomainDestroyFlags(dom, 0); } -static char *qemuDomainGetOSType(virDomainPtr dom) { + +static char * +qemuDomainGetOSType(virDomainPtr dom) +{ virDomainObj *vm; char *type = NULL; @@ -2129,6 +2163,7 @@ static char *qemuDomainGetOSType(virDomainPtr dom) { return type; } + /* Returns max memory in kb, 0 if error */ static unsigned long long qemuDomainGetMaxMemory(virDomainPtr dom) @@ -2149,8 +2184,11 @@ qemuDomainGetMaxMemory(virDomainPtr dom) return ret; } -static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, - unsigned int flags) + +static int +qemuDomainSetMemoryFlags(virDomainPtr dom, + unsigned long newmem, + unsigned int flags) { virQEMUDriver *driver = dom->conn->privateData; qemuDomainObjPrivate *priv; @@ -2279,18 +2317,27 @@ static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem, return ret; } -static int qemuDomainSetMemory(virDomainPtr dom, unsigned long newmem) + +static int +qemuDomainSetMemory(virDomainPtr dom, + unsigned long newmem) { return qemuDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE); } -static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) + +static int +qemuDomainSetMaxMemory(virDomainPtr dom, + unsigned long memory) { return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); } -static int qemuDomainSetMemoryStatsPeriod(virDomainPtr dom, int period, - unsigned int flags) + +static int +qemuDomainSetMemoryStatsPeriod(virDomainPtr dom, + int period, + unsigned int flags) { virQEMUDriver *driver = dom->conn->privateData; qemuDomainObjPrivate *priv; @@ -2360,7 +2407,10 @@ static int qemuDomainSetMemoryStatsPeriod(virDomainPtr dom, int period, return ret; } -static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) + +static int +qemuDomainInjectNMI(virDomainPtr domain, + unsigned int flags) { virDomainObj *vm = NULL; int ret = -1; @@ -2394,12 +2444,14 @@ static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) return ret; } -static int qemuDomainSendKey(virDomainPtr domain, - unsigned int codeset, - unsigned int holdtime, - unsigned int *keycodes, - int nkeycodes, - unsigned int flags) + +static int +qemuDomainSendKey(virDomainPtr domain, + unsigned int codeset, + unsigned int holdtime, + unsigned int *keycodes, + int nkeycodes, + unsigned int flags) { virDomainObj *vm = NULL; int ret = -1; @@ -5641,7 +5693,9 @@ qemuDomainSetIOThreadParams(virDomainPtr dom, } -static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel) +static int +qemuDomainGetSecurityLabel(virDomainPtr dom, + virSecurityLabelPtr seclabel) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -5682,8 +5736,10 @@ static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr secl return ret; } -static int qemuDomainGetSecurityLabelList(virDomainPtr dom, - virSecurityLabelPtr* seclabels) + +static int +qemuDomainGetSecurityLabelList(virDomainPtr dom, + virSecurityLabelPtr* seclabels) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -5744,8 +5800,9 @@ static int qemuDomainGetSecurityLabelList(virDomainPtr dom, } -static int qemuNodeGetSecurityModel(virConnectPtr conn, - virSecurityModelPtr secmodel) +static int +qemuNodeGetSecurityModel(virConnectPtr conn, + virSecurityModelPtr secmodel) { virQEMUDriver *driver = conn->privateData; g_autoptr(virCaps) caps = NULL; @@ -6199,9 +6256,9 @@ qemuDomainManagedSaveDefineXML(virDomainPtr dom, const char *dxml, } -static char -*qemuDomainGetXMLDesc(virDomainPtr dom, - unsigned int flags) +static char * +qemuDomainGetXMLDesc(virDomainPtr dom, + unsigned int flags) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -6245,10 +6302,11 @@ static char } -static char *qemuConnectDomainXMLToNative(virConnectPtr conn, - const char *format, - const char *xmlData, - unsigned int flags) +static char * +qemuConnectDomainXMLToNative(virConnectPtr conn, + const char *format, + const char *xmlData, + unsigned int flags) { virQEMUDriver *driver = conn->privateData; g_autoptr(virDomainObj) vm = NULL; @@ -6308,8 +6366,11 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn, } -static int qemuConnectListDefinedDomains(virConnectPtr conn, - char **const names, int nnames) { +static int +qemuConnectListDefinedDomains(virConnectPtr conn, + char **const names, + int nnames) +{ virQEMUDriver *driver = conn->privateData; if (virConnectListDefinedDomainsEnsureACL(conn) < 0) @@ -6320,7 +6381,9 @@ static int qemuConnectListDefinedDomains(virConnectPtr conn, conn); } -static int qemuConnectNumOfDefinedDomains(virConnectPtr conn) + +static int +qemuConnectNumOfDefinedDomains(virConnectPtr conn) { virQEMUDriver *driver = conn->privateData; @@ -7794,14 +7857,18 @@ qemuDomainDetachDeviceAlias(virDomainPtr dom, } -static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml) +static int +qemuDomainDetachDevice(virDomainPtr dom, + const char *xml) { return qemuDomainDetachDeviceFlags(dom, xml, VIR_DOMAIN_AFFECT_LIVE); } -static int qemuDomainGetAutostart(virDomainPtr dom, - int *autostart) + +static int +qemuDomainGetAutostart(virDomainPtr dom, + int *autostart) { virDomainObj *vm; int ret = -1; @@ -7820,8 +7887,10 @@ static int qemuDomainGetAutostart(virDomainPtr dom, return ret; } -static int qemuDomainSetAutostart(virDomainPtr dom, - int autostart) + +static int +qemuDomainSetAutostart(virDomainPtr dom, + int autostart) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -7986,8 +8055,9 @@ qemuDomainSetAutostartOnce(virDomainPtr dom, } -static char *qemuDomainGetSchedulerType(virDomainPtr dom, - int *nparams) +static char * +qemuDomainGetSchedulerType(virDomainPtr dom, + int *nparams) { char *ret = NULL; virDomainObj *vm = NULL; @@ -18915,9 +18985,11 @@ qemuDomainRenameCallback(virDomainObj *vm, return ret; } -static int qemuDomainRename(virDomainPtr dom, - const char *new_name, - unsigned int flags) + +static int +qemuDomainRename(virDomainPtr dom, + const char *new_name, + unsigned int flags) { virQEMUDriver *driver = dom->conn->privateData; virDomainObj *vm = NULL; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Create 'virTypedParamValidateType' which will use the same logic encapsulated in a function. Use the error message wording from 'virTypedParamsValidate' as it contains less fluff. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/util/virtypedparam-public.c | 54 +++++++++++++++++++++------------ src/util/virtypedparam.c | 27 +++++++++++++++++ src/util/virtypedparam.h | 4 +++ 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/util/virtypedparam-public.c b/src/util/virtypedparam-public.c index 3486623a9c..8a953ed20f 100644 --- a/src/util/virtypedparam-public.c +++ b/src/util/virtypedparam-public.c @@ -147,18 +147,6 @@ virTypedParamsGet(virTypedParameterPtr params, } -#define VIR_TYPED_PARAM_CHECK_TYPE(check_type) \ - do { if (param->type != check_type) { \ - virReportError(VIR_ERR_INVALID_ARG, \ - _("Invalid type '%1$s' requested for parameter '%2$s', actual type is '%3$s'"), \ - virTypedParameterTypeToString(check_type), \ - name, \ - virTypedParameterTypeToString(param->type)); \ - virDispatchError(NULL); \ - return -1; \ - } } while (0) - - /** * virTypedParamsGetInt: * @params: array of typed parameters @@ -189,7 +177,11 @@ virTypedParamsGetInt(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_INT); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_INT) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = param->value.i; @@ -227,7 +219,11 @@ virTypedParamsGetUInt(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_UINT); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_UINT) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = param->value.ui; @@ -265,7 +261,11 @@ virTypedParamsGetLLong(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_LLONG); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_LLONG) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = param->value.l; @@ -303,7 +303,11 @@ virTypedParamsGetULLong(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_ULLONG); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_ULLONG) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = param->value.ul; @@ -341,7 +345,11 @@ virTypedParamsGetDouble(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_DOUBLE); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_DOUBLE) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = param->value.d; @@ -379,7 +387,11 @@ virTypedParamsGetBoolean(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_BOOLEAN); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_BOOLEAN) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = !!param->value.b; @@ -419,7 +431,11 @@ virTypedParamsGetString(virTypedParameterPtr params, if (!(param = virTypedParamsGet(params, nparams, name))) return 0; - VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_STRING); + if (virTypedParamValidateType(param, VIR_TYPED_PARAM_STRING) < 0) { + virDispatchError(NULL); + return -1; + } + if (value) *value = param->value.s; diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index f25530a735..0b40c14f90 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -42,6 +42,33 @@ VIR_ENUM_IMPL(virTypedParameter, "string", ); + +/** + * virTypedParamValidateType: + * @param: typed parameter to validate + * @expected_type: type to look for + * + * Validates that @param is a parameter of @expected type. + * + * Returns 0 on success; -1 on error and reports an error. + */ +int +virTypedParamValidateType(virTypedParameterPtr param, + unsigned int expected_type) +{ + if (param->type != expected_type) { + virReportError(VIR_ERR_INVALID_ARG, + _("invalid type '%1$s' for parameter '%2$s', expected '%3$s'"), + virTypedParameterTypeToString(expected_type), + param->field, + virTypedParameterTypeToString(param->type)); + return -1; + } + + return 0; +} + + static int virTypedParamsSortName(const void *left, const void *right, diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index 774744244a..c1fc28c612 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -63,6 +63,10 @@ struct _virTypedParameterRemote { virTypedParameterRemoteValue value; }; +int +virTypedParamValidateType(virTypedParameterPtr param, + unsigned int expected_type) + G_GNUC_WARN_UNUSED_RESULT; int virTypedParamsValidate(virTypedParameterPtr params, -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> If the actual type of the typed parameter is an invalid number the type checker would still attempt to convert it to a string resuling in an attempt to print a NULL string. libc saves us from the crash but the error message is still wrong. Fix it. Fixes: 54dd75fd97339dd49a54554e9327e5680c72132b Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/util/virtypedparam.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 0b40c14f90..6cfdd3276d 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -56,6 +56,13 @@ int virTypedParamValidateType(virTypedParameterPtr param, unsigned int expected_type) { + if (param->type <= 0 || param->type >= VIR_TYPED_PARAM_LAST) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown type ('%1$d') of parameter '%2$s'"), + param->type, param->field); + return -1; + } + if (param->type != expected_type) { virReportError(VIR_ERR_INVALID_ARG, _("invalid type '%1$s' for parameter '%2$s', expected '%3$s'"), -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Replace the internals of the macro by a function so that 'virTypedParameterToString' doesn't need to be exported as it also adds mappings for values which don't exist in the public API. This change also prevents a NULL to be passed to string formatters in case when the caller sends an unknown typed parameter type as we now also make sure that the type is in range. Fixes: 54dd75fd97339dd49a54554e9327e5680c72132b Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virtypedparam.c | 25 +++++++++++++++++++++++++ src/util/virtypedparam.h | 11 +++++------ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cf0e71cc6a..9f02f74847 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3652,6 +3652,7 @@ virTPMSwtpmSetupFeatureTypeFromString; # util/virtypedparam.h +virTypedParamDebugstr; virTypedParameterAssign; virTypedParameterToString; virTypedParameterTypeFromString; diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 6cfdd3276d..77c9279eff 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -1109,3 +1109,28 @@ virTypedParamListAddDouble(virTypedParamList *list, virTypedParamSetNameVPrintf(list, par, namefmt, ap); va_end(ap); } + + +/** + * virTypedParamDebugstr: + * @param: typed parameter + * + * Format @param into a string used for debug prints in public API handlers. + * This must make sure to work on unknown typed parameter types. + * + * Returns the formatted string; caller must free it. + */ +char * +virTypedParamDebugstr(virTypedParameterPtr param) +{ + g_autofree char *value = virTypedParameterToString(param); + int type = param->type; + + if (type < 0 || type > VIR_TYPED_PARAM_LAST) + type = 0; + + return g_strdup_printf("params[\"%s\"]=(%s)%s", + param->field, + virTypedParameterTypeToString(type), + NULLSTR(value)); +} diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index c1fc28c612..3d6f6b999c 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -140,18 +140,17 @@ virTypedParamsSerialize(virTypedParameterPtr params, VIR_ENUM_DECL(virTypedParameter); +char * +virTypedParamDebugstr(virTypedParameterPtr param); + #define VIR_TYPED_PARAMS_DEBUG(params, nparams) \ do { \ int _i; \ if (!params) \ break; \ for (_i = 0; _i < (nparams); _i++) { \ - char *_value = virTypedParameterToString((params) + _i); \ - VIR_DEBUG("params[\"%s\"]=(%s)%s", \ - (params)[_i].field, \ - virTypedParameterTypeToString((params)[_i].type), \ - NULLSTR(_value)); \ - VIR_FREE(_value); \ + g_autofree char *_debugstr = virTypedParamDebugstr((params) + _i); \ + VIR_DEBUG("%s", _debugstr); \ } \ } while (0) -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The enum handler implementation has already some special values, upcoming patches will add more so keep the only internal to avoid surprises. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt_private.syms | 2 -- src/util/virtypedparam.c | 2 ++ src/util/virtypedparam.h | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9f02f74847..37c9c73d92 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3655,8 +3655,6 @@ virTPMSwtpmSetupFeatureTypeFromString; virTypedParamDebugstr; virTypedParameterAssign; virTypedParameterToString; -virTypedParameterTypeFromString; -virTypedParameterTypeToString; virTypedParamListAddBoolean; virTypedParamListAddDouble; virTypedParamListAddInt; diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 77c9279eff..0b494e60fd 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -30,6 +30,8 @@ #define VIR_FROM_THIS VIR_FROM_NONE +VIR_ENUM_DECL(virTypedParameter); + VIR_ENUM_IMPL(virTypedParameter, VIR_TYPED_PARAM_LAST, "unknown", diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index 3d6f6b999c..819166ff1b 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -138,8 +138,6 @@ virTypedParamsSerialize(virTypedParameterPtr params, unsigned int *remote_params_len, unsigned int flags); -VIR_ENUM_DECL(virTypedParameter); - char * virTypedParamDebugstr(virTypedParameterPtr param); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> 'virTypedParamsValidate' has special logic to handle the internal VIR_TYPED_PARAM_UNSIGNED type, but unfortunately the implementation of the error which is reported is flawed as it only updated the 'expecttype' string when the type actually matched. In cases when it didn't we'd report the following error: error: invalid argument: invalid type 'string' for parameter 'poll_shrink', expected '(null)' To fix it we can re-implement the validation part by using virTypedParamValidateType simply by adding the VIR_TYPED_PARAM_UNSIGNED to 'virTypedParameterTypeToString' handling which is now private and adding logic to allow either one of the unsigned types, which allows us to use the same function in both cases, simplifying the code. Fixes: 07652410a7af98ca03281c4bfe20415ced26a44a Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/util/virtypedparam.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 0b494e60fd..ec8046b998 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -33,7 +33,7 @@ VIR_ENUM_DECL(virTypedParameter); VIR_ENUM_IMPL(virTypedParameter, - VIR_TYPED_PARAM_LAST, + VIR_TYPED_PARAM_UNSIGNED + 1, "unknown", "int", "uint", @@ -42,6 +42,8 @@ VIR_ENUM_IMPL(virTypedParameter, "double", "boolean", "string", + "", /* VIR_TYPED_PARAM_LAST */ + "uint, ullong", /* VIR_TYPED_PARAM_UNSIGNED */ ); @@ -50,7 +52,9 @@ VIR_ENUM_IMPL(virTypedParameter, * @param: typed parameter to validate * @expected_type: type to look for * - * Validates that @param is a parameter of @expected type. + * Validates that @param is a parameter of @expected type. If @expected_type is + * VIR_TYPED_PARAM_UNSIGNED, both VIR_TYPED_PARAM_UINT and VIR_TYPED_PARAM_ULLONG + * are accepted. * * Returns 0 on success; -1 on error and reports an error. */ @@ -65,7 +69,10 @@ virTypedParamValidateType(virTypedParameterPtr param, return -1; } - if (param->type != expected_type) { + if (!(param->type == expected_type || + (expected_type == VIR_TYPED_PARAM_UNSIGNED && + (param->type == VIR_TYPED_PARAM_UINT || + param->type == VIR_TYPED_PARAM_ULLONG)))) { virReportError(VIR_ERR_INVALID_ARG, _("invalid type '%1$s' for parameter '%2$s', expected '%3$s'"), virTypedParameterTypeToString(expected_type), @@ -147,9 +154,6 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) if (STRNEQ(sorted[i].field, keys[j].field)) { j++; } else { - const char *expecttype = virTypedParameterTypeToString(keys[j].type); - int type = sorted[i].type; - if (STREQ_NULLABLE(last_name, sorted[i].field) && !(keys[j].value.i & VIR_TYPED_PARAM_MULTIPLE)) { virReportError(VIR_ERR_INVALID_ARG, @@ -158,24 +162,9 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) return -1; } - if (keys[j].type == VIR_TYPED_PARAM_UNSIGNED && - (type == VIR_TYPED_PARAM_UINT || - type == VIR_TYPED_PARAM_ULLONG)) { - type = VIR_TYPED_PARAM_UNSIGNED; - expecttype = "uint, ullong"; - } - - if (type != keys[j].type) { - const char *badtype; - - badtype = virTypedParameterTypeToString(sorted[i].type); - if (!badtype) - badtype = virTypedParameterTypeToString(0); - virReportError(VIR_ERR_INVALID_ARG, - _("invalid type '%1$s' for parameter '%2$s', expected '%3$s'"), - badtype, sorted[i].field, expecttype); + if (virTypedParamValidateType(sorted + i, keys[j].type) < 0) return -1; - } + last_name = sorted[i].field; i++; } -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Validate also variables exported as 'extern' e.g. from the util submodule. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/check-symfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check-symfile.py b/scripts/check-symfile.py index c2ee405118..e4149b771e 100755 --- a/scripts/check-symfile.py +++ b/scripts/check-symfile.py @@ -61,7 +61,7 @@ for elflib in elflibs: for line in nm: line = line.decode("utf-8") - symmatch = re.search(r'''^\S+\s(?:[TBSDG])\s(\S+)\s*$''', line) + symmatch = re.search(r'''^\S+\s(?:[TBSDGR])\s(\S+)\s*$''', line) if symmatch is None: continue -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The utility functions which get CPU map and stats don't actually use the flags. Remove the argument and move the 'virCheckFlags' to driver implementation. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/bhyve/bhyve_driver.c | 8 ++++++-- src/ch/ch_driver.c | 7 +++++-- src/lxc/lxc_driver.c | 8 ++++++-- src/openvz/openvz_driver.c | 8 ++++++-- src/qemu/qemu_driver.c | 8 ++++++-- src/util/virhostcpu.c | 10 ++-------- src/util/virhostcpu.h | 6 ++---- src/vz/vz_driver.c | 8 ++++++-- tests/virhostcputest.c | 2 +- 9 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index c8dd1a728a..2718c074f3 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1145,10 +1145,12 @@ bhyveNodeGetCPUStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUStatsEnsureACL(conn) < 0) return -1; - return virHostCPUGetStats(cpuNum, params, nparams, flags); + return virHostCPUGetStats(cpuNum, params, nparams); } static int @@ -1359,10 +1361,12 @@ bhyveNodeGetCPUMap(virConnectPtr conn, unsigned int *online, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUMapEnsureACL(conn) < 0) return -1; - return virHostCPUGetMap(cpumap, online, flags); + return virHostCPUGetMap(cpumap, online); } static int diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 662857f88e..874fca2193 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -1642,12 +1642,15 @@ chDomainGetVcpuPinInfo(virDomain *dom, static int chNodeGetCPUMap(virConnectPtr conn, unsigned char **cpumap, - unsigned int *online, unsigned int flags) + unsigned int *online, + unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUMapEnsureACL(conn) < 0) return -1; - return virHostCPUGetMap(cpumap, online, flags); + return virHostCPUGetMap(cpumap, online); } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c0a93c0444..db00288900 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -4785,10 +4785,12 @@ lxcNodeGetCPUStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUStatsEnsureACL(conn) < 0) return -1; - return virHostCPUGetStats(cpuNum, params, nparams, flags); + return virHostCPUGetStats(cpuNum, params, nparams); } @@ -4866,10 +4868,12 @@ lxcNodeGetCPUMap(virConnectPtr conn, unsigned int *online, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUMapEnsureACL(conn) < 0) return -1; - return virHostCPUGetMap(cpumap, online, flags); + return virHostCPUGetMap(cpumap, online); } diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 19bdfa37f2..60b8a9534b 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1849,7 +1849,9 @@ openvzNodeGetCPUStats(virConnectPtr conn G_GNUC_UNUSED, int *nparams, unsigned int flags) { - return virHostCPUGetStats(cpuNum, params, nparams, flags); + virCheckFlags(0, -1); + + return virHostCPUGetStats(cpuNum, params, nparams); } @@ -1890,7 +1892,9 @@ openvzNodeGetCPUMap(virConnectPtr conn G_GNUC_UNUSED, unsigned int *online, unsigned int flags) { - return virHostCPUGetMap(cpumap, online, flags); + virCheckFlags(0, -1); + + return virHostCPUGetMap(cpumap, online); } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 80b21d4650..52c6ce2f27 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16384,10 +16384,12 @@ qemuNodeGetCPUStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUStatsEnsureACL(conn) < 0) return -1; - return virHostCPUGetStats(cpuNum, params, nparams, flags); + return virHostCPUGetStats(cpuNum, params, nparams); } @@ -16465,10 +16467,12 @@ qemuNodeGetCPUMap(virConnectPtr conn, unsigned int *online, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUMapEnsureACL(conn) < 0) return -1; - return virHostCPUGetMap(cpumap, online, flags); + return virHostCPUGetMap(cpumap, online); } diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index 870338edad..60743765a4 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -1043,11 +1043,8 @@ virHostCPUGetInfo(virArch hostarch G_GNUC_UNUSED, int virHostCPUGetStats(int cpuNum G_GNUC_UNUSED, virNodeCPUStatsPtr params G_GNUC_UNUSED, - int *nparams G_GNUC_UNUSED, - unsigned int flags) + int *nparams G_GNUC_UNUSED) { - virCheckFlags(0, -1); - #ifdef __linux__ { int ret; @@ -1144,14 +1141,11 @@ virHostCPUGetOnlineBitmap(void) int virHostCPUGetMap(unsigned char **cpumap, - unsigned int *online, - unsigned int flags) + unsigned int *online) { g_autoptr(virBitmap) cpus = NULL; int ncpus = virHostCPUGetCount(); - virCheckFlags(0, -1); - if (!cpumap && !online) return ncpus; diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h index 289ae41439..238054ed34 100644 --- a/src/util/virhostcpu.h +++ b/src/util/virhostcpu.h @@ -36,8 +36,7 @@ struct _virHostCPUTscInfo { int virHostCPUGetStats(int cpuNum, virNodeCPUStatsPtr params, - int *nparams, - unsigned int flags); + int *nparams); bool virHostCPUHasBitmap(void); virBitmap *virHostCPUGetPresentBitmap(void); @@ -49,8 +48,7 @@ int virHostCPUGetCount(void); int virHostCPUGetThreadsPerSubcore(virArch arch) ATTRIBUTE_MOCKABLE; int virHostCPUGetMap(unsigned char **cpumap, - unsigned int *online, - unsigned int flags); + unsigned int *online); int virHostCPUGetInfo(virArch hostarch, unsigned int *cpus, unsigned int *mhz, diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 2d8878fe7f..f8193367c9 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1000,10 +1000,12 @@ vzNodeGetCPUMap(virConnectPtr conn, unsigned int *online, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUMapEnsureACL(conn) < 0) return -1; - return virHostCPUGetMap(cpumap, online, flags); + return virHostCPUGetMap(cpumap, online); } static int @@ -1964,10 +1966,12 @@ vzNodeGetCPUStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetCPUStatsEnsureACL(conn) < 0) return -1; - return virHostCPUGetStats(cpuNum, params, nparams, flags); + return virHostCPUGetStats(cpuNum, params, nparams); } static int diff --git a/tests/virhostcputest.c b/tests/virhostcputest.c index 4b31b79444..e362ee8d39 100644 --- a/tests/virhostcputest.c +++ b/tests/virhostcputest.c @@ -249,7 +249,7 @@ linuxTestHostCPUGetMap(const void *data G_GNUC_UNUSED) { g_autofree unsigned char *cpumap = NULL; - int ncpus = virHostCPUGetMap(&cpumap, NULL, 0); + int ncpus = virHostCPUGetMap(&cpumap, NULL); g_autoptr(virBitmap) actual = virBitmapNewData(cpumap, VIR_DIV_UP(ncpus, 8)); g_autoptr(virBitmap) expected = NULL; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The utility functions which get memory stats don't actually use the flags. Remove the argument and move the 'virCheckFlags' to driver implementation. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/bhyve/bhyve_driver.c | 12 +++++++++--- src/ch/ch_driver.c | 4 +++- src/lxc/lxc_driver.c | 12 +++++++++--- src/openvz/openvz_driver.c | 4 +++- src/qemu/qemu_driver.c | 12 +++++++++--- src/util/virhostmem.c | 29 +++++++---------------------- src/util/virhostmem.h | 9 +++------ src/vz/vz_driver.c | 4 +++- 8 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 2718c074f3..8813413037 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1160,10 +1160,12 @@ bhyveNodeGetMemoryStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetMemoryStatsEnsureACL(conn) < 0) return -1; - return virHostMemGetStats(cellNum, params, nparams, flags); + return virHostMemGetStats(cellNum, params, nparams); } static int @@ -1375,10 +1377,12 @@ bhyveNodeGetMemoryParameters(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + if (virNodeGetMemoryParametersEnsureACL(conn) < 0) return -1; - return virHostMemGetParameters(params, nparams, flags); + return virHostMemGetParameters(params, nparams); } static int @@ -1387,10 +1391,12 @@ bhyveNodeSetMemoryParameters(virConnectPtr conn, int nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeSetMemoryParametersEnsureACL(conn) < 0) return -1; - return virHostMemSetParameters(params, nparams, flags); + return virHostMemSetParameters(params, nparams); } static char * diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 874fca2193..ff3cb55c69 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -2304,10 +2304,12 @@ chNodeGetMemoryStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetMemoryStatsEnsureACL(conn) < 0) return -1; - return virHostMemGetStats(cellNum, params, nparams, flags); + return virHostMemGetStats(cellNum, params, nparams); } static int diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index db00288900..c51da98777 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -4801,10 +4801,12 @@ lxcNodeGetMemoryStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetMemoryStatsEnsureACL(conn) < 0) return -1; - return virHostMemGetStats(cellNum, params, nparams, flags); + return virHostMemGetStats(cellNum, params, nparams); } @@ -4842,10 +4844,12 @@ lxcNodeGetMemoryParameters(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + if (virNodeGetMemoryParametersEnsureACL(conn) < 0) return -1; - return virHostMemGetParameters(params, nparams, flags); + return virHostMemGetParameters(params, nparams); } @@ -4855,10 +4859,12 @@ lxcNodeSetMemoryParameters(virConnectPtr conn, int nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeSetMemoryParametersEnsureACL(conn) < 0) return -1; - return virHostMemSetParameters(params, nparams, flags); + return virHostMemSetParameters(params, nparams); } diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 60b8a9534b..173ccfbe6e 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1862,7 +1862,9 @@ openvzNodeGetMemoryStats(virConnectPtr conn G_GNUC_UNUSED, int *nparams, unsigned int flags) { - return virHostMemGetStats(cellNum, params, nparams, flags); + virCheckFlags(0, -1); + + return virHostMemGetStats(cellNum, params, nparams); } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 52c6ce2f27..f121a0e788 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16400,10 +16400,12 @@ qemuNodeGetMemoryStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetMemoryStatsEnsureACL(conn) < 0) return -1; - return virHostMemGetStats(cellNum, params, nparams, flags); + return virHostMemGetStats(cellNum, params, nparams); } @@ -16441,10 +16443,12 @@ qemuNodeGetMemoryParameters(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + if (virNodeGetMemoryParametersEnsureACL(conn) < 0) return -1; - return virHostMemGetParameters(params, nparams, flags); + return virHostMemGetParameters(params, nparams); } @@ -16454,10 +16458,12 @@ qemuNodeSetMemoryParameters(virConnectPtr conn, int nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeSetMemoryParametersEnsureACL(conn) < 0) return -1; - return virHostMemSetParameters(params, nparams, flags); + return virHostMemSetParameters(params, nparams); } diff --git a/src/util/virhostmem.c b/src/util/virhostmem.c index 09a322fdea..7d7deac34b 100644 --- a/src/util/virhostmem.c +++ b/src/util/virhostmem.c @@ -248,11 +248,8 @@ virHostMemGetStatsLinux(FILE *meminfo, int virHostMemGetStats(int cellNum G_GNUC_UNUSED, virNodeMemoryStatsPtr params G_GNUC_UNUSED, - int *nparams G_GNUC_UNUSED, - unsigned int flags) + int *nparams G_GNUC_UNUSED) { - virCheckFlags(0, -1); - #ifdef __linux__ { int ret; @@ -356,14 +353,11 @@ virHostMemParametersAreAllSupported(virTypedParameterPtr params, #ifdef __linux__ int -virHostMemSetParameters(virTypedParameterPtr params G_GNUC_UNUSED, - int nparams G_GNUC_UNUSED, - unsigned int flags) +virHostMemSetParameters(virTypedParameterPtr params, + int nparams) { size_t i; - virCheckFlags(0, -1); - if (virTypedParamsValidate(params, nparams, VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, VIR_TYPED_PARAM_UINT, @@ -387,11 +381,8 @@ virHostMemSetParameters(virTypedParameterPtr params G_GNUC_UNUSED, #else int virHostMemSetParameters(virTypedParameterPtr params G_GNUC_UNUSED, - int nparams G_GNUC_UNUSED, - unsigned int flags) + int nparams G_GNUC_UNUSED) { - virCheckFlags(0, -1); - virReportError(VIR_ERR_NO_SUPPORT, "%s", _("node set memory parameters not implemented on this platform")); return -1; @@ -443,9 +434,8 @@ virHostMemGetParameterValue(const char *field, #define NODE_MEMORY_PARAMETERS_NUM 8 #ifdef __linux__ int -virHostMemGetParameters(virTypedParameterPtr params G_GNUC_UNUSED, - int *nparams G_GNUC_UNUSED, - unsigned int flags) +virHostMemGetParameters(virTypedParameterPtr params, + int *nparams) { unsigned int pages_to_scan; unsigned int sleep_millisecs; @@ -458,8 +448,6 @@ virHostMemGetParameters(virTypedParameterPtr params G_GNUC_UNUSED, size_t i; int ret; - virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); - if ((*nparams) == 0) { *nparams = NODE_MEMORY_PARAMETERS_NUM; return 0; @@ -580,11 +568,8 @@ virHostMemGetParameters(virTypedParameterPtr params G_GNUC_UNUSED, #else int virHostMemGetParameters(virTypedParameterPtr params G_GNUC_UNUSED, - int *nparams G_GNUC_UNUSED, - unsigned int flags) + int *nparams G_GNUC_UNUSED) { - virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); - virReportError(VIR_ERR_NO_SUPPORT, "%s", _("node get memory parameters not implemented on this platform")); return -1; diff --git a/src/util/virhostmem.h b/src/util/virhostmem.h index 5c8d46cfa4..4a0d692402 100644 --- a/src/util/virhostmem.h +++ b/src/util/virhostmem.h @@ -25,8 +25,7 @@ int virHostMemGetStats(int cellNum, virNodeMemoryStatsPtr params, - int *nparams, - unsigned int flags); + int *nparams); int virHostMemGetCellsFree(unsigned long long *freeMems, int startCell, int maxCells); @@ -34,12 +33,10 @@ int virHostMemGetInfo(unsigned long long *mem, unsigned long long *freeMem); int virHostMemGetParameters(virTypedParameterPtr params, - int *nparams, - unsigned int flags); + int *nparams); int virHostMemSetParameters(virTypedParameterPtr params, - int nparams, - unsigned int flags); + int nparams); int virHostMemGetFreePages(unsigned int npages, unsigned int *pages, diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index f8193367c9..3dea4d450d 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1981,10 +1981,12 @@ vzNodeGetMemoryStats(virConnectPtr conn, int *nparams, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeGetMemoryStatsEnsureACL(conn) < 0) return -1; - return virHostMemGetStats(cellNum, params, nparams, flags); + return virHostMemGetStats(cellNum, params, nparams); } static int -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Remove the unused argument and bump the 'virCheckFlags' calls to the top level. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/lxc/lxc_driver.c | 4 +++- src/qemu/qemu_driver.c | 4 +++- src/util/virnodesuspend.c | 5 +---- src/util/virnodesuspend.h | 3 +-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c51da98777..df8e4e06ec 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -4889,10 +4889,12 @@ lxcNodeSuspendForDuration(virConnectPtr conn, unsigned long long duration, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeSuspendForDurationEnsureACL(conn) < 0) return -1; - return virNodeSuspend(target, duration, flags); + return virNodeSuspend(target, duration); } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f121a0e788..558c22982d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16488,10 +16488,12 @@ qemuNodeSuspendForDuration(virConnectPtr conn, unsigned long long duration, unsigned int flags) { + virCheckFlags(0, -1); + if (virNodeSuspendForDurationEnsureACL(conn) < 0) return -1; - return virNodeSuspend(target, duration, flags); + return virNodeSuspend(target, duration); } static int diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index 37659f13ad..5b65643d06 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -138,16 +138,13 @@ static void virNodeSuspendHelper(void *cmdString) * operation is still in progress. */ int virNodeSuspend(unsigned int target, - unsigned long long duration, - unsigned int flags) + unsigned long long duration) { static virThread thread; const char *cmdString = NULL; unsigned int supported; VIR_LOCK_GUARD lock = { NULL }; - virCheckFlags(0, -1); - if (virNodeSuspendGetTargetMask(&supported) < 0) return -1; diff --git a/src/util/virnodesuspend.h b/src/util/virnodesuspend.h index f767961bff..dc8324df1d 100644 --- a/src/util/virnodesuspend.h +++ b/src/util/virnodesuspend.h @@ -24,7 +24,6 @@ #include "internal.h" int virNodeSuspend(unsigned int target, - unsigned long long duration, - unsigned int flags); + unsigned long long duration); int virNodeSuspendGetTargetMask(unsigned int *bitmask); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Move the flag check to the top level to allow programatic introspection of supported flags. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_backup.c | 8 +------- src/qemu/qemu_backup.h | 3 +-- src/qemu/qemu_driver.c | 7 ++++++- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index 65a083ea74..a0544c83dc 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -808,9 +808,6 @@ qemuBackupBegin(virDomainObj *vm, int ret = -1; g_autoptr(qemuFDPassDirect) fdpass = NULL; - virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL | - VIR_DOMAIN_BACKUP_BEGIN_PRESERVE_SHUTDOWN_DOMAIN, -1); - if (!(def = virDomainBackupDefParseString(backupXML, priv->driver->xmlopt, 0))) return -1; @@ -986,16 +983,13 @@ qemuBackupBegin(virDomainObj *vm, char * -qemuBackupGetXMLDesc(virDomainObj *vm, - unsigned int flags) +qemuBackupGetXMLDesc(virDomainObj *vm) { qemuDomainObjPrivate *priv = vm->privateData; g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; virDomainBackupDef *backup; - virCheckFlags(0, NULL); - if (!(backup = qemuDomainGetBackup(vm))) return NULL; diff --git a/src/qemu/qemu_backup.h b/src/qemu/qemu_backup.h index c259883bca..602a1e6a99 100644 --- a/src/qemu/qemu_backup.h +++ b/src/qemu/qemu_backup.h @@ -25,8 +25,7 @@ qemuBackupBegin(virDomainObj *vm, unsigned int flags); char * -qemuBackupGetXMLDesc(virDomainObj *vm, - unsigned int flags); +qemuBackupGetXMLDesc(virDomainObj *vm); void qemuBackupJobCancelBlockjobs(virDomainObj *vm, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 558c22982d..8027b5775e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13627,6 +13627,9 @@ qemuDomainBackupBegin(virDomainPtr domain, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL | + VIR_DOMAIN_BACKUP_BEGIN_PRESERVE_SHUTDOWN_DOMAIN, -1); + if (!(vm = qemuDomainObjFromDomain(domain))) goto cleanup; @@ -13648,13 +13651,15 @@ qemuDomainBackupGetXMLDesc(virDomainPtr domain, virDomainObj *vm = NULL; char *ret = NULL; + virCheckFlags(0, NULL); + if (!(vm = qemuDomainObjFromDomain(domain))) return NULL; if (virDomainBackupGetXMLDescEnsureACL(domain->conn, vm->def) < 0) goto cleanup; - ret = qemuBackupGetXMLDesc(vm, flags); + ret = qemuBackupGetXMLDesc(vm); cleanup: virDomainObjEndAPI(&vm); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Move the flag check to the top level to allow programatic introspection of supported flags. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8027b5775e..e6ad16f31b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7417,9 +7417,6 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObj *vm, unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE | VIR_DOMAIN_DEF_PARSE_ABI_UPDATE; - virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | - VIR_DOMAIN_AFFECT_CONFIG, -1); - cfg = virQEMUDriverGetConfig(driver); /* The config and live post processing address auto-generation algorithms @@ -7512,6 +7509,9 @@ qemuDomainAttachDeviceFlags(virDomainPtr dom, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + if (!(vm = qemuDomainObjFromDomain(dom))) goto cleanup; @@ -7660,9 +7660,6 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriver *driver, unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; g_autoptr(virDomainDef) vmdef = NULL; - virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | - VIR_DOMAIN_AFFECT_CONFIG, -1); - cfg = virQEMUDriverGetConfig(driver); if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && @@ -7796,6 +7793,9 @@ qemuDomainDetachDeviceFlags(virDomainPtr dom, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + if (!(vm = qemuDomainObjFromDomain(dom))) goto cleanup; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Move the flag check to the top level to allow programatic introspection of supported flags. Extract the supported flags as a macro so that they can be reused in both coredump APIs. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e6ad16f31b..431b3b741e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3234,6 +3234,12 @@ doCoreDump(virQEMUDriver *driver, return ret; } +#define QEMU_DOMAIN_CORE_DUMP_FLAGS \ + VIR_DUMP_CRASH | \ + VIR_DUMP_BYPASS_CACHE | \ + VIR_DUMP_RESET | \ + VIR_DUMP_MEMORY_ONLY + static int qemuDomainCoreDumpWithFormat(virDomainPtr dom, @@ -3248,9 +3254,7 @@ qemuDomainCoreDumpWithFormat(virDomainPtr dom, int ret = -1; virObjectEvent *event = NULL; - virCheckFlags(VIR_DUMP_CRASH | - VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET | - VIR_DUMP_MEMORY_ONLY, -1); + virCheckFlags(QEMU_DOMAIN_CORE_DUMP_FLAGS, -1); if (!(vm = qemuDomainObjFromDomain(dom))) return -1; @@ -3343,6 +3347,8 @@ qemuDomainCoreDump(virDomainPtr dom, const char *path, unsigned int flags) { + virCheckFlags(QEMU_DOMAIN_CORE_DUMP_FLAGS, -1); + return qemuDomainCoreDumpWithFormat(dom, path, VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Move the flag check to the top level to allow programatic introspection of supported flags. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_checkpoint.c | 11 ----------- src/qemu/qemu_driver.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_checkpoint.c b/src/qemu/qemu_checkpoint.c index 193cf9a06a..f063b5a5c0 100644 --- a/src/qemu/qemu_checkpoint.c +++ b/src/qemu/qemu_checkpoint.c @@ -582,9 +582,6 @@ qemuCheckpointCreateXML(virDomainPtr domain, g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); g_autoptr(virDomainCheckpointDef) def = NULL; - virCheckFlags(VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE | - VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE_VALIDATE, NULL); - if (redefine) { parse_flags |= VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE; update_current = false; @@ -783,10 +780,6 @@ qemuCheckpointGetXMLDesc(virDomainObj *vm, virDomainCheckpointDef *chkdef; unsigned int format_flags; - virCheckFlags(VIR_DOMAIN_CHECKPOINT_XML_SECURE | - VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN | - VIR_DOMAIN_CHECKPOINT_XML_SIZE, NULL); - if (!(chk = qemuCheckpointObjFromCheckpoint(vm, checkpoint))) return NULL; @@ -847,10 +840,6 @@ qemuCheckpointDelete(virDomainObj *vm, struct virQEMUCheckpointReparent rep; bool metadata_only = !!(flags & VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY); - virCheckFlags(VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN | - VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY | - VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY, -1); - if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) return -1; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 431b3b741e..b0b5c12d47 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13448,6 +13448,9 @@ qemuDomainCheckpointCreateXML(virDomainPtr domain, virDomainObj *vm = NULL; virDomainCheckpointPtr checkpoint = NULL; + virCheckFlags(VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE | + VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE_VALIDATE, NULL); + if (!(vm = qemuDomainObjFromDomain(domain))) goto cleanup; @@ -13589,6 +13592,10 @@ qemuDomainCheckpointGetXMLDesc(virDomainCheckpointPtr checkpoint, virDomainObj *vm = NULL; char *xml = NULL; + virCheckFlags(VIR_DOMAIN_CHECKPOINT_XML_SECURE | + VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN | + VIR_DOMAIN_CHECKPOINT_XML_SIZE, NULL); + if (!(vm = qemuDomObjFromCheckpoint(checkpoint))) return NULL; @@ -13610,6 +13617,10 @@ qemuDomainCheckpointDelete(virDomainCheckpointPtr checkpoint, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN | + VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY | + VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY, -1); + if (!(vm = qemuDomObjFromCheckpoint(checkpoint))) return -1; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Create QEMU_DOMAIN_RESTORE_FLAGS define which collects all the flags used by either of the implementations of the 'Restore' API and move the flag checking into the implementation function so that it's available later for introspection. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b0b5c12d47..7f8958e45b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5843,6 +5843,11 @@ qemuNodeGetSecurityModel(virConnectPtr conn, return 0; } +#define QEMU_DOMAIN_RESTORE_FLAGS \ + VIR_DOMAIN_SAVE_BYPASS_CACHE | \ + VIR_DOMAIN_SAVE_RUNNING | \ + VIR_DOMAIN_SAVE_PAUSED | \ + VIR_DOMAIN_SAVE_RESET_NVRAM /** * qemuDomainRestoreInternal: @@ -5894,18 +5899,12 @@ qemuDomainRestoreInternal(virConnectPtr conn, virQEMUSaveData *data = NULL; virFileWrapperFd *wrapperFd = NULL; bool hook_taint = false; - bool reset_nvram = false; + bool reset_nvram = (flags & VIR_DOMAIN_SAVE_RESET_NVRAM) != 0; bool sparse = false; bool bypass_cache = (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0; g_autoptr(qemuMigrationParams) restoreParams = NULL; - virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE | - VIR_DOMAIN_SAVE_RUNNING | - VIR_DOMAIN_SAVE_PAUSED | - VIR_DOMAIN_SAVE_RESET_NVRAM, -1); - - if (flags & VIR_DOMAIN_SAVE_RESET_NVRAM) - reset_nvram = true; + virCheckFlags(QEMU_DOMAIN_RESTORE_FLAGS, -1); if (qemuSaveImageGetMetadata(driver, NULL, path, ensureACL, conn, &def, &data) < 0) { if (unlink_corrupt && @@ -6045,6 +6044,8 @@ qemuDomainRestoreFlags(virConnectPtr conn, const char *dxml, unsigned int flags) { + virCheckFlags(QEMU_DOMAIN_RESTORE_FLAGS, -1); + return qemuDomainRestoreInternal(conn, NULL, path, false, dxml, NULL, 0, flags, virDomainRestoreFlagsEnsureACL, VIR_ASYNC_JOB_START); @@ -6068,6 +6069,8 @@ qemuDomainRestoreParams(virConnectPtr conn, const char *dxml = NULL; int ret = -1; + virCheckFlags(QEMU_DOMAIN_RESTORE_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, VIR_DOMAIN_SAVE_PARAM_FILE, VIR_TYPED_PARAM_STRING, VIR_DOMAIN_SAVE_PARAM_DXML, VIR_TYPED_PARAM_STRING, -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Move the 'virCheckFlags' invocations to the top level driver function so that they become available for introspection. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 27 +++++++++++++++++++++++++++ src/qemu/qemu_snapshot.c | 27 --------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7f8958e45b..a2b5959e55 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13010,6 +13010,24 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, virDomainObj *vm = NULL; virDomainSnapshotPtr snapshot = NULL; + virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE | + VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT | + VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA | + VIR_DOMAIN_SNAPSHOT_CREATE_HALT | + VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY | + VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT | + VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE | + VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC | + VIR_DOMAIN_SNAPSHOT_CREATE_LIVE | + VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE, NULL); + + VIR_REQUIRE_FLAG_RET(VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE, + VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY, + NULL); + VIR_EXCLUSIVE_FLAGS_RET(VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, + VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE, + NULL); + if (!(vm = qemuDomainObjFromDomain(domain))) goto cleanup; @@ -13408,6 +13426,11 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING | + VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED | + VIR_DOMAIN_SNAPSHOT_REVERT_FORCE | + VIR_DOMAIN_SNAPSHOT_REVERT_RESET_NVRAM, -1); + if (!(vm = qemuDomObjFromSnapshot(snapshot))) goto cleanup; @@ -13429,6 +13452,10 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | + VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY | + VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1); + if (!(vm = qemuDomObjFromSnapshot(snapshot))) return -1; diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index 82ae38ca29..07548ca62e 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -2222,24 +2222,6 @@ qemuSnapshotCreateXML(virDomainPtr domain, g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); g_autoptr(virDomainSnapshotDef) def = NULL; - virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE | - VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT | - VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA | - VIR_DOMAIN_SNAPSHOT_CREATE_HALT | - VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY | - VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT | - VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE | - VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC | - VIR_DOMAIN_SNAPSHOT_CREATE_LIVE | - VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE, NULL); - - VIR_REQUIRE_FLAG_RET(VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE, - VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY, - NULL); - VIR_EXCLUSIVE_FLAGS_RET(VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, - VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE, - NULL); - if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot halt after transient domain snapshot")); @@ -2950,11 +2932,6 @@ qemuSnapshotRevert(virDomainObj *vm, g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); unsigned int start_flags = VIR_QEMU_PROCESS_START_GEN_VMID; - virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING | - VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED | - VIR_DOMAIN_SNAPSHOT_REVERT_FORCE | - VIR_DOMAIN_SNAPSHOT_REVERT_RESET_NVRAM, -1); - if (flags & VIR_DOMAIN_SNAPSHOT_REVERT_RESET_NVRAM) start_flags |= VIR_QEMU_PROCESS_START_RESET_NVRAM; @@ -4489,10 +4466,6 @@ qemuSnapshotDelete(virDomainObj *vm, bool stop_qemu = false; g_autoslist(qemuSnapshotDeleteExternalData) externalData = NULL; - virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | - VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY | - VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1); - if (virDomainObjBeginAsyncJob(vm, VIR_ASYNC_JOB_SNAPSHOT, VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_DELETE, flags) < 0) { -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The flag check inside 'qemuDomainGetSEVInfo' makes no sense because it only validates the 'VIR_TYPED_PARAM_STRING_OKAY' which is not actually used. Remove the 'flags parameter from 'qemuDomainGetSEVInfo' and validate flags at 'qemuDomainGetLaunchSecurityInfo' Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a2b5959e55..781efd612c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -19668,16 +19668,13 @@ qemuNodeGetSEVInfo(virConnectPtr conn, static int qemuDomainGetSEVInfo(virDomainObj *vm, - virTypedParamList *list, - unsigned int flags) + virTypedParamList *list) { int ret = -1; int rv; g_autofree char *tmp = NULL; qemuMonitorSEVInfo info = { }; - virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); - if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0) return -1; @@ -19737,6 +19734,8 @@ qemuDomainGetLaunchSecurityInfo(virDomainPtr domain, virDomainObj *vm; int ret = -1; + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + if (!(vm = qemuDomainObjFromDomain(domain))) goto cleanup; @@ -19751,7 +19750,7 @@ qemuDomainGetLaunchSecurityInfo(virDomainPtr domain, switch (vm->def->sec->sectype) { case VIR_DOMAIN_LAUNCH_SECURITY_SEV: case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP: - if (qemuDomainGetSEVInfo(vm, list, flags) < 0) + if (qemuDomainGetSEVInfo(vm, list) < 0) goto cleanup; break; case VIR_DOMAIN_LAUNCH_SECURITY_PV: -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 781efd612c..8e30857b34 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7742,9 +7742,6 @@ qemuDomainDetachDeviceAliasLiveAndConfig(virQEMUDriver *driver, g_autoptr(virDomainDef) vmdef = NULL; unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; - virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | - VIR_DOMAIN_AFFECT_CONFIG, -1); - cfg = virQEMUDriverGetConfig(driver); if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && @@ -7840,6 +7837,9 @@ qemuDomainDetachDeviceAlias(virDomainPtr dom, virDomainObj *vm = NULL; int ret = -1; + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + if (!(vm = qemuDomainObjFromDomain(dom))) goto cleanup; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The implementation for managed save uses 'qemuDomainSaveImageDefineXML' internally which validates the flags. To have a top level flag validation for the upcoming flag introspection export the supported flags as a macro and add a 'virCheckFlags' to 'qemuDomainManagedSaveDefineXML'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8e30857b34..34d8f0257d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6120,6 +6120,11 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path, return ret; } + +#define QEMU_SAVE_IMAGE_DEFINE_FLAGS \ + VIR_DOMAIN_SAVE_RUNNING | \ + VIR_DOMAIN_SAVE_PAUSED + static int qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path, const char *dxml, unsigned int flags) @@ -6132,8 +6137,7 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path, virQEMUSaveData *data = NULL; int state = -1; - virCheckFlags(VIR_DOMAIN_SAVE_RUNNING | - VIR_DOMAIN_SAVE_PAUSED, -1); + virCheckFlags(QEMU_SAVE_IMAGE_DEFINE_FLAGS, -1); if (flags & VIR_DOMAIN_SAVE_RUNNING) state = 1; @@ -6243,6 +6247,8 @@ qemuDomainManagedSaveDefineXML(virDomainPtr dom, const char *dxml, g_autofree char *path = NULL; int ret = -1; + virCheckFlags(QEMU_SAVE_IMAGE_DEFINE_FLAGS, -1); + if (!(vm = qemuDomainObjFromDomain(dom))) return -1; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The implementation uses 'qemuDomainQemuMonitorCommandWithFiles' internally. To have a top level flag validation for the upcoming flag introspection export the supported flags as a macro and add a 'virCheckFlags'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 34d8f0257d..1eef19d3ff 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13720,6 +13720,9 @@ qemuDomainBackupGetXMLDesc(virDomainPtr domain, } +#define QEMU_DOMAIN_MONITOR_COMMAND_FLAGS \ + VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP + static int qemuDomainQemuMonitorCommandWithFiles(virDomainPtr domain, const char *cmd, @@ -13737,7 +13740,7 @@ qemuDomainQemuMonitorCommandWithFiles(virDomainPtr domain, bool hmp; int fd = -1; - virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1); + virCheckFlags(QEMU_DOMAIN_MONITOR_COMMAND_FLAGS, -1); /* currently we don't pass back any fds */ if (outfds) @@ -13791,6 +13794,8 @@ qemuDomainQemuMonitorCommand(virDomainPtr domain, char **result, unsigned int flags) { + virCheckFlags(QEMU_DOMAIN_MONITOR_COMMAND_FLAGS, -1); + return qemuDomainQemuMonitorCommandWithFiles(domain, cmd, 0, NULL, NULL, NULL, result, flags); } -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The implementation uses 'virDomainQemuMonitorEventStateRegisterID' internally. To have a top level flag validation for the upcoming flag introspection export the supported flags as a macro and add a 'virCheckFlags'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/conf/domain_event.c | 4 +--- src/conf/domain_event.h | 5 +++++ src/qemu/qemu_driver.c | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 88087bad4f..4fb0f68ae9 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -2471,9 +2471,7 @@ virDomainQemuMonitorEventStateRegisterID(virConnectPtr conn, return -1; if (flags != -1) - virCheckFlags(VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX | - VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE, - -1); + virCheckFlags(VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_FLAGS, -1); data = g_new0(virDomainQemuMonitorEventData, 1); data->flags = flags; if (event && flags != -1) { diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index f31cfb9e42..63ecd66b21 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -334,6 +334,11 @@ virDomainEventStateDeregister(virConnectPtr conn, virConnectDomainEventCallback callback) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + +#define VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_FLAGS \ + VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX | \ + VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE + int virDomainQemuMonitorEventStateRegisterID(virConnectPtr conn, virObjectEventState *state, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1eef19d3ff..758dbbe19f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16352,6 +16352,8 @@ qemuConnectDomainQemuMonitorEventRegister(virConnectPtr conn, virQEMUDriver *driver = conn->privateData; int ret = -1; + virCheckFlags(VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_FLAGS, -1); + if (virConnectDomainQemuMonitorEventRegisterEnsureACL(conn) < 0) return -1; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The implementation uses 'virDomainObjGetMetadata' internally. To have a top level flag validation for the upcoming flag introspection export the supported flags as a macro and add a 'virCheckFlags'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/conf/domain_conf.c | 3 +-- src/conf/domain_conf.h | 4 ++++ src/qemu/qemu_driver.c | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3497e84bf5..d73bac5cc5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -31557,8 +31557,7 @@ virDomainObjGetMetadata(virDomainObj *vm, virDomainDef *def; char *ret = NULL; - virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | - VIR_DOMAIN_AFFECT_CONFIG, NULL); + virCheckFlags(VIR_DOMAIN_OBJ_GET_METADATA_FLAGS, NULL); if (type >= VIR_DOMAIN_METADATA_LAST) { virReportError(VIR_ERR_INVALID_ARG, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a8f90803da..bdfb99ed1d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -4543,6 +4543,10 @@ const char *virDomainChrSourceDefGetPath(virDomainChrSourceDef *chr); void virDomainChrSourceDefClear(virDomainChrSourceDef *def); +#define VIR_DOMAIN_OBJ_GET_METADATA_FLAGS \ + VIR_DOMAIN_AFFECT_LIVE | \ + VIR_DOMAIN_AFFECT_CONFIG + char *virDomainObjGetMetadata(virDomainObj *vm, int type, const char *uri, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 758dbbe19f..c8975fbbf6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15998,6 +15998,8 @@ qemuDomainGetMetadata(virDomainPtr dom, virDomainObj *vm; char *ret = NULL; + virCheckFlags(VIR_DOMAIN_OBJ_GET_METADATA_FLAGS, NULL); + if (!(vm = qemuDomainObjFromDomain(dom))) return NULL; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The API will provide a central point to query for runtime information about support of APIs, flags, typed parameters and in future possibly other information for current connection object. The intofmation can be used to e.g. see which flags are supported for which API. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- include/libvirt/libvirt-host.h | 3 +++ src/driver-hypervisor.h | 5 +++++ src/libvirt-host.c | 40 ++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 ++++++++++++- src/remote_protocol-structs | 7 ++++++ 7 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 5b448e7954..f9562df9e7 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -1041,5 +1041,8 @@ int virNodeAllocPages(virConnectPtr conn, unsigned int cellCount, unsigned int flags); +char *virConnectGetIntrospection(virConnectPtr conn, + unsigned int flags); + #endif /* LIBVIRT_HOST_H */ diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 6a43688b0c..79a7d819a4 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1473,6 +1473,10 @@ typedef int const char *groupname, unsigned int flags); +typedef char * +(*virDrvConnectGetIntrospection)(virConnectPtr conn, + unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; /** @@ -1750,4 +1754,5 @@ struct _virHypervisorDriver { virDrvDomainGraphicsReload domainGraphicsReload; virDrvDomainSetThrottleGroup domainSetThrottleGroup; virDrvDomainDelThrottleGroup domainDelThrottleGroup; + virDrvConnectGetIntrospection connectGetIntrospection; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 6b4345b09d..eec3d4d3cd 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -142,6 +142,46 @@ virConnectSupportsFeature(virConnectPtr conn, int feature) } +/** + * virConnectGetIntrospection: + * @conn: pointer to the hypervisor connection + * @flags: currently unused, pass 0 + * + * Request a XML containing introspection information for the current + * connection. The introspection XML contains information about supported APIs, + * flags, and other information which depends on what the current driver + * associated with the connection supports. + * + * Returns: XML string containing the introspection data. Caller is responsible + * for freeing the associated memory. On error NULL is returned. + * + * Since: 12.4.0 + */ +char * +virConnectGetIntrospection(virConnectPtr conn, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, flags=0x%x", conn, flags); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + + if (conn->driver->connectGetIntrospection) { + char *ret = conn->driver->connectGetIntrospection(conn, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + /** * virConnectGetType: * @conn: pointer to the hypervisor connection diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index c506acd2ed..3a01d21d33 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -956,4 +956,9 @@ LIBVIRT_11.2.0 { virDomainDelThrottleGroup; } LIBVIRT_10.2.0; +LIBVIRT_12.4.0 { + global: + virConnectGetIntrospection; +} LIBVIRT_11.2.0; + # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ec71eaed87..e26da6a309 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7935,6 +7935,7 @@ static virHypervisorDriver hypervisor_driver = { .domainGraphicsReload = remoteDomainGraphicsReload, /* 10.2.0 */ .domainSetThrottleGroup = remoteDomainSetThrottleGroup, /* 11.2.0 */ .domainDelThrottleGroup = remoteDomainDelThrottleGroup, /* 11.2.0 */ + .connectGetIntrospection = remoteConnectGetIntrospection, /* 12.4.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 38a83c64ea..5ba88d4582 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -4009,6 +4009,13 @@ struct remote_domain_event_nic_mac_change_msg { remote_nonnull_string newMAC; }; +struct remote_connect_get_introspection_args { + unsigned int flags; +}; + +struct remote_connect_get_introspection_ret { + remote_nonnull_string xml; +}; /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -7120,5 +7127,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453 + REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453, + + /** + * @generate: both + * @acl: connect:read + */ + REMOTE_PROC_CONNECT_GET_INTROSPECTION = 454 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index d11a8f91a9..9d02ae762e 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3337,6 +3337,12 @@ struct remote_domain_event_nic_mac_change_msg { remote_nonnull_string oldMAC; remote_nonnull_string newMAC; }; +struct remote_connect_get_introspection_args { + u_int flags; +}; +struct remote_connect_get_introspection_ret { + remote_nonnull_string xml; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3791,4 +3797,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_THROTTLE_GROUP = 451, REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP = 452, REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453, + REMOTE_PROC_CONNECT_GET_INTROSPECTION = 454, }; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- docs/manpages/virsh.rst | 19 ++++++++++++++++++ tools/virsh-host.c | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 80b0ea14a8..01e2ac9d32 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -1097,6 +1097,25 @@ on the host are reported. The option *--all* will report every CPU model known to the hypervisor, including ones that are not supported on the hypervisor (e.g. newer generation models). +introspection +------------- + +**Syntax:** + +:: + + introspection [--xpath EXPRESSION] [--wrap] + +Output the libvirt connection feature introspection XML. + +If the **--xpath** argument provides an XPath expression, it will be +evaluated against the output XML and only those matching nodes will +be printed. The default behaviour is to print each matching node as +a standalone document, however, for ease of additional processing, +the **--wrap** argument will cause the matching node to be wrapped +in a common root node. + + DOMAIN COMMANDS =============== diff --git a/tools/virsh-host.c b/tools/virsh-host.c index ef91e22fed..e1980bc276 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1864,6 +1864,43 @@ cmdHypervisorCPUModelNames(vshControl *ctl, } +static const vshCmdInfo info_introspection = { + .help = N_("get XML containing connection introspection data"), + .desc = N_("get XML containing connection introspection data"), +}; + +static const vshCmdOptDef opts_introspection[] = { + {.name = "xpath", + .type = VSH_OT_STRING, + .completer = vshCompleteEmpty, + .help = N_("xpath expression to filter the XML document") + }, + {.name = "wrap", + .type = VSH_OT_BOOL, + .help = N_("wrap xpath results in an common root element"), + }, + {.name = NULL} +}; + +static bool +cmdIntrospection(vshControl *ctl, + const vshCmd *cmd) +{ + g_autofree char *xml = NULL; + virshControl *priv = ctl->privData; + bool wrap = vshCommandOptBool(cmd, "wrap"); + const char *xpath = NULL; + + if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0) + return false; + + if (!(xml = virConnectGetIntrospection(priv->conn, 0))) + return false; + + return virshDumpXML(ctl, xml, "domain", xpath, wrap); +} + + const vshCmdDef hostAndHypervisorCmds[] = { {.name = "allocpages", .handler = cmdAllocpages, @@ -2003,5 +2040,11 @@ const vshCmdDef hostAndHypervisorCmds[] = { .info = &info_version, .flags = 0 }, + {.name = "introspection", + .handler = cmdIntrospection, + .opts = opts_introspection, + .info = &info_introspection, + .flags = 0 + }, {.name = NULL} }; -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> The script analyzes the driver implementation source file and generates an include file which describes the analyzed driver in terms of: - supported APIs - flags supported for the API (by looking at virCheckFlags) The generated structure then will be used to generate the introspection XML. The script goes through the 'virHypervisorDriver' struct, finds all callbacks corresponding to public APIs and then goes through the functions finding the 'virCheckFlags' to collect supported flags per API. Since the migration APIs are public but use internal functions which don't map directly, the script tries to find the best matching internal API and then infers the flags for the public migration APIs from the detected flags. The script works only with the contemporary coding style for functions due to regex usage so any driver impl file needs to be modernized first. As first example, introspection of qemu driver is generated. An excerpt from the generated data (which is for internal use, and will be used to generate XML): static const virIntrospectionData driver_api_introspection[] = { { .api = "virConnectBaselineCPU", .flags_arg = true, .flags = VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE, }, { .api = "virConnectBaselineHypervisorCPU", .flags_arg = true, .flags = VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE | VIR_CONNECT_BASELINE_CPU_IGNORE_HOST, }, { .api = "virConnectClose", .flags_arg = false, }, Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/genintrospection.py | 220 ++++++++++++++++++++++++++++++++++++ scripts/meson.build | 1 + src/qemu/meson.build | 18 +++ 3 files changed, 239 insertions(+) create mode 100644 scripts/genintrospection.py diff --git a/scripts/genintrospection.py b/scripts/genintrospection.py new file mode 100644 index 0000000000..25a17e2b0c --- /dev/null +++ b/scripts/genintrospection.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import argparse +import re +import sys + + +# driver callbacks needed to infer the introspection for public migration APIs +# which do not map directly to any driver API callback. We need a representative +# sample of APIs supporting typed parameters and flags +# The APIs are ordered acco +migration_driver_symbols = [ + "domainMigrateBegin3Params", + "domainMigrateBegin3", + "domainMigratePrepare2", + "domainMigratePrepare", +] + +migration_public_api = { + "virDomainMigrate": {}, + "virDomainMigrateToURI": {}, + "virDomainMigrate2": {}, + "virDomainMigrateToURI2": {}, + "virDomainMigrate3": {"params": True}, + "virDomainMigrateToURI3": {"params": True}, +} + + +def load_public_symbols(filename): + """load the public symbol file and return all APIs""" + symbols = [] + + with open(filename, "r") as symfile: + while True: + line = symfile.readline() + + if not line: + break + + m = re.match(r"\s+(?P<sym>vir\w+);", line) + + if not m: + continue + + symbols.append(m.group("sym")) + + return symbols + + +def parse_api(filename, syms): + with open(filename, "r") as f: + content = f.read() + + # parse the definition of current driver's virHypervisorDriver struct + driverdef = re.search( + r"virHypervisorDriver.*?=\s+{(?P<apis>[^}]+)", + content, + flags=re.DOTALL | re.MULTILINE, + ) + + # parse all functions + # requires that the input file is well formed: + # - types of return value are on separate line including pointer symbol + # - function name starts on separate line followed by opening parenthesis for arguments + # - opening brace for body is on start of a separate line + # - closing brace for body is on start of a separate line + funciter = re.finditer( + r"^(?P<name>\w+)\((?P<args>[^)]*)\)\n^{(?P<impl>.*?)^}", + content, + flags=re.DOTALL | re.MULTILINE, + ) + + if not driverdef: + raise Exception(f"'virHypervisorDriver' definition not found in '{filename}'") + + # create mapping from public API names to local driver's callback names + apis = {} + # .connectOpen = qemuConnectOpen -> apis['qemuConnectOpen'] = 'virConnectOpen' + for api in re.finditer( + r"\.(?P<field>\w+)\s+=\s+(?P<callback>\w+)", driverdef.group("apis") + ): + # skip hypervisor driver name definition + if api.group("field") == "name": + continue + + # skip APIs that have had their implementation removed + if api.group("callback") == "NULL": + continue + + # connectOpen -> virConnectOpen + # for migration API we use the name in virHypervisorDriver + name = api.group("field") + apiname = None + + if name in migration_driver_symbols: + apis[api.group("callback")] = name + else: + apiname = "vir" + name[0:1].upper() + name[1:] + apis[api.group("callback")] = apiname + + flagmap = {} + migr_data = {} + # parse exported functions, presence of 'flags' argument and the 'virCheckFlags' expression + for f in funciter: + apiname = apis.get(f.group("name"), None) + migrationapi = False + + # process exported public APIs or migration handlers; migration handlers + # will be at the end handled separately + if not apiname: + continue + + if apiname in migration_driver_symbols: + migrationapi = True + elif apiname not in syms: + continue + + data = { + "callback": f.group("name"), + "flags_arg": False, + "flags_supported": None, + } + + flagarg = re.search(r"\bflags\b", f.group("args")) + if flagarg: + data["flags_arg"] = True + + flagcheck = re.search( + r"virCheckFlags(?:Goto)?\((?P<flags>[^,]+),", + f.group("impl"), + flags=re.DOTALL | re.MULTILINE, + ) + + if flagcheck: + data["flags_supported"] = re.sub(r"\s+", " ", flagcheck.group("flags")) + + if migrationapi: + migr_data[apiname] = data + else: + flagmap[apiname] = data + + # populate migration API data. To do this we want to find which internal + # APIs are supported and then populate the list based on the detected + # information + for m in migration_driver_symbols: + if m in migr_data: + for apiname, pub in migration_public_api.items(): + data = migr_data[m].copy() + flagmap[apiname] = data + + break + + return flagmap + + +parser = argparse.ArgumentParser( + description="Tool to generate data for 'virConnectIntrospect'" +) +parser.add_argument( + "--symfile", action="append", required=True, help="public symbol file(s)" +) +parser.add_argument("--driverfile", required=True, help="driver implementation file") +parser.add_argument("--output", required=True, help="output file") +args = parser.parse_args() + +syms = [] +for sf in args.symfile: + syms += load_public_symbols(sf) + +introspection = parse_api(args.driverfile, syms) + +fail = False + +with open(args.output, "w") as outfile: + outfile.write( + f"""/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * Generated data for introspection of '{args.driverfile}'. + * This file is generated by '{parser.prog}' + */ +""" + ) + + outfile.write( + """ +static const virIntrospectionData driver_api_introspection[] = +{ +""" + ) + + for api in sorted(introspection.keys()): + data = introspection[api] + + outfile.write(f' {{ .api = "{api}",\n') + if data.get("flags_arg", False): + outfile.write(" .flags_arg = true,\n") + outfile.write(f" .flags = {data.get("flags_supported", 0)},\n") + else: + outfile.write(" .flags_arg = false,\n") + + outfile.write(" },\n") + + epilogue = """ { .api = NULL } +}; +""" + outfile.write(epilogue) + +for api, data in introspection.items(): + if ( + data.get("flags_arg", False) is True + and data.get("flags_supported", None) is None + ): + print(f"failed to parse flags for '{api}' in '{data.get("callback", "")}'") + fail = True + +if fail: + sys.exit(1) diff --git a/scripts/meson.build b/scripts/meson.build index 15a23e8738..bfb3eb7bf4 100644 --- a/scripts/meson.build +++ b/scripts/meson.build @@ -13,6 +13,7 @@ scripts = [ 'dtrace2systemtap.py', 'esx_vi_generator.py', 'genaclperms.py', + 'genintrospection.py', 'genpolkit.py', 'gensystemtap.py', 'group-qemu-caps.py', diff --git a/src/qemu/meson.build b/src/qemu/meson.build index b4fb62f14f..a6cc3d1a85 100644 --- a/src/qemu/meson.build +++ b/src/qemu/meson.build @@ -45,6 +45,23 @@ qemu_driver_sources = [ 'qemu_virtiofs.c', ] +introspection_files = custom_target( + 'qemu_introspection.inc.h', + output: 'qemu_introspection.inc.h', + input: [ + '../libvirt_public.syms', + '../libvirt_qemu.syms', + 'qemu_driver.c', + ], + command: [ + meson_python_prog, python3_prog, genintrospection_prog, + '--symfile', meson.project_source_root() / 'src' / 'libvirt_public.syms', + '--symfile', meson.project_source_root() / 'src' / 'libvirt_qemu.syms', + '--driverfile', meson.project_source_root() / 'src' / 'qemu' / 'qemu_driver.c', + '--output', '@OUTPUT@' + ] +) + driver_source_files += files(qemu_driver_sources) stateful_driver_source_files += files(qemu_driver_sources) @@ -95,6 +112,7 @@ if conf.has('WITH_QEMU') [ qemu_driver_sources, qemu_dtrace_gen_headers, + introspection_files, ], dependencies: [ access_dep, -- 2.54.0
On Thu, Apr 30, 2026 at 13:43:42 +0200, Peter Krempa via Devel wrote:
From: Peter Krempa <pkrempa@redhat.com>
The script analyzes the driver implementation source file and generates an include file which describes the analyzed driver in terms of:
- supported APIs - flags supported for the API (by looking at virCheckFlags)
The generated structure then will be used to generate the introspection XML.
The script goes through the 'virHypervisorDriver' struct, finds all callbacks corresponding to public APIs and then goes through the functions finding the 'virCheckFlags' to collect supported flags per API.
Since the migration APIs are public but use internal functions which don't map directly, the script tries to find the best matching internal API and then infers the flags for the public migration APIs from the detected flags.
The script works only with the contemporary coding style for functions due to regex usage so any driver impl file needs to be modernized first.
As first example, introspection of qemu driver is generated. An excerpt from the generated data (which is for internal use, and will be used to generate XML):
static const virIntrospectionData driver_api_introspection[] = { { .api = "virConnectBaselineCPU", .flags_arg = true, .flags = VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE, }, { .api = "virConnectBaselineHypervisorCPU", .flags_arg = true, .flags = VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE | VIR_CONNECT_BASELINE_CPU_IGNORE_HOST, }, { .api = "virConnectClose", .flags_arg = false, },
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/genintrospection.py | 220 ++++++++++++++++++++++++++++++++++++ scripts/meson.build | 1 + src/qemu/meson.build | 18 +++ 3 files changed, 239 insertions(+) create mode 100644 scripts/genintrospection.py
The following hunks need to be squashed in to make it work on non-fedora43 systems: diff --git a/scripts/genintrospection.py b/scripts/genintrospection.py old mode 100644 new mode 100755 diff --git a/scripts/genintrospection.py b/scripts/genintrospection.py index 25a17e2b0c..c3ac5c940a 100644 --- a/scripts/genintrospection.py +++ b/scripts/genintrospection.py @@ -197,7 +197,7 @@ static const virIntrospectionData driver_api_introspection[] = outfile.write(f' {{ .api = "{api}",\n') if data.get("flags_arg", False): outfile.write(" .flags_arg = true,\n") - outfile.write(f" .flags = {data.get("flags_supported", 0)},\n") + outfile.write(f" .flags = {data.get('flags_supported', 0)},\n") else: outfile.write(" .flags_arg = false,\n") @@ -213,7 +213,7 @@ for api, data in introspection.items(): data.get("flags_arg", False) is True and data.get("flags_supported", None) is None ): - print(f"failed to parse flags for '{api}' in '{data.get("callback", "")}'") + print(f"failed to parse flags for '{api}' in '{data.get('callback', '')}'") fail = True if fail: diff --git a/src/qemu/meson.build b/src/qemu/meson.build index a6cc3d1a85..a95ad13b6a 100644 --- a/src/qemu/meson.build +++ b/src/qemu/meson.build @@ -54,7 +54,7 @@ introspection_files = custom_target( 'qemu_driver.c', ], command: [ - meson_python_prog, python3_prog, genintrospection_prog, + meson_python_prog, genintrospection_prog, '--symfile', meson.project_source_root() / 'src' / 'libvirt_public.syms', '--symfile', meson.project_source_root() / 'src' / 'libvirt_qemu.syms', '--driverfile', meson.project_source_root() / 'src' / 'qemu' / 'qemu_driver.c',
From: Peter Krempa <pkrempa@redhat.com> Add general infrastructure for converting the generated introspection into XML which can be returned via 'virConnectGetIntrospection' and use it in the qemu driver. Example of the generated introspection XML: $ virsh introspection <libvirt-introspection> <hypervisor> <api name='virConnectBaselineCPU'> <flags dec='3' hex='0x3'/> </api> <api name='virConnectBaselineHypervisorCPU'> <flags dec='7' hex='0x7'/> </api> <api name='virConnectClose'/> [...] The XML has the provisions to add introspection for sub-drivers as well as can be extended in the future with other dynamic parameters such as the names and types of virTypedParameter input fields. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt_private.syms | 5 +++++ src/qemu/qemu_driver.c | 17 +++++++++++++++++ src/util/meson.build | 1 + src/util/virintrospection.c | 37 +++++++++++++++++++++++++++++++++++++ src/util/virintrospection.h | 17 +++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 src/util/virintrospection.c create mode 100644 src/util/virintrospection.h diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 37c9c73d92..706079b87f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2657,6 +2657,11 @@ virInhibitorRelease; virInitctlFifos; virInitctlSetRunLevel; + +# util/virintrospection.h +virIntrospectionGetXML; + + # util/viriommufd.h virIOMMUFDOpenDevice; virIOMMUFDSupported; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c8975fbbf6..38f87a4bff 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -105,6 +105,7 @@ #include "virdomaincheckpointobjlist.h" #include "virutil.h" #include "backup_conf.h" +#include "virintrospection.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -20871,6 +20872,21 @@ qemuDomainDelThrottleGroup(virDomainPtr dom, } +#include "qemu_introspection.inc.h" + +static char * +qemuConnectGetIntrospection(virConnectPtr conn G_GNUC_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + + if (virConnectGetIntrospectionEnsureACL(conn) < 0) + return NULL; + + return virIntrospectionGetXML(driver_api_introspection); +} + + static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, .connectURIProbe = qemuConnectURIProbe, @@ -21125,6 +21141,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainSetAutostartOnce = qemuDomainSetAutostartOnce, /* 11.2.0 */ .domainSetThrottleGroup = qemuDomainSetThrottleGroup, /* 11.2.0 */ .domainDelThrottleGroup = qemuDomainDelThrottleGroup, /* 11.2.0 */ + .connectGetIntrospection = qemuConnectGetIntrospection, /* 12.4.0 */ }; diff --git a/src/util/meson.build b/src/util/meson.build index 9fb0aa0fe7..542f8a1b9b 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -46,6 +46,7 @@ util_sources = [ 'viridentity.c', 'virinhibitor.c', 'virinitctl.c', + 'virintrospection.c', 'viriommufd.c', 'viriscsi.c', 'virjson.c', diff --git a/src/util/virintrospection.c b/src/util/virintrospection.c new file mode 100644 index 0000000000..b9fb5beda8 --- /dev/null +++ b/src/util/virintrospection.c @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <config.h> + +#include "virintrospection.h" +#include "virxml.h" +#include "virbuffer.h" + +char * +virIntrospectionGetXML(const virIntrospectionData *d) +{ + g_auto(virBuffer) xml = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) sections = VIR_BUFFER_INIT_CHILD(&xml); + g_auto(virBuffer) apis = VIR_BUFFER_INIT_CHILD(§ions); + size_t i; + + for (i = 0; d[i].api != NULL; i++) { + g_auto(virBuffer) api_attr = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) api_elem = VIR_BUFFER_INIT_CHILD(&apis); + + virBufferAsprintf(&api_attr, " name='%s'", d[i].api); + + if (d[i].flags_arg) { + virBufferAsprintf(&api_elem, "<flags dec='%u' hex='0x%x'/>\n", + d[i].flags, d[i].flags); + } + + virXMLFormatElement(&apis, "api", &api_attr, &api_elem); + } + + virXMLFormatElement(§ions, "hypervisor", NULL, &apis); + virXMLFormatElementEmpty(&xml, "libvirt-introspection", NULL, §ions); + + return virBufferContentAndReset(&xml); +} diff --git a/src/util/virintrospection.h b/src/util/virintrospection.h new file mode 100644 index 0000000000..f996ce0f07 --- /dev/null +++ b/src/util/virintrospection.h @@ -0,0 +1,17 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#include <stdbool.h> + +struct _virIntrospectionData { + const char *api; + bool flags_arg; + unsigned int flags; +}; +typedef struct _virIntrospectionData virIntrospectionData; + +char * +virIntrospectionGetXML(const virIntrospectionData *d); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> While 'virTypedParamsValidate', which uses varargs to pass the template to validate parameters agains, is convenient for single uses we have multiple occasions where we want to validate the same list of parameters in muliple places. We use either a macro which expands to the parameter list in place or a function which encapsulates the validation. For introspection of input typed parameters we'll need to have the list of supported typed parameters in each function which uses them as input and either of the approaches is inconvenient for generating the introspection parts. Refactor 'virTypedParamsValidate', to split the actual validation internals into ''virTypedParamsValidateInternal' and create two wrappers: - 'virTypedParamsValidate' which uses varargs - 'virTypedParamsValidateTemplate' which uses an array of structs containing the template. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virtypedparam.c | 134 +++++++++++++++++++++++++-------------- src/util/virtypedparam.h | 11 ++++ 3 files changed, 100 insertions(+), 46 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 706079b87f..20507af7f7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3684,6 +3684,7 @@ virTypedParamsRemoteFree; virTypedParamsReplaceString; virTypedParamsSerialize; virTypedParamsValidate; +virTypedParamsValidateTemplate; # util/viruri.h diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index ec8046b998..92f25cea39 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -94,75 +94,55 @@ virTypedParamsSortName(const void *left, return strcmp(param_left->field, param_right->field); } +static int +virTypedParamsSortTemplate(const void *left, + const void *right, + void *opaque G_GNUC_UNUSED) +{ + const virTypedParamValidationTemplate *param_left = left; + const virTypedParamValidationTemplate *param_right = right; + return strcmp(param_left->name, param_right->name); +} + /* Validate that PARAMS contains only recognized parameter names with * correct types, and with no duplicates except for parameters * specified with VIR_TYPED_PARAM_MULTIPLE flag in type. * Pass in as many name/type pairs as appropriate, and pass NULL to end * the list of accepted parameters. Return 0 on success, -1 on failure * with error message already issued. */ -int -virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) +static int +virTypedParamsValidateInternal(virTypedParameterPtr params, + size_t nparams, + virTypedParamValidationTemplate *templates, + size_t ntemplates) { - va_list ap; size_t i; size_t j; - const char *name; const char *last_name = NULL; - size_t nkeys = 0; - size_t nkeysalloc = 0; - g_autofree virTypedParameterPtr sorted = NULL; - g_autofree virTypedParameterPtr keys = NULL; + g_autofree virTypedParameterPtr sorted = g_new0(virTypedParameter, nparams); - if (!nparams) { - return 0; - } - - va_start(ap, nparams); - - sorted = g_new0(virTypedParameter, nparams); - - /* Here we intentionally don't copy values */ memcpy(sorted, params, sizeof(*params) * nparams); g_qsort_with_data(sorted, nparams, sizeof(*sorted), virTypedParamsSortName, NULL); - name = va_arg(ap, const char *); - while (name) { - int type = va_arg(ap, int); - VIR_RESIZE_N(keys, nkeysalloc, nkeys, 1); - - if (virStrcpyStatic(keys[nkeys].field, name) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Field name '%1$s' too long"), name); - va_end(ap); - return -1; - } - - keys[nkeys].type = type & ~VIR_TYPED_PARAM_MULTIPLE; - /* Value is not used anyway */ - keys[nkeys].value.i = type & VIR_TYPED_PARAM_MULTIPLE; - - nkeys++; - name = va_arg(ap, const char *); - } - - va_end(ap); - - g_qsort_with_data(keys, nkeys, sizeof(*keys), virTypedParamsSortName, NULL); + g_qsort_with_data(templates, ntemplates, + sizeof(*templates), virTypedParamsSortTemplate, NULL); - for (i = 0, j = 0; i < nparams && j < nkeys;) { - if (STRNEQ(sorted[i].field, keys[j].field)) { + for (i = 0, j = 0; i < nparams && j < ntemplates;) { + if (STRNEQ(sorted[i].field, templates[j].name)) { j++; } else { - if (STREQ_NULLABLE(last_name, sorted[i].field) && - !(keys[j].value.i & VIR_TYPED_PARAM_MULTIPLE)) { + unsigned int expected_type = templates[j].typeflags & ~VIR_TYPED_PARAM_MULTIPLE; + bool multiple = templates[j].typeflags & VIR_TYPED_PARAM_MULTIPLE; + + if (STREQ_NULLABLE(last_name, sorted[i].field) && !multiple) { virReportError(VIR_ERR_INVALID_ARG, _("parameter '%1$s' occurs multiple times"), sorted[i].field); return -1; } - if (virTypedParamValidateType(sorted + i, keys[j].type) < 0) + if (virTypedParamValidateType(sorted + i, expected_type) < 0) return -1; last_name = sorted[i].field; @@ -170,7 +150,7 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) } } - if (j == nkeys && i != nparams) { + if (j == ntemplates && i != nparams) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("parameter '%1$s' not supported"), sorted[i].field); @@ -181,6 +161,68 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) } +/* Validate that PARAMS contains only recognized parameter names with + * correct types, and with no duplicates except for parameters + * specified with VIR_TYPED_PARAM_MULTIPLE flag in type. + * Pass in as many name/type pairs as appropriate, and pass NULL to end + * the list of accepted parameters. Return 0 on success, -1 on failure + * with error message already issued. */ +int +virTypedParamsValidate(virTypedParameterPtr params, + int nparams, + ...) +{ + va_list ap; + const char *name; + g_autofree virTypedParamValidationTemplate *templates = NULL; + size_t ntemplates = 0; + size_t ntemplatesalloc = 0; + + if (nparams == 0) + return 0; + + va_start(ap, nparams); + + for (name = va_arg(ap, const char *); name; name = va_arg(ap, const char *)) { + VIR_RESIZE_N(templates, ntemplatesalloc, ntemplates, 1); + + if (virStrcpy((char *)templates[ntemplates].name, name, VIR_TYPED_PARAM_FIELD_LENGTH) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Field name '%1$s' too long"), name); + va_end(ap); + return -1; + } + + templates[ntemplates].typeflags = va_arg(ap, unsigned int); + ntemplates++; + } + + va_end(ap); + + return virTypedParamsValidateInternal(params, nparams, templates, ntemplates); +} + + +int +virTypedParamsValidateTemplate(virTypedParameterPtr params, + int nparams, + const virTypedParamValidationTemplate *templates) +{ + size_t ntemplates = 0; + g_autofree virTypedParamValidationTemplate *templ_copy = NULL; + + /* we need to copy the list of templates because + * 'virTypedParamsValidateInternal' will need to sort it */ + while (*templates[ntemplates++].name == '\0') + ; + + templ_copy = g_new0(virTypedParamValidationTemplate, ntemplates); + memcpy(templ_copy, templates, sizeof(*templates) * ntemplates); + + return virTypedParamsValidateInternal(params, nparams, templ_copy, ntemplates); +} + + /* Check if params contains only specified parameter names. Return true if * only specified names are present in params, false if params contains any * unspecified parameter name. */ diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index 819166ff1b..bee3ecc14d 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -68,6 +68,17 @@ virTypedParamValidateType(virTypedParameterPtr param, unsigned int expected_type) G_GNUC_WARN_UNUSED_RESULT; +struct _virTypedParamValidationTemplate { + const char name[VIR_TYPED_PARAM_FIELD_LENGTH]; /* parameter name */ + unsigned int typeflags; +}; +typedef struct _virTypedParamValidationTemplate virTypedParamValidationTemplate; + +int +virTypedParamsValidateTemplate(virTypedParameterPtr params, + int nparams, + const virTypedParamValidationTemplate *templates) + G_GNUC_WARN_UNUSED_RESULT; int virTypedParamsValidate(virTypedParameterPtr params, int nparams, -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Refactor the code to use the new helper for validating migration params and making them later available for introspection. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 12 ++++++------ src/qemu/qemu_migration.c | 29 +++++++++++++++++++++++++++++ src/qemu/qemu_migration.h | 32 +------------------------------- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 38f87a4bff..f01146655e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11143,7 +11143,7 @@ qemuDomainMigrateBegin3Params(virDomainPtr domain, virDomainObj *vm; virCheckFlags(QEMU_MIGRATION_FLAGS, NULL); - if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + if (virTypedParamsValidateTemplate(params, nparams, qemuMigrationParametersValidation) < 0) return NULL; if (virTypedParamsGetString(params, nparams, @@ -11252,7 +11252,7 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, const char *nbdURI = NULL; virCheckFlags(QEMU_MIGRATION_FLAGS, -1); - if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + if (virTypedParamsValidateTemplate(params, nparams, qemuMigrationParametersValidation) < 0) return -1; if (virTypedParamsGetString(params, nparams, @@ -11390,7 +11390,7 @@ qemuDomainMigratePrepareTunnel3Params(virConnectPtr dconn, g_autoptr(qemuMigrationParams) migParams = NULL; virCheckFlags(QEMU_MIGRATION_FLAGS, -1); - if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + if (virTypedParamsValidateTemplate(params, nparams, qemuMigrationParametersValidation) < 0) return -1; if (virTypedParamsGetString(params, nparams, @@ -11494,7 +11494,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, int ret = -1; virCheckFlags(QEMU_MIGRATION_FLAGS, -1); - if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + if (virTypedParamsValidateTemplate(params, nparams, qemuMigrationParametersValidation) < 0) return ret; if (virTypedParamsGetString(params, nparams, @@ -11640,7 +11640,7 @@ qemuDomainMigrateFinish3Params(virConnectPtr dconn, const char *dname = NULL; virCheckFlags(QEMU_MIGRATION_FLAGS, NULL); - if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + if (virTypedParamsValidateTemplate(params, nparams, qemuMigrationParametersValidation) < 0) return NULL; if (virTypedParamsGetString(params, nparams, @@ -11709,7 +11709,7 @@ qemuDomainMigrateConfirm3Params(virDomainPtr domain, virCheckFlags(QEMU_MIGRATION_FLAGS, -1); - if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + if (virTypedParamsValidateTemplate(params, nparams, qemuMigrationParametersValidation) < 0) return -1; if (!(vm = qemuDomainObjFromDomain(domain))) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index ffffeea75c..bc06a100e4 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -84,6 +84,35 @@ VIR_ENUM_IMPL(qemuMigrationJobPhase, "finish_resume", ); +const virTypedParamValidationTemplate qemuMigrationParametersValidation[] = { + { VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_BANDWIDTH, VIR_TYPED_PARAM_ULLONG }, + { VIR_MIGRATE_PARAM_GRAPHICS_URI, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_LISTEN_ADDRESS, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_MIGRATE_DISKS, VIR_TYPED_PARAM_STRING | VIR_TYPED_PARAM_MULTIPLE }, + { VIR_MIGRATE_PARAM_MIGRATE_DISKS_DETECT_ZEROES, VIR_TYPED_PARAM_STRING | VIR_TYPED_PARAM_MULTIPLE }, + { VIR_MIGRATE_PARAM_MIGRATE_DISKS_TARGET_ZERO, VIR_TYPED_PARAM_STRING | VIR_TYPED_PARAM_MULTIPLE }, + { VIR_MIGRATE_PARAM_DISKS_PORT, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_COMPRESSION, VIR_TYPED_PARAM_STRING | VIR_TYPED_PARAM_MULTIPLE }, + { VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, VIR_TYPED_PARAM_ULLONG }, + { VIR_MIGRATE_PARAM_PERSIST_XML, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY, VIR_TYPED_PARAM_ULLONG }, + { VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_COMPRESSION_ZLIB_LEVEL, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL, VIR_TYPED_PARAM_INT }, + { VIR_MIGRATE_PARAM_TLS_DESTINATION, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_DISKS_URI, VIR_TYPED_PARAM_STRING }, + { VIR_MIGRATE_PARAM_BANDWIDTH_AVAIL_SWITCHOVER, VIR_TYPED_PARAM_ULLONG }, + { "", 0 } +}; + static bool ATTRIBUTE_NONNULL(1) qemuMigrationJobIsAllowed(virDomainObj *vm) diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 59f32d2ebf..7e9410e1f7 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -65,38 +65,8 @@ 0) /* All supported migration parameters and their types. */ -#define QEMU_MIGRATION_PARAMETERS \ - VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_BANDWIDTH, VIR_TYPED_PARAM_ULLONG, \ - VIR_MIGRATE_PARAM_GRAPHICS_URI, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_LISTEN_ADDRESS, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_MIGRATE_DISKS, VIR_TYPED_PARAM_STRING | \ - VIR_TYPED_PARAM_MULTIPLE, \ - VIR_MIGRATE_PARAM_MIGRATE_DISKS_DETECT_ZEROES, VIR_TYPED_PARAM_STRING | \ - VIR_TYPED_PARAM_MULTIPLE, \ - VIR_MIGRATE_PARAM_MIGRATE_DISKS_TARGET_ZERO, VIR_TYPED_PARAM_STRING | \ - VIR_TYPED_PARAM_MULTIPLE, \ - VIR_MIGRATE_PARAM_DISKS_PORT, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_COMPRESSION, VIR_TYPED_PARAM_STRING | \ - VIR_TYPED_PARAM_MULTIPLE, \ - VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, VIR_TYPED_PARAM_ULLONG, \ - VIR_MIGRATE_PARAM_PERSIST_XML, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY, VIR_TYPED_PARAM_ULLONG, \ - VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_COMPRESSION_ZLIB_LEVEL, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL, VIR_TYPED_PARAM_INT, \ - VIR_MIGRATE_PARAM_TLS_DESTINATION, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_DISKS_URI, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_BANDWIDTH_AVAIL_SWITCHOVER, VIR_TYPED_PARAM_ULLONG, \ - NULL +extern const virTypedParamValidationTemplate qemuMigrationParametersValidation[]; typedef enum { QEMU_MIGRATION_PHASE_NONE = 0, -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Make the block io tuning params introspectable. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 81 +++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 53 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f01146655e..82f5febc6b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15345,57 +15345,29 @@ qemuDomainCheckBlockIoTuneReset(virDomainDiskDef *disk, } -static int -qemuDomainValidateBlockIoTune(virTypedParameterPtr params, - int nparams) -{ - if (virTypedParamsValidate(params, nparams, - VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME, - VIR_TYPED_PARAM_STRING, - VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX_LENGTH, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX_LENGTH, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX_LENGTH, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX_LENGTH, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX_LENGTH, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX_LENGTH, - VIR_TYPED_PARAM_ULLONG, - NULL) < 0) - return -1; - - return 0; -} - +const virTypedParamValidationTemplate qemuDomainBlockIoTuneParametersValidation[] = { + { VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME, VIR_TYPED_PARAM_STRING }, + { VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX_LENGTH, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX_LENGTH, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX_LENGTH, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX_LENGTH, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX_LENGTH, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX_LENGTH, VIR_TYPED_PARAM_ULLONG }, + { "", 0 } +}; static int qemuDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info, @@ -15597,7 +15569,9 @@ qemuDomainSetBlockIoTune(virDomainPtr dom, virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); - if (qemuDomainValidateBlockIoTune(params, nparams) < 0) + + if (virTypedParamsValidateTemplate(params, nparams, + qemuDomainBlockIoTuneParametersValidation) < 0) return -1; if (!(vm = qemuDomainObjFromDomain(dom))) @@ -20677,7 +20651,8 @@ qemuDomainSetThrottleGroup(virDomainPtr dom, return -1; } - if (qemuDomainValidateBlockIoTune(params, nparams) < 0) + if (virTypedParamsValidateTemplate(params, nparams, + qemuDomainBlockIoTuneParametersValidation) < 0) return -1; if (!(vm = qemuDomainObjFromDomain(dom))) -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Refactor the validation using 'virTypedParamsValidateTemplate' and export the template so that 'qemuNodeSetMemoryParameters' can expose them via introspection. In addition since 'virHostMemSetParameters' is conditionally compiled, platforms which don't support it will not expose given params. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 4 ++++ src/util/virhostmem.c | 24 ++++++++++++++++-------- src/util/virhostmem.h | 2 ++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 20507af7f7..94351fe153 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2605,6 +2605,7 @@ virHostMemGetParameters; virHostMemGetStats; virHostMemGetTHPSize; virHostMemSetParameters; +virHostMemSetParametersValidation; # util/virhostuptime.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 82f5febc6b..d64366924c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16502,6 +16502,10 @@ qemuNodeSetMemoryParameters(virConnectPtr conn, { virCheckFlags(0, -1); + if (virTypedParamsValidateTemplate(params, nparams, + virHostMemSetParametersValidation) < 0) + return -1; + if (virNodeSetMemoryParametersEnsureACL(conn) < 0) return -1; diff --git a/src/util/virhostmem.c b/src/util/virhostmem.c index 7d7deac34b..beff114362 100644 --- a/src/util/virhostmem.c +++ b/src/util/virhostmem.c @@ -351,21 +351,24 @@ virHostMemParametersAreAllSupported(virTypedParameterPtr params, } #endif + #ifdef __linux__ +const virTypedParamValidationTemplate virHostMemSetParametersValidation[] = +{ + { VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, VIR_TYPED_PARAM_UINT }, + { VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, VIR_TYPED_PARAM_UINT }, + { VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES, VIR_TYPED_PARAM_UINT }, + { "", 0 } +}; + int virHostMemSetParameters(virTypedParameterPtr params, int nparams) { size_t i; - if (virTypedParamsValidate(params, nparams, - VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, - VIR_TYPED_PARAM_UINT, - VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, - VIR_TYPED_PARAM_UINT, - VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES, - VIR_TYPED_PARAM_UINT, - NULL) < 0) + if (virTypedParamsValidateTemplate(params, nparams, + virHostMemSetParametersValidation) < 0) return -1; if (!virHostMemParametersAreAllSupported(params, nparams)) @@ -379,6 +382,11 @@ virHostMemSetParameters(virTypedParameterPtr params, return 0; } #else +const virTypedParamValidationTemplate virHostMemSetParametersValidation[] = +{ + { "", 0 } +}; + int virHostMemSetParameters(virTypedParameterPtr params G_GNUC_UNUSED, int nparams G_GNUC_UNUSED) diff --git a/src/util/virhostmem.h b/src/util/virhostmem.h index 4a0d692402..ebe7d26f21 100644 --- a/src/util/virhostmem.h +++ b/src/util/virhostmem.h @@ -22,6 +22,7 @@ #pragma once #include "internal.h" +#include "virtypedparam.h" int virHostMemGetStats(int cellNum, virNodeMemoryStatsPtr params, @@ -35,6 +36,7 @@ int virHostMemGetInfo(unsigned long long *mem, int virHostMemGetParameters(virTypedParameterPtr params, int *nparams); +extern const virTypedParamValidationTemplate virHostMemSetParametersValidation[]; int virHostMemSetParameters(virTypedParameterPtr params, int nparams); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> For making introspection possible both qemuDomainSetSchedulerParameters and qemuDomainSetSchedulerParametersFlags need to have the check present. Refactor the flag validation to make it present in both APIs. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d64366924c..f0ef6796d3 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8991,6 +8991,20 @@ qemuSetIOThreadsBWLive(virDomainObj *vm, virCgroup *cgroup, goto endjob; \ } + +const virTypedParamValidationTemplate qemuDomainSetSchedulerParametersValidation[] = { + { VIR_DOMAIN_SCHEDULER_CPU_SHARES, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_SCHEDULER_VCPU_PERIOD, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, VIR_TYPED_PARAM_LLONG }, + { VIR_DOMAIN_SCHEDULER_GLOBAL_PERIOD, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_SCHEDULER_GLOBAL_QUOTA, VIR_TYPED_PARAM_LLONG }, + { VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA, VIR_TYPED_PARAM_LLONG }, + { VIR_DOMAIN_SCHEDULER_IOTHREAD_PERIOD, VIR_TYPED_PARAM_ULLONG }, + { VIR_DOMAIN_SCHEDULER_IOTHREAD_QUOTA, VIR_TYPED_PARAM_LLONG }, + { "", 0 } +}; + static int qemuDomainSetSchedulerParametersFlags(virDomainPtr dom, virTypedParameterPtr params, @@ -9016,26 +9030,9 @@ qemuDomainSetSchedulerParametersFlags(virDomainPtr dom, virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); - if (virTypedParamsValidate(params, nparams, - VIR_DOMAIN_SCHEDULER_CPU_SHARES, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_SCHEDULER_VCPU_PERIOD, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, - VIR_TYPED_PARAM_LLONG, - VIR_DOMAIN_SCHEDULER_GLOBAL_PERIOD, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_SCHEDULER_GLOBAL_QUOTA, - VIR_TYPED_PARAM_LLONG, - VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA, - VIR_TYPED_PARAM_LLONG, - VIR_DOMAIN_SCHEDULER_IOTHREAD_PERIOD, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_SCHEDULER_IOTHREAD_QUOTA, - VIR_TYPED_PARAM_LLONG, - NULL) < 0) + + if (virTypedParamsValidateTemplate(params, nparams, + qemuDomainSetSchedulerParametersValidation) < 0) return -1; if (!(vm = qemuDomainObjFromDomain(dom))) @@ -9297,6 +9294,10 @@ qemuDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params, int nparams) { + if (virTypedParamsValidateTemplate(params, nparams, + qemuDomainSetSchedulerParametersValidation) < 0) + return -1; + return qemuDomainSetSchedulerParametersFlags(dom, params, nparams, -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> This will allow introspecting them. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_driver.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f0ef6796d3..718994f5b5 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5318,20 +5318,6 @@ qemuDomainIOThreadParseParams(virTypedParameterPtr params, { int rc; - if (virTypedParamsValidate(params, nparams, - VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, - VIR_TYPED_PARAM_ULLONG, - VIR_DOMAIN_IOTHREAD_POLL_GROW, - VIR_TYPED_PARAM_UNSIGNED, - VIR_DOMAIN_IOTHREAD_POLL_SHRINK, - VIR_TYPED_PARAM_UNSIGNED, - VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, - VIR_TYPED_PARAM_INT, - VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX, - VIR_TYPED_PARAM_INT, - NULL) < 0) - return -1; - if ((rc = virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, &iothread->poll_max_ns)) < 0) @@ -5674,6 +5660,20 @@ qemuDomainSetIOThreadParams(virDomainPtr dom, virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); + if (virTypedParamsValidate(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, + VIR_TYPED_PARAM_ULLONG, + VIR_DOMAIN_IOTHREAD_POLL_GROW, + VIR_TYPED_PARAM_UNSIGNED, + VIR_DOMAIN_IOTHREAD_POLL_SHRINK, + VIR_TYPED_PARAM_UNSIGNED, + VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, + VIR_TYPED_PARAM_INT, + VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX, + VIR_TYPED_PARAM_INT, + NULL) < 0) + return -1; + if (iothread_id == 0) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("invalid value of 0 for iothread_id")); -- 2.54.0
From: Peter Krempa <pkrempa@redhat.com> Extract information about typed parameters from calls to 'virTypedParamsValidate'/'virTypedParamsValidateTemplate' and expose them in the introspection XML: <api name='virDomainMigrate3'> <flags dec='2097151' hex='0x1fffff'/> <typed-parameters type='input' name='params'> <param name='migrate_uri' type='string'/> <param name='destination_name' type='string'/> <param name='destination_xml' type='string'/> <param name='bandwidth' type='ullong'/> <param name='graphics_uri' type='string'/> <param name='listen_address' type='string'/> <param name='migrate_disks' type='string' multiple='yes'/> <param name='migrate_disks_detect_zeroes' type='string' multiple='yes'/> <param name='migrate_disks_target_zero' type='string' multiple='yes'/> <param name='disks_port' type='int'/> <param name='compression' type='string' multiple='yes'/> <param name='compression.mt.level' type='int'/> <param name='compression.mt.threads' type='int'/> <param name='compression.mt.dthreads' type='int'/> <param name='compression.xbzrle.cache' type='ullong'/> <param name='persistent_xml' type='string'/> <param name='auto_converge.initial' type='int'/> <param name='auto_converge.increment' type='int'/> <param name='bandwidth.postcopy' type='ullong'/> <param name='parallel.connections' type='int'/> <param name='compression.zlib.level' type='int'/> <param name='compression.zstd.level' type='int'/> <param name='tls.destination' type='string'/> <param name='disks_uri' type='string'/> <param name='bandwidth.avail.switchover' type='ullong'/> </typed-parameters> </api> Migration APIs once again required special handling as some typed params are supported even if the backing APIs using typed parameters arend supported because they can be converted to legacy parameters for the lesser APIs. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/genintrospection.py | 127 ++++++++++++++++++++++++++++++++++++ src/util/virintrospection.c | 45 +++++++++++++ src/util/virintrospection.h | 3 + 3 files changed, 175 insertions(+) diff --git a/scripts/genintrospection.py b/scripts/genintrospection.py index 25a17e2b0c..ac51634d10 100644 --- a/scripts/genintrospection.py +++ b/scripts/genintrospection.py @@ -7,6 +7,21 @@ import re import sys +# APIs which fill a user-supplied virTypedParameter pointer -- use it as output +input_params_exceptions = [ + "virDomainGetBlkioParameters", + "virDomainGetMemoryParameters", + "virDomainGetNumaParameters", + "virDomainGetSchedulerParametersFlags", + "virDomainGetSchedulerParameters", + "virDomainBlockStatsFlags", + "virDomainGetInterfaceParameters", + "virDomainGetBlockIoTune", + "virDomainGetCPUStats", + "virNodeGetMemoryParameters", +] + + # driver callbacks needed to infer the introspection for public migration APIs # which do not map directly to any driver API callback. We need a representative # sample of APIs supporting typed parameters and flags @@ -27,6 +42,15 @@ migration_public_api = { "virDomainMigrateToURI3": {"params": True}, } +# list of parameters supported by 'virDomainMigrate3'/'virDomainMigrateToURI3' +# if any migration protocol version is supported by extracting the parameters +migration_public_api_fallback_params = [ + ("VIR_MIGRATE_PARAM_URI", "VIR_TYPED_PARAM_STRING"), + ("VIR_MIGRATE_PARAM_DEST_NAME", "VIR_TYPED_PARAM_STRING"), + ("VIR_MIGRATE_PARAM_DEST_XML", "VIR_TYPED_PARAM_STRING"), + ("VIR_MIGRATE_PARAM_BANDWIDTH", "VIR_TYPED_PARAM_ULLONG"), +] + def load_public_symbols(filename): """load the public symbol file and return all APIs""" @@ -121,8 +145,13 @@ def parse_api(filename, syms): "callback": f.group("name"), "flags_arg": False, "flags_supported": None, + "input_params": False, + "input_params_supported": None, + "input_params_template": None, } + # find APIs having 'flags' argument and find the corresponding + # virCheckFlags flagarg = re.search(r"\bflags\b", f.group("args")) if flagarg: data["flags_arg"] = True @@ -136,6 +165,54 @@ def parse_api(filename, syms): if flagcheck: data["flags_supported"] = re.sub(r"\s+", " ", flagcheck.group("flags")) + # find APIs supporting typed parameters as input and find the + # corresponding supported flags by matching 'virTypedParamsValidate' + # We're looking for APIs which take typed parameters as input, which + # excludes any API taking a double-pointer. From the rest + # the 'input_params_exceptions' array has APIs which output typed + # parameters into a pre-allocated array and thus are excluded + paramarg = re.search( + r"virTypedParameter(?P<ptrtype>Ptr)?(?P<ptrstar>[ *]+)", f.group("args") + ) + param_nptrs = 0 + + if paramarg: + if paramarg.group("ptrtype"): + param_nptrs += 1 + + for c in paramarg.group("ptrstar"): + if c == "*": + param_nptrs += 1 + + if param_nptrs == 1 and apiname not in input_params_exceptions: + data["input_params"] = True + + paramscheck = re.search( + r"virTypedParamsValidate(?P<template>Template)?(?:Deferred)?\([^,]+,\s*[^,]+,\s*(?P<params>[^)]+)\)", + f.group("impl"), + flags=re.DOTALL | re.MULTILINE, + ) + + if paramscheck: + if paramscheck.group("template"): + data["input_params_template"] = paramscheck.group("params") + + else: + data["input_params_supported"] = [] + + idx = 0 + params = re.sub(r"\s+", "", paramscheck.group("params")).split(",") + + while idx < len(params): + if params[idx] == "NULL": + break + + data["input_params_supported"].append( + (params[idx], params[idx + 1]) + ) + + idx += 2 + if migrationapi: migr_data[apiname] = data else: @@ -148,6 +225,18 @@ def parse_api(filename, syms): if m in migr_data: for apiname, pub in migration_public_api.items(): data = migr_data[m].copy() + + if pub.get("params", False): + if not data["input_params"]: + data["input_params"] = True + data["input_params_supported"] = ( + migration_public_api_fallback_params + ) + else: + data["input_params"] = False + data["input_params_supported"] = None + data["input_params_template"] = None + flagmap[apiname] = data break @@ -184,6 +273,27 @@ with open(args.output, "w") as outfile: """ ) + for api in sorted(introspection.keys()): + data = introspection[api] + + if data.get("input_params_supported", None) is None: + continue + + outfile.write( + f""" +const virTypedParamValidationTemplate {data["callback"]}InputParamValidation[] = {{ +""" + ) + + for param, flag in data["input_params_supported"]: + outfile.write(f" {{ {param}, {flag} }},\n") + + outfile.write( + """ { "", 0 } +}; +""" + ) + outfile.write( """ static const virIntrospectionData driver_api_introspection[] = @@ -201,6 +311,15 @@ static const virIntrospectionData driver_api_introspection[] = else: outfile.write(" .flags_arg = false,\n") + if data.get("input_params_supported", None) is not None: + outfile.write( + f" .input_params = {data["callback"]}InputParamValidation,\n" + ) + elif data.get("input_params_template", None) is not None: + outfile.write(f" .input_params = {data["input_params_template"]},\n") + else: + outfile.write(" .input_params = NULL,\n") + outfile.write(" },\n") epilogue = """ { .api = NULL } @@ -216,5 +335,13 @@ for api, data in introspection.items(): print(f"failed to parse flags for '{api}' in '{data.get("callback", "")}'") fail = True + if data.get("input_params", False) is True and ( + data.get("input_params_supported", None) is None + and data.get("input_params_template", None) is None + ): + print( + f"failed to parse typed params for '{api}' in '{data.get("callback", "")}'" + ) + fail = True if fail: sys.exit(1) diff --git a/src/util/virintrospection.c b/src/util/virintrospection.c index b9fb5beda8..2862e60924 100644 --- a/src/util/virintrospection.c +++ b/src/util/virintrospection.c @@ -8,6 +8,24 @@ #include "virxml.h" #include "virbuffer.h" +/* These strings are exported int he XML */ +VIR_ENUM_DECL(virIntrospectionTypedParam); + +VIR_ENUM_IMPL(virIntrospectionTypedParam, + VIR_TYPED_PARAM_UNSIGNED + 1, + "", + "int", + "uint", + "llong", + "ullong", + "double", + "boolean", + "string", + "", /* VIR_TYPED_PARAM_LAST */ + "ullong", /* VIR_TYPED_PARAM_UNSIGNED */ +); + + char * virIntrospectionGetXML(const virIntrospectionData *d) { @@ -27,6 +45,33 @@ virIntrospectionGetXML(const virIntrospectionData *d) d[i].flags, d[i].flags); } + if (d[i].input_params) { + g_auto(virBuffer) typedparam_attr = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) typedparam_elem = VIR_BUFFER_INIT_CHILD(&api_elem); + size_t j; + + virBufferAddLit(&typedparam_attr, " type='input' name='params'"); + + for (j = 0; d[i].input_params[j].name[0] != '\0'; j++) { + unsigned int typeval = d[i].input_params[j].typeflags & ~VIR_TYPED_PARAM_MULTIPLE; + const char *type = virIntrospectionTypedParamTypeToString(typeval); + + virBufferAsprintf(&typedparam_elem, "<param name='%s'", + d[i].input_params[j].name); + + if (type && type[0] != '\0') + virBufferAsprintf(&typedparam_elem, " type='%s'", type); + + if (d[i].input_params[j].typeflags & VIR_TYPED_PARAM_MULTIPLE) + virBufferAddLit(&typedparam_elem, " multiple='yes'"); + + virBufferAddLit(&typedparam_elem, "/>\n"); + } + + virXMLFormatElement(&api_elem, "typed-parameters", + &typedparam_attr, &typedparam_elem); + } + virXMLFormatElement(&apis, "api", &api_attr, &api_elem); } diff --git a/src/util/virintrospection.h b/src/util/virintrospection.h index f996ce0f07..8d259e36ce 100644 --- a/src/util/virintrospection.h +++ b/src/util/virintrospection.h @@ -6,10 +6,13 @@ #include <stdbool.h> +#include "virtypedparam.h" + struct _virIntrospectionData { const char *api; bool flags_arg; unsigned int flags; + const virTypedParamValidationTemplate *input_params; }; typedef struct _virIntrospectionData virIntrospectionData; -- 2.54.0
On Thu, Apr 30, 2026 at 13:43:50 +0200, Peter Krempa via Devel wrote:
From: Peter Krempa <pkrempa@redhat.com>
Extract information about typed parameters from calls to 'virTypedParamsValidate'/'virTypedParamsValidateTemplate' and expose them in the introspection XML:
<api name='virDomainMigrate3'> <flags dec='2097151' hex='0x1fffff'/> <typed-parameters type='input' name='params'> <param name='migrate_uri' type='string'/> <param name='destination_name' type='string'/> <param name='destination_xml' type='string'/> <param name='bandwidth' type='ullong'/> <param name='graphics_uri' type='string'/> <param name='listen_address' type='string'/> <param name='migrate_disks' type='string' multiple='yes'/> <param name='migrate_disks_detect_zeroes' type='string' multiple='yes'/> <param name='migrate_disks_target_zero' type='string' multiple='yes'/> <param name='disks_port' type='int'/> <param name='compression' type='string' multiple='yes'/> <param name='compression.mt.level' type='int'/> <param name='compression.mt.threads' type='int'/> <param name='compression.mt.dthreads' type='int'/> <param name='compression.xbzrle.cache' type='ullong'/> <param name='persistent_xml' type='string'/> <param name='auto_converge.initial' type='int'/> <param name='auto_converge.increment' type='int'/> <param name='bandwidth.postcopy' type='ullong'/> <param name='parallel.connections' type='int'/> <param name='compression.zlib.level' type='int'/> <param name='compression.zstd.level' type='int'/> <param name='tls.destination' type='string'/> <param name='disks_uri' type='string'/> <param name='bandwidth.avail.switchover' type='ullong'/> </typed-parameters> </api>
Migration APIs once again required special handling as some typed params are supported even if the backing APIs using typed parameters arend supported because they can be converted to legacy parameters for the lesser APIs.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/genintrospection.py | 127 ++++++++++++++++++++++++++++++++++++ src/util/virintrospection.c | 45 +++++++++++++ src/util/virintrospection.h | 3 + 3 files changed, 175 insertions(+)
Consider this squashed in to fix the script with older python versions: diff --git a/scripts/genintrospection.py b/scripts/genintrospection.py index 13b1322746..95469fc15a 100755 --- a/scripts/genintrospection.py +++ b/scripts/genintrospection.py @@ -313,12 +313,10 @@ static const virIntrospectionData driver_api_introspection[] = if data.get("input_params_supported", None) is not None: outfile.write( - f" .input_params = {data["callback"]}InputParamValidation,\n" + f" .input_params = {data['callback']}InputParamValidation,\n" ) elif data.get("input_params_template", None) is not None: - outfile.write(f" .input_params = {data["input_params_template"]},\n") - else: - outfile.write(" .input_params = NULL,\n") + outfile.write(f" .input_params = {data['input_params_template']},\n") outfile.write(" },\n") @@ -340,7 +338,7 @@ for api, data in introspection.items(): and data.get("input_params_template", None) is None ): print( - f"failed to parse typed params for '{api}' in '{data.get("callback", "")}'" + f"failed to parse typed params for '{api}' in '{data.get('callback', '')}'" ) fail = True if fail:
From: Peter Krempa <pkrempa@redhat.com> Use the new VIR_DOMAIN_BLOCK_RESIZE_PROBE_FLAGS flag to probe for VIR_DOMAIN_BLOCK_RESIZE_EXTEND and use it if available. This will give users the same protection as with --extend in the default case. IMPORTANT: This patch changes behaviour for users who want to shrink their VM's block device knowingly. Such users, when using a newer daemon will be required to pass --allow-shrink now. I've contemplated either renaming the whole command to preserve functionality for the existing one and deprecating 'virsh blockresize' or adding just the '--extend', but unfortunately neither of those in the end looked appealing to me. As shrinking filesystems is much more invloved and much less common the benefit of preventing accidental data loss should outweigh the breakage from the change. To aleviate issues with scripts virsh now also provides the '--probe-arguments' option to allow safe probe if virsh supports this new argument. Closes: https://gitlab.com/libvirt/libvirt/-/work_items/789 Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- docs/manpages/virsh.rst | 11 +++++++- tools/virsh-domain.c | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 01e2ac9d32..e3cf647b51 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -1661,7 +1661,7 @@ blockresize :: - blockresize domain path ([size] | [--capacity]) [--extend] + blockresize domain path ([size] | [--capacity]) [--extend] [--allow-shrink] Resize a block device of domain while the domain is running, *path* specifies the absolute path of the block device; it corresponds @@ -1674,6 +1674,15 @@ smaller than the old size, thus prevents (accidental) shrinking of the block device which may lead to data loss. Users are encouraged to always use this flag unless communicating with an older hypervisor. +As of libvirt 12.4.0 the 'virsh blockresize' command now probes whether the +hypervisor supports enforcing that the device is not shrunk accidentally and +if it is supported this feature will be used as a precaution from accidental +data loss even at the cost of change of behaviour. With older hypervisors +which do not support the feature the protection will not be avaliable. +Users wanting to shrink the block device must use the *--allow-shrink* +flag. In scripts it's possible to look for presence of *--allow-shrink* in +output of ``virsh help blockresize`` to determine if the flag is supported. + For image formats without metadata (raw) stored inside fixed-size storage (e.g. block devices) the --capacity flag can be used to resize the device to the full size of the backing device. diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 08a1ce3953..71bf5f39b0 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -3313,6 +3313,51 @@ cmdBlockpull(vshControl *ctl, const vshCmd *cmd) return ret; } + +/** + * virshIntrospectFlags: + * @ctl: virsh control data + * @api: name of API to introspect flags + * @flags: filled with flags supported by @api on success + * + * Uses the 'virConnectIntrospection' to introspect @api and return supported + * flags. + * + * Returns 0 on success (@flags are populated), -1 on error. No errors are + * reported by this function. + */ +static int +virshIntrospectFlags(vshControl *ctl, + const char *api, + unsigned int *flags) +{ + virshControl *priv = ctl->privData; + g_autofree char *introspectionxml = NULL; + g_autoptr(xmlDoc) xmldoc = NULL; + g_autoptr(xmlXPathContext) ctxt = NULL; + g_autofree char *xpath = g_strdup_printf("string(//api[@name='%s']/flags/@dec)", + api); + + *flags = 0; + + if (!(introspectionxml = virConnectGetIntrospection(priv->conn, 0))) { + vshResetLibvirtError(); + return -1; + } + + if (!(xmldoc = virXMLParseStringCtxt(introspectionxml, "(introspection xml)", + &ctxt))) + return -1; + + if (virXPathUInt(xpath, ctxt, flags) < 0) + return -1; + + vshDebug(ctl, VSH_ERR_DEBUG, "api:'%s' flags='0x%x'", api, *flags); + + return 0; +} + + /* * "blockresize" command */ @@ -3343,6 +3388,10 @@ static const vshCmdOptDef opts_blockresize[] = { .type = VSH_OT_BOOL, .help = N_("ensure that the new size is larger than actual capacity (prevent shrink)") }, + {.name = "allow-shrink", + .type = VSH_OT_BOOL, + .help = N_("disable size checks so that device can be shrunk") + }, {.name = NULL} }; @@ -3378,6 +3427,16 @@ cmdBlockresize(vshControl *ctl, const vshCmd *cmd) if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; + /* probe for support of VIR_DOMAIN_BLOCK_RESIZE_EXTEND and use it if it's + * supported to prevent mishaps even at the cost of usability change */ + if (!vshCommandOptBool(cmd, "allow-shrink")) { + unsigned int supportedflags = 0; + + if (virshIntrospectFlags(ctl, "virDomainBlockResize", &supportedflags) == 0 && + supportedflags & VIR_DOMAIN_BLOCK_RESIZE_EXTEND) + flags |= VIR_DOMAIN_BLOCK_RESIZE_EXTEND; + } + if (virDomainBlockResize(dom, path, size, flags) < 0) { vshError(ctl, _("Failed to resize block device '%1$s'"), path); return false; -- 2.54.0
participants (1)
-
Peter Krempa