:p
atchew
Login
The series adds a dual state to the mdev node devices as these objects can be active and defined at the same time. These two states can become different. To be able to also introspect the persistent and transient nodedevs filtering is added. To be able to also dump the XML of an inactive state while the node device is active a new option is added. The last four patches add the capability to update a mdev node device. This can be done on the persistent configuration, on the active configuration or on both. To support this v1.3.0 of mdevctl is required. nodeDeviceDefineXML() does now support modifying a persistent configuration. Changes since v2: * made error messages in virNodeDeviceObjUpdateModificationImpact() device type agnostic * renamed virNodeDeviceUpdateXML* into virNodeDeviceUpdate* * renamed nodeDeviceDefCompareMdevs() into nodeDeviceDefValidateUpdate() * renamed multiple local variable names * removed method for config cloning by commenting cross config compare in nodeDeviceDefValidateUpdate() * changed nodeDeviceDefineXML() to modify an existing persistent configuration Changes since v1: * replaced spec file requirement for v1.3.0 of mdevctl by a dynamic support check and an unsupported message if not available * removed persisted precheck in virsh * renamed persisted and persist into persistent * addressed all other review comments made on v1 * added NEWS Boris Fiuczynski (12): virmdev: prepare type and attributes for dual state node_device: refactor mdev attributes handling node_device: remove unnecessary checks in virNodeDeviceDefFormat nodedev: add an active config to mdev tools: add option inactive to nodedev-dumpxml nodedev: add persisted and transient filter on list tools: add switches persisted and transient to nodedev-list virsh: doc fix on nodedev-list api: add virNodeDeviceUpdate() nodedev: Implement virNodeDeviceUpdate virsh: add nodedev-update nodedev: allow modify on define of a persistent node device NEWS.rst | 12 + docs/drvnodedev.rst | 4 +- docs/manpages/virsh.rst | 36 +- include/libvirt/libvirt-nodedev.h | 31 ++ libvirt.spec.in | 1 + src/access/viraccessperm.c | 1 + src/access/viraccessperm.h | 6 + src/conf/node_device_conf.c | 76 +-- src/conf/node_device_conf.h | 14 +- src/conf/virnodedeviceobj.c | 50 ++ src/conf/virnodedeviceobj.h | 3 + src/driver-nodedev.h | 6 + src/libvirt-nodedev.c | 51 +- src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 + src/node_device/node_device_driver.c | 489 ++++++++++++++---- src/node_device/node_device_driver.h | 17 +- src/node_device/node_device_udev.c | 5 +- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 17 +- src/remote_protocol-structs | 6 + src/test/test_driver.c | 6 +- src/util/virmdev.h | 6 + ...60c_c60c_c60c_c60c_c60cc60cc60c_update.xml | 16 + tests/nodedevmdevctldata/mdevctl-modify.argv | 25 + tests/nodedevmdevctldata/mdevctl-modify.json | 4 + tests/nodedevmdevctltest.c | 94 +++- ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 14 + ...d_b7f0_4fea_b468_f1da537d301b_inactive.xml | 1 + ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 10 + ...c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml | 9 + ...9_36ea_4111_8f0a_8c9a70e21366_inactive.xml | 1 + ...9_495e_4243_ad9f_beb3f14c23d9_inactive.xml | 1 + ...4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml | 8 + ...6_1ca8_49ac_b176_871d16c13076_inactive.xml | 1 + tests/nodedevxml2xmltest.c | 59 ++- tools/virsh-nodedev.c | 140 ++++- 37 files changed, 1067 insertions(+), 160 deletions(-) create mode 100644 tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.argv create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.json create mode 100644 tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 120000 tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Create a new structure holding type and attributes as these are modifable in a persisted mdev configuration and run out of sync with the active mdev configuration. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- src/conf/node_device_conf.c | 18 +++---- src/conf/node_device_conf.h | 4 +- src/node_device/node_device_driver.c | 70 ++++++++++++++-------------- src/node_device/node_device_udev.c | 2 +- src/util/virmdev.h | 6 +++ 5 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapMdevDefFormat(virBuffer *buf, { size_t i; - virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.type); + virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.dev_config.type); virBufferEscapeString(buf, "<uuid>%s</uuid>\n", data->mdev.uuid); virBufferEscapeString(buf, "<parent_addr>%s</parent_addr>\n", data->mdev.parent_addr); virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n", data->mdev.iommuGroupNumber); - for (i = 0; i < data->mdev.nattributes; i++) { - virMediatedDeviceAttr *attr = data->mdev.attributes[i]; + for (i = 0; i < data->mdev.dev_config.nattributes; i++) { + virMediatedDeviceAttr *attr = data->mdev.dev_config.attributes[i]; virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n", attr->name, attr->value); } @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt, return -1; } - VIR_APPEND_ELEMENT(mdev->attributes, mdev->nattributes, attr); + VIR_APPEND_ELEMENT(mdev->dev_config.attributes, mdev->dev_config.nattributes, attr); return 0; } @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, ctxt->node = node; - if (!(mdev->type = virXPathString("string(./type[1]/@id)", ctxt))) { + if (!(mdev->dev_config.type = virXPathString("string(./type[1]/@id)", ctxt))) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("missing type id attribute for '%1$s'"), def->name); return -1; @@ -XXX,XX +XXX,XX @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps) g_free(data->sg.path); break; case VIR_NODE_DEV_CAP_MDEV: - g_free(data->mdev.type); + g_free(data->mdev.dev_config.type); g_free(data->mdev.uuid); - for (i = 0; i < data->mdev.nattributes; i++) - virMediatedDeviceAttrFree(data->mdev.attributes[i]); - g_free(data->mdev.attributes); + for (i = 0; i < data->mdev.dev_config.nattributes; i++) + virMediatedDeviceAttrFree(data->mdev.dev_config.attributes[i]); + g_free(data->mdev.dev_config.attributes); g_free(data->mdev.parent_addr); break; case VIR_NODE_DEV_CAP_CSS_DEV: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -XXX,XX +XXX,XX @@ struct _virNodeDevCapSystem { typedef struct _virNodeDevCapMdev virNodeDevCapMdev; struct _virNodeDevCapMdev { - char *type; unsigned int iommuGroupNumber; char *uuid; - virMediatedDeviceAttr **attributes; - size_t nattributes; + virMediatedDeviceConfig dev_config; char *parent_addr; bool autostart; }; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) g_autoptr(virJSONValue) json = virJSONValueNewObject(); const char *startval = mdev->autostart ? "auto" : "manual"; - if (virJSONValueObjectAppendString(json, "mdev_type", mdev->type) < 0) + if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) return -1; if (virJSONValueObjectAppendString(json, "start", startval) < 0) return -1; - if (mdev->attributes) { + if (mdev->dev_config.attributes) { g_autoptr(virJSONValue) attributes = virJSONValueNewArray(); - for (i = 0; i < mdev->nattributes; i++) { - virMediatedDeviceAttr *attr = mdev->attributes[i]; + for (i = 0; i < mdev->dev_config.nattributes; i++) { + virMediatedDeviceAttr *attr = mdev->dev_config.attributes[i]; g_autoptr(virJSONValue) jsonattr = virJSONValueNewObject(); if (virJSONValueObjectAppendString(jsonattr, attr->name, attr->value) < 0) @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, mdev = &child->caps->data.mdev; mdev->uuid = g_strdup(uuid); mdev->parent_addr = g_strdup(parent); - mdev->type = + mdev->dev_config.type = g_strdup(virJSONValueObjectGetString(props, "mdev_type")); start = virJSONValueObjectGetString(props, "start"); mdev->autostart = STREQ_NULLABLE(start, "auto"); @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, size_t i; int nattrs = virJSONValueArraySize(attrs); - mdev->attributes = g_new0(virMediatedDeviceAttr*, nattrs); - mdev->nattributes = nattrs; + mdev->dev_config.attributes = g_new0(virMediatedDeviceAttr*, nattrs); + mdev->dev_config.nattributes = nattrs; for (i = 0; i < nattrs; i++) { virJSONValue *attr = virJSONValueArrayGet(attrs, i); @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0)); value = virJSONValueObjectGetValue(attr, 0); attribute->value = g_strdup(virJSONValueGetString(value)); - mdev->attributes[i] = attribute; + mdev->dev_config.attributes[i] = attribute; } } mdevGenerateDeviceName(child); @@ -XXX,XX +XXX,XX @@ nodeDeviceUpdateMediatedDevices(void) /* returns true if any attributes were copied, else returns false */ static bool -virMediatedDeviceAttrsCopy(virNodeDevCapMdev *dst, - virNodeDevCapMdev *src) +virMediatedDeviceAttrsCopy(virMediatedDeviceConfig *dst_config, + virMediatedDeviceConfig *src_config) { bool ret = false; size_t i; - if (src->nattributes != dst->nattributes) { + if (src_config->nattributes != dst_config->nattributes) { ret = true; - for (i = 0; i < dst->nattributes; i++) - virMediatedDeviceAttrFree(dst->attributes[i]); - g_free(dst->attributes); - - dst->nattributes = src->nattributes; - dst->attributes = g_new0(virMediatedDeviceAttr*, - src->nattributes); - for (i = 0; i < dst->nattributes; i++) - dst->attributes[i] = virMediatedDeviceAttrNew(); + for (i = 0; i < dst_config->nattributes; i++) + virMediatedDeviceAttrFree(dst_config->attributes[i]); + g_free(dst_config->attributes); + + dst_config->nattributes = src_config->nattributes; + dst_config->attributes = g_new0(virMediatedDeviceAttr*, + src_config->nattributes); + for (i = 0; i < dst_config->nattributes; i++) + dst_config->attributes[i] = virMediatedDeviceAttrNew(); } - for (i = 0; i < src->nattributes; i++) { - if (STRNEQ_NULLABLE(src->attributes[i]->name, - dst->attributes[i]->name)) { + for (i = 0; i < src_config->nattributes; i++) { + if (STRNEQ_NULLABLE(src_config->attributes[i]->name, + dst_config->attributes[i]->name)) { ret = true; - g_free(dst->attributes[i]->name); - dst->attributes[i]->name = - g_strdup(src->attributes[i]->name); + g_free(dst_config->attributes[i]->name); + dst_config->attributes[i]->name = + g_strdup(src_config->attributes[i]->name); } - if (STRNEQ_NULLABLE(src->attributes[i]->value, - dst->attributes[i]->value)) { + if (STRNEQ_NULLABLE(src_config->attributes[i]->value, + dst_config->attributes[i]->value)) { ret = true; - g_free(dst->attributes[i]->value); - dst->attributes[i]->value = - g_strdup(src->attributes[i]->value); + g_free(dst_config->attributes[i]->value); + dst_config->attributes[i]->value = + g_strdup(src_config->attributes[i]->value); } } @@ -XXX,XX +XXX,XX @@ nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, virNodeDevCapMdev *srcmdev = &src->caps->data.mdev; virNodeDevCapMdev *dstmdev = &dst->caps->data.mdev; - if (STRNEQ_NULLABLE(dstmdev->type, srcmdev->type)) { + if (STRNEQ_NULLABLE(dstmdev->dev_config.type, srcmdev->dev_config.type)) { ret = true; - g_free(dstmdev->type); - dstmdev->type = g_strdup(srcmdev->type); + g_free(dstmdev->dev_config.type); + dstmdev->dev_config.type = g_strdup(srcmdev->dev_config.type); } if (STRNEQ_NULLABLE(dstmdev->uuid, srcmdev->uuid)) { @@ -XXX,XX +XXX,XX @@ nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, dstmdev->uuid = g_strdup(srcmdev->uuid); } - if (virMediatedDeviceAttrsCopy(dstmdev, srcmdev)) + if (virMediatedDeviceAttrsCopy(&dstmdev->dev_config, &srcmdev->dev_config)) ret = true; if (dstmdev->autostart != srcmdev->autostart) { diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -XXX,XX +XXX,XX @@ udevProcessMediatedDevice(struct udev_device *dev, return -1; } - data->type = g_path_get_basename(canonicalpath); + data->dev_config.type = g_path_get_basename(canonicalpath); data->uuid = g_strdup(udev_device_get_sysname(dev)); if ((iommugrp = virMediatedDeviceGetIOMMUGroupNum(data->uuid)) < 0) diff --git a/src/util/virmdev.h b/src/util/virmdev.h index XXXXXXX..XXXXXXX 100644 --- a/src/util/virmdev.h +++ b/src/util/virmdev.h @@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceAttr, virMediatedDeviceAttrFree); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceList, virObjectUnref); +typedef struct _virMediatedDeviceConfig virMediatedDeviceConfig; +struct _virMediatedDeviceConfig { + char *type; + virMediatedDeviceAttr **attributes; + size_t nattributes; +}; typedef struct _virMediatedDeviceType virMediatedDeviceType; struct _virMediatedDeviceType { -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Refactor attribute handling code into methods for easier reuse. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- src/conf/node_device_conf.c | 27 ++++--- src/node_device/node_device_driver.c | 104 ++++++++++++++++----------- 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapStorageDefFormat(virBuffer *buf, } static void -virNodeDeviceCapMdevDefFormat(virBuffer *buf, - const virNodeDevCapData *data) +virNodeDeviceCapMdevAttrFormat(virBuffer *buf, + const virMediatedDeviceConfig *config) { size_t i; + for (i = 0; i < config->nattributes; i++) { + virMediatedDeviceAttr *attr = config->attributes[i]; + virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n", + attr->name, attr->value); + } +} + +static void +virNodeDeviceCapMdevDefFormat(virBuffer *buf, + const virNodeDevCapData *data) +{ virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.dev_config.type); virBufferEscapeString(buf, "<uuid>%s</uuid>\n", data->mdev.uuid); virBufferEscapeString(buf, "<parent_addr>%s</parent_addr>\n", @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapMdevDefFormat(virBuffer *buf, virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n", data->mdev.iommuGroupNumber); - for (i = 0; i < data->mdev.dev_config.nattributes; i++) { - virMediatedDeviceAttr *attr = data->mdev.dev_config.attributes[i]; - virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n", - attr->name, attr->value); - } + virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.dev_config); } static void @@ -XXX,XX +XXX,XX @@ virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt, static int virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt, xmlNodePtr node, - virNodeDevCapMdev *mdev) + virMediatedDeviceConfig *config) { VIR_XPATH_NODE_AUTORESTORE(ctxt) g_autoptr(virMediatedDeviceAttr) attr = virMediatedDeviceAttrNew(); @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt, return -1; } - VIR_APPEND_ELEMENT(mdev->dev_config.attributes, mdev->dev_config.nattributes, attr); + VIR_APPEND_ELEMENT(config->attributes, config->nattributes, attr); return 0; } @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, return -1; for (i = 0; i < nattrs; i++) - virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], mdev); + virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->dev_config); return 0; } diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceHasCapability(virNodeDeviceDef *def, virNodeDevCapType type) } -/* format a json string that provides configuration information about this mdev - * to the mdevctl utility */ static int -nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) +nodeDeviceAttributesToJSON(virJSONValue *json, + virMediatedDeviceConfig *config) { size_t i; - virNodeDevCapMdev *mdev = &def->caps->data.mdev; - g_autoptr(virJSONValue) json = virJSONValueNewObject(); - const char *startval = mdev->autostart ? "auto" : "manual"; - - if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) - return -1; - - if (virJSONValueObjectAppendString(json, "start", startval) < 0) - return -1; - - if (mdev->dev_config.attributes) { + if (config->attributes) { g_autoptr(virJSONValue) attributes = virJSONValueNewArray(); - for (i = 0; i < mdev->dev_config.nattributes; i++) { - virMediatedDeviceAttr *attr = mdev->dev_config.attributes[i]; + for (i = 0; i < config->nattributes; i++) { + virMediatedDeviceAttr *attr = config->attributes[i]; g_autoptr(virJSONValue) jsonattr = virJSONValueNewObject(); if (virJSONValueObjectAppendString(jsonattr, attr->name, attr->value) < 0) @@ -XXX,XX +XXX,XX @@ nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) return -1; } + return 0; +} + + +/* format a json string that provides configuration information about this mdev + * to the mdevctl utility */ +static int +nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) +{ + virNodeDevCapMdev *mdev = &def->caps->data.mdev; + g_autoptr(virJSONValue) json = virJSONValueNewObject(); + const char *startval = mdev->autostart ? "auto" : "manual"; + + if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) + return -1; + + if (virJSONValueObjectAppendString(json, "start", startval) < 0) + return -1; + + if (nodeDeviceAttributesToJSON(json, &mdev->dev_config) < 0) + return -1; + *buf = virJSONValueToString(json, false); if (!*buf) return -1; @@ -XXX,XX +XXX,XX @@ matchDeviceAddress(virNodeDeviceObj *obj, } +static int +nodeDeviceParseMdevctlAttributes(virMediatedDeviceConfig *config, + virJSONValue *attrs) +{ + size_t i; + + if (attrs && virJSONValueIsArray(attrs)) { + int nattrs = virJSONValueArraySize(attrs); + + config->attributes = g_new0(virMediatedDeviceAttr*, nattrs); + config->nattributes = nattrs; + + for (i = 0; i < nattrs; i++) { + virJSONValue *attr = virJSONValueArrayGet(attrs, i); + virMediatedDeviceAttr *attribute; + virJSONValue *value; + + if (!virJSONValueIsObject(attr) || + virJSONValueObjectKeysNumber(attr) != 1) + return -1; + + attribute = g_new0(virMediatedDeviceAttr, 1); + attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0)); + value = virJSONValueObjectGetValue(attr, 0); + attribute->value = g_strdup(virJSONValueGetString(value)); + config->attributes[i] = attribute; + } + } + + return 0; +} + + static virNodeDeviceDef* nodeDeviceParseMdevctlChildDevice(const char *parent, virJSONValue *json) @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, virNodeDevCapMdev *mdev; const char *uuid; virJSONValue *props; - virJSONValue *attrs; g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1); virNodeDeviceObj *parent_obj; const char *start = NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, start = virJSONValueObjectGetString(props, "start"); mdev->autostart = STREQ_NULLABLE(start, "auto"); - attrs = virJSONValueObjectGet(props, "attrs"); - - if (attrs && virJSONValueIsArray(attrs)) { - size_t i; - int nattrs = virJSONValueArraySize(attrs); - - mdev->dev_config.attributes = g_new0(virMediatedDeviceAttr*, nattrs); - mdev->dev_config.nattributes = nattrs; - - for (i = 0; i < nattrs; i++) { - virJSONValue *attr = virJSONValueArrayGet(attrs, i); - virMediatedDeviceAttr *attribute; - virJSONValue *value; - - if (!virJSONValueIsObject(attr) || - virJSONValueObjectKeysNumber(attr) != 1) - return NULL; + if (nodeDeviceParseMdevctlAttributes(&mdev->dev_config, + virJSONValueObjectGet(props, "attrs")) < 0) + return NULL; - attribute = g_new0(virMediatedDeviceAttr, 1); - attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0)); - value = virJSONValueObjectGetValue(attr, 0); - attribute->value = g_strdup(virJSONValueGetString(value)); - mdev->dev_config.attributes[i] = attribute; - } - } mdevGenerateDeviceName(child); return g_steal_pointer(&child); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
virBufferEscapeString already contains the null check. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- src/conf/node_device_conf.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def) virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->name); virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path); - if (def->devnode) - virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", - def->devnode); + virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", + def->devnode); if (def->devlinks) { for (i = 0; def->devlinks[i]; i++) virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n", def->devlinks[i]); } - if (def->parent) - virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent); + virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent); if (def->driver) { virBufferAddLit(&buf, "<driver>\n"); virBufferAdjustIndent(&buf, 2); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
The configuration of a defined mdev can be modified after the mdev is started. The defined configuration and the active configuration can therefore run out of sync. Handle this by storing the modifiable data which is the mdev type and attributes in two separate active and defined configurations. mdevctl supports with callout scripts to do an attribute retrieval of started mdevs which is already implemented in libvirt. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- include/libvirt/libvirt-nodedev.h | 11 ++++ src/conf/node_device_conf.c | 53 ++++++++++------ src/conf/node_device_conf.h | 5 +- src/libvirt-nodedev.c | 2 +- src/node_device/node_device_driver.c | 61 +++++++++++++------ src/node_device/node_device_driver.h | 6 +- src/node_device/node_device_udev.c | 4 +- src/test/test_driver.c | 6 +- tests/nodedevmdevctltest.c | 4 +- ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 14 +++++ ...d_b7f0_4fea_b468_f1da537d301b_inactive.xml | 1 + ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 10 +++ ...c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml | 9 +++ ...9_36ea_4111_8f0a_8c9a70e21366_inactive.xml | 1 + ...9_495e_4243_ad9f_beb3f14c23d9_inactive.xml | 1 + ...4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml | 8 +++ ...6_1ca8_49ac_b176_871d16c13076_inactive.xml | 1 + tests/nodedevxml2xmltest.c | 59 +++++++++++++++--- 18 files changed, 197 insertions(+), 59 deletions(-) create mode 100644 tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 120000 tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -XXX,XX +XXX,XX @@ int virNodeDeviceListCaps (virNodeDevicePtr dev, char **const names, int maxnames); +/** + * virNodeDeviceXMLFlags: + * + * Flags used to provide the state of the returned node device configuration. + * + * Since: 10.1.0 + */ +typedef enum { + VIR_NODE_DEVICE_XML_INACTIVE = 1 << 0, /* dump inactive device configuration (Since: 10.1.0) */ +} virNodeDeviceXMLFlags; + char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev, unsigned int flags); diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapMdevAttrFormat(virBuffer *buf, static void virNodeDeviceCapMdevDefFormat(virBuffer *buf, - const virNodeDevCapData *data) + const virNodeDevCapData *data, + bool defined) { - virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.dev_config.type); + if (defined) + virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.defined_config.type); + else + virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.active_config.type); virBufferEscapeString(buf, "<uuid>%s</uuid>\n", data->mdev.uuid); virBufferEscapeString(buf, "<parent_addr>%s</parent_addr>\n", data->mdev.parent_addr); virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n", data->mdev.iommuGroupNumber); - - virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.dev_config); + if (defined) + virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.defined_config); + else + virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.active_config); } static void @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapCSSDefFormat(virBuffer *buf, char * -virNodeDeviceDefFormat(const virNodeDeviceDef *def) +virNodeDeviceDefFormat(const virNodeDeviceDef *def, unsigned int flags) { g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; virNodeDevCapsDef *caps; size_t i = 0; + bool inactive_state = flags & VIR_NODE_DEVICE_XML_INACTIVE; virBufferAddLit(&buf, "<device>\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->name); - virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path); - virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", - def->devnode); - if (def->devlinks) { - for (i = 0; def->devlinks[i]; i++) - virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n", - def->devlinks[i]); + if (!inactive_state) { + virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path); + virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", + def->devnode); + if (def->devlinks) { + for (i = 0; def->devlinks[i]; i++) + virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n", + def->devlinks[i]); + } } virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent); - if (def->driver) { + if (def->driver && !inactive_state) { virBufferAddLit(&buf, "<driver>\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->driver); @@ -XXX,XX +XXX,XX @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def) virBufferEscapeString(&buf, "<type>%s</type>\n", virNodeDevDRMTypeToString(data->drm.type)); break; case VIR_NODE_DEV_CAP_MDEV: - virNodeDeviceCapMdevDefFormat(&buf, data); + virNodeDeviceCapMdevDefFormat(&buf, data, inactive_state); break; case VIR_NODE_DEV_CAP_CCW_DEV: virNodeDeviceCapCCWDefFormat(&buf, data); @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, ctxt->node = node; - if (!(mdev->dev_config.type = virXPathString("string(./type[1]/@id)", ctxt))) { + if (!(mdev->defined_config.type = virXPathString("string(./type[1]/@id)", ctxt))) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("missing type id attribute for '%1$s'"), def->name); return -1; @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, return -1; for (i = 0; i < nattrs; i++) - virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->dev_config); + virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->defined_config); return 0; } @@ -XXX,XX +XXX,XX @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps) g_free(data->sg.path); break; case VIR_NODE_DEV_CAP_MDEV: - g_free(data->mdev.dev_config.type); + g_free(data->mdev.defined_config.type); + g_free(data->mdev.active_config.type); g_free(data->mdev.uuid); - for (i = 0; i < data->mdev.dev_config.nattributes; i++) - virMediatedDeviceAttrFree(data->mdev.dev_config.attributes[i]); - g_free(data->mdev.dev_config.attributes); + for (i = 0; i < data->mdev.defined_config.nattributes; i++) + virMediatedDeviceAttrFree(data->mdev.defined_config.attributes[i]); + g_free(data->mdev.defined_config.attributes); + for (i = 0; i < data->mdev.active_config.nattributes; i++) + virMediatedDeviceAttrFree(data->mdev.active_config.attributes[i]); + g_free(data->mdev.active_config.attributes); g_free(data->mdev.parent_addr); break; case VIR_NODE_DEV_CAP_CSS_DEV: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -XXX,XX +XXX,XX @@ typedef struct _virNodeDevCapMdev virNodeDevCapMdev; struct _virNodeDevCapMdev { unsigned int iommuGroupNumber; char *uuid; - virMediatedDeviceConfig dev_config; + virMediatedDeviceConfig defined_config; + virMediatedDeviceConfig active_config; char *parent_addr; bool autostart; }; @@ -XXX,XX +XXX,XX @@ struct _virNodeDeviceDef { }; char * -virNodeDeviceDefFormat(const virNodeDeviceDef *def); +virNodeDeviceDefFormat(const virNodeDeviceDef *def, unsigned int flags); typedef int (*virNodeDeviceDefPostParseCallback)(virNodeDeviceDef *dev, diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, /** * virNodeDeviceGetXMLDesc: * @dev: pointer to the node device - * @flags: extra flags; not used yet, so callers should always pass 0 + * @flags: bitwise-OR of virNodeDeviceXMLFlags * * Fetch an XML document describing all aspects of * the device. diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceGetXMLDesc(virNodeDevicePtr device, virNodeDeviceDef *def; char *ret = NULL; - virCheckFlags(0, NULL); + virCheckFlags(VIR_NODE_DEVICE_XML_INACTIVE, NULL); if (nodeDeviceInitWait() < 0) return NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceGetXMLDesc(virNodeDevicePtr device, if (virNodeDeviceUpdateCaps(def) < 0) goto cleanup; - ret = virNodeDeviceDefFormat(def); + if (flags & VIR_NODE_DEVICE_XML_INACTIVE) { + if (!virNodeDeviceObjIsPersistent(obj)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("node device '%1$s' is not persistent"), + def->name); + goto cleanup; + } + } else { + if (!virNodeDeviceObjIsActive(obj)) + flags |= VIR_NODE_DEVICE_XML_INACTIVE; + } + + ret = virNodeDeviceDefFormat(def, flags); cleanup: virNodeDeviceObjEndAPI(&obj); @@ -XXX,XX +XXX,XX @@ nodeDeviceAttributesToJSON(virJSONValue *json, /* format a json string that provides configuration information about this mdev * to the mdevctl utility */ static int -nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) +nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf, bool defined) { virNodeDevCapMdev *mdev = &def->caps->data.mdev; + virMediatedDeviceConfig *mdev_config = defined ? &mdev->defined_config : &mdev->active_config; g_autoptr(virJSONValue) json = virJSONValueNewObject(); const char *startval = mdev->autostart ? "auto" : "manual"; - if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) + if (virJSONValueObjectAppendString(json, "mdev_type", mdev_config->type) < 0) return -1; if (virJSONValueObjectAppendString(json, "start", startval) < 0) return -1; - if (nodeDeviceAttributesToJSON(json, &mdev->dev_config) < 0) + if (nodeDeviceAttributesToJSON(json, mdev_config) < 0) return -1; *buf = virJSONValueToString(json, false); @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, return NULL; } - if (nodeDeviceDefToMdevctlConfig(def, &inbuf) < 0) { + if (nodeDeviceDefToMdevctlConfig(def, &inbuf, true) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("couldn't convert node device def to mdevctl JSON")); return NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlAttributes(virMediatedDeviceConfig *config, static virNodeDeviceDef* nodeDeviceParseMdevctlChildDevice(const char *parent, - virJSONValue *json) + virJSONValue *json, + bool defined) { virNodeDevCapMdev *mdev; + virMediatedDeviceConfig *mdev_config; const char *uuid; virJSONValue *props; g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1); @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, child->caps->data.type = VIR_NODE_DEV_CAP_MDEV; mdev = &child->caps->data.mdev; + mdev_config = defined ? &mdev->defined_config : &mdev->active_config; mdev->uuid = g_strdup(uuid); mdev->parent_addr = g_strdup(parent); - mdev->dev_config.type = + mdev_config->type = g_strdup(virJSONValueObjectGetString(props, "mdev_type")); start = virJSONValueObjectGetString(props, "start"); mdev->autostart = STREQ_NULLABLE(start, "auto"); - if (nodeDeviceParseMdevctlAttributes(&mdev->dev_config, + if (nodeDeviceParseMdevctlAttributes(mdev_config, virJSONValueObjectGet(props, "attrs")) < 0) return NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, int nodeDeviceParseMdevctlJSON(const char *jsonstring, - virNodeDeviceDef ***devs) + virNodeDeviceDef ***devs, + bool defined) { int n; g_autoptr(virJSONValue) json_devicelist = NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlJSON(const char *jsonstring, g_autoptr(virNodeDeviceDef) child = NULL; virJSONValue *child_obj = virJSONValueArrayGet(child_array, j); - if (!(child = nodeDeviceParseMdevctlChildDevice(parent, child_obj))) { + if (!(child = nodeDeviceParseMdevctlChildDevice(parent, child_obj, defined))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to parse child device")); goto error; @@ -XXX,XX +XXX,XX @@ nodeDeviceUpdateMediatedDevice(virNodeDeviceDef *def, /* Active devices contain some additional information (e.g. sysfs * path) that is not provided by mdevctl, so re-use the existing * definition and copy over new mdev data */ - changed = nodeDeviceDefCopyFromMdevctl(olddef, owned); + changed = nodeDeviceDefCopyFromMdevctl(olddef, owned, defined); if (was_defined && !changed) { /* if this device was already defined and the definition @@ -XXX,XX +XXX,XX @@ virMdevctlList(bool defined, return -1; } - return nodeDeviceParseMdevctlJSON(output, devs); + return nodeDeviceParseMdevctlJSON(output, devs, defined); } @@ -XXX,XX +XXX,XX @@ virMediatedDeviceAttrsCopy(virMediatedDeviceConfig *dst_config, * Returns true if anything was copied, else returns false */ bool nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, - virNodeDeviceDef *src) + virNodeDeviceDef *src, + bool defined) { bool ret = false; virNodeDevCapMdev *srcmdev = &src->caps->data.mdev; virNodeDevCapMdev *dstmdev = &dst->caps->data.mdev; + virMediatedDeviceConfig *srcmdevconfig = &src->caps->data.mdev.active_config; + virMediatedDeviceConfig *dstmdevconfig = &dst->caps->data.mdev.active_config; + + if (defined) { + srcmdevconfig = &src->caps->data.mdev.defined_config; + dstmdevconfig = &dst->caps->data.mdev.defined_config; + } - if (STRNEQ_NULLABLE(dstmdev->dev_config.type, srcmdev->dev_config.type)) { + if (STRNEQ_NULLABLE(dstmdevconfig->type, srcmdevconfig->type)) { ret = true; - g_free(dstmdev->dev_config.type); - dstmdev->dev_config.type = g_strdup(srcmdev->dev_config.type); + g_free(dstmdevconfig->type); + dstmdevconfig->type = g_strdup(srcmdevconfig->type); } if (STRNEQ_NULLABLE(dstmdev->uuid, srcmdev->uuid)) { @@ -XXX,XX +XXX,XX @@ nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, dstmdev->uuid = g_strdup(srcmdev->uuid); } - if (virMediatedDeviceAttrsCopy(&dstmdev->dev_config, &srcmdev->dev_config)) + if (virMediatedDeviceAttrsCopy(dstmdevconfig, srcmdevconfig)) ret = true; if (dstmdev->autostart != srcmdev->autostart) { diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlListCommand(bool defined, int nodeDeviceParseMdevctlJSON(const char *jsonstring, - virNodeDeviceDef ***devs); + virNodeDeviceDef ***devs, + bool defined); int nodeDeviceUpdateMediatedDevices(void); @@ -XXX,XX +XXX,XX @@ nodeDeviceGenerateName(virNodeDeviceDef *def, const char *s); bool nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, - virNodeDeviceDef *src); + virNodeDeviceDef *src, + bool defined); int nodeDeviceCreate(virNodeDevice *dev, diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -XXX,XX +XXX,XX @@ udevProcessMediatedDevice(struct udev_device *dev, return -1; } - data->dev_config.type = g_path_get_basename(canonicalpath); + data->active_config.type = g_path_get_basename(canonicalpath); data->uuid = g_strdup(udev_device_get_sysname(dev)); if ((iommugrp = virMediatedDeviceGetIOMMUGroupNum(data->uuid)) < 0) @@ -XXX,XX +XXX,XX @@ udevAddOneDevice(struct udev_device *device) objdef = virNodeDeviceObjGetDef(obj); if (is_mdev) - nodeDeviceDefCopyFromMdevctl(def, objdef); + nodeDeviceDefCopyFromMdevctl(def, objdef, false); persistent = virNodeDeviceObjIsPersistent(obj); autostart = virNodeDeviceObjIsAutostart(obj); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -XXX,XX +XXX,XX @@ testNodeDeviceGetXMLDesc(virNodeDevicePtr dev, virNodeDeviceObj *obj; char *ret = NULL; - virCheckFlags(0, NULL); + virCheckFlags(VIR_NODE_DEVICE_XML_INACTIVE, NULL); if (!(obj = testNodeDeviceObjFindByName(driver, dev->name))) return NULL; - ret = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(obj)); + ret = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(obj), flags); virNodeDeviceObjEndAPI(&obj); return ret; @@ -XXX,XX +XXX,XX @@ testNodeDeviceMockCreateVport(testDriver *driver, "scsi_host11"))) goto cleanup; - xml = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(objcopy)); + xml = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(objcopy), 0); virNodeDeviceObjEndAPI(&objcopy); if (!xml) goto cleanup; diff --git a/tests/nodedevmdevctltest.c b/tests/nodedevmdevctltest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/nodedevmdevctltest.c +++ b/tests/nodedevmdevctltest.c @@ -XXX,XX +XXX,XX @@ testMdevctlParse(const void *data) return -1; } - if ((nmdevs = nodeDeviceParseMdevctlJSON(buf, &mdevs)) < 0) { + if ((nmdevs = nodeDeviceParseMdevctlJSON(buf, &mdevs, true)) < 0) { VIR_TEST_DEBUG("Unable to parse json for %s", filename); return -1; } for (i = 0; i < nmdevs; i++) { - g_autofree char *devxml = virNodeDeviceDefFormat(mdevs[i]); + g_autofree char *devxml = virNodeDeviceDefFormat(mdevs[i], VIR_NODE_DEVICE_XML_INACTIVE); if (!devxml) goto cleanup; virBufferAddStr(&xmloutbuf, devxml); diff --git a/tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml b/tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <path>/sys/devices/css0/0.0.0052/c60cc60c-c60c-c60c-c60c-c60cc60cc60c</path> + <parent>css_0_0_0052</parent> + <driver> + <name>vfio_ccw_mdev</name> + </driver> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <parent_addr>0.0.0052</parent_addr> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml b/tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml @@ -0,0 +1 @@ +mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <path>/sys/devices/css0/0.0.0052/c60cc60c-c60c-c60c-c60c-c60cc60cc60c</path> + <parent>css_0_0_0052</parent> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <parent>css_0_0_0052</parent> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml b/tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml @@ -0,0 +1 @@ +mdev_d069d019_36ea_4111_8f0a_8c9a70e21366.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml b/tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml @@ -0,0 +1 @@ +mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml b/tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_ee0b88c4-f554-4dc1-809d-b2a01e8e48ad</name> + <parent>ap_matrix</parent> + <capability type='mdev'> + <type id='vfio_ap-passthrough'/> + <iommuGroup number='0'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml b/tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml @@ -0,0 +1 @@ +mdev_fedc4916_1ca8_49ac_b176_871d16c13076.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/nodedevxml2xmltest.c +++ b/tests/nodedevxml2xmltest.c @@ -XXX,XX +XXX,XX @@ #define VIR_FROM_THIS VIR_FROM_NONE +struct TestData { + const char *filename; + unsigned int flags; +}; + static int -testCompareXMLToXMLFiles(const char *xml, const char *outfile) +testCompareXMLToXMLFiles(const char *xml, const char *outfile, unsigned int flags) { g_autofree char *xmlData = NULL; g_autofree char *actual = NULL; int ret = -1; virNodeDeviceDef *dev = NULL; virNodeDevCapsDef *caps; + size_t i; if (virTestLoadFile(xml, &xmlData) < 0) goto fail; @@ -XXX,XX +XXX,XX @@ testCompareXMLToXMLFiles(const char *xml, const char *outfile) data->storage.logical_block_size; } } + + if (caps->data.type == VIR_NODE_DEV_CAP_MDEV && + !(flags & VIR_NODE_DEVICE_XML_INACTIVE)) { + data->mdev.active_config.type = g_strdup(data->mdev.defined_config.type); + for (i = 0; i < data->mdev.defined_config.nattributes; i++) { + g_autoptr(virMediatedDeviceAttr) attr = g_new0(virMediatedDeviceAttr, 1); + attr->name = g_strdup(data->mdev.defined_config.attributes[i]->name); + attr->value = g_strdup(data->mdev.defined_config.attributes[i]->value); + VIR_APPEND_ELEMENT(data->mdev.active_config.attributes, + data->mdev.active_config.nattributes, + attr); + } + } } - if (!(actual = virNodeDeviceDefFormat(dev))) + if (!(actual = virNodeDeviceDefFormat(dev, flags))) goto fail; if (virTestCompareToFile(actual, outfile) < 0) @@ -XXX,XX +XXX,XX @@ static int testCompareXMLToXMLHelper(const void *data) { int result = -1; + const struct TestData *tdata = data; g_autofree char *xml = NULL; g_autofree char *outfile = NULL; xml = g_strdup_printf("%s/nodedevschemadata/%s.xml", abs_srcdir, - (const char *)data); + tdata->filename); - outfile = g_strdup_printf("%s/nodedevxml2xmlout/%s.xml", abs_srcdir, - (const char *)data); + if (tdata->flags & VIR_NODE_DEVICE_XML_INACTIVE) + outfile = g_strdup_printf("%s/nodedevxml2xmlout/%s_inactive.xml", abs_srcdir, + tdata->filename); + else + outfile = g_strdup_printf("%s/nodedevxml2xmlout/%s.xml", abs_srcdir, + tdata->filename); - result = testCompareXMLToXMLFiles(xml, outfile); + result = testCompareXMLToXMLFiles(xml, outfile, tdata->flags); return result; } @@ -XXX,XX +XXX,XX @@ mymain(void) { int ret = 0; +#define DO_TEST_FLAGS(desc, filename, flags) \ + do { \ + struct TestData data = { filename, flags }; \ + if (virTestRun(desc, testCompareXMLToXMLHelper, &data) < 0) \ + ret = -1; \ + } \ + while (0) + #define DO_TEST(name) \ - if (virTestRun("Node device XML-2-XML " name, \ - testCompareXMLToXMLHelper, (name)) < 0) \ - ret = -1 + DO_TEST_FLAGS("Node device XML-2-XML " name, name, 0) + +#define DO_TEST_INACTIVE(name) \ + DO_TEST_FLAGS("Node device XML-2-XML INACTIVE " name, \ + name, VIR_NODE_DEVICE_XML_INACTIVE) DO_TEST("computer"); DO_TEST("DVD_GCC_4247N"); @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST("pci_0000_02_10_7_mdev_types"); DO_TEST("pci_0000_42_00_0_vpd"); DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); + DO_TEST_INACTIVE("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); DO_TEST("ccw_0_0_ffff"); DO_TEST("css_0_0_ffff"); DO_TEST("css_0_0_ffff_channel_dev_addr"); @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST("mdev_d069d019_36ea_4111_8f0a_8c9a70e21366"); DO_TEST("mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9"); DO_TEST("mdev_fedc4916_1ca8_49ac_b176_871d16c13076"); + DO_TEST_INACTIVE("mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad"); + DO_TEST_INACTIVE("mdev_d069d019_36ea_4111_8f0a_8c9a70e21366"); + DO_TEST_INACTIVE("mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9"); + DO_TEST_INACTIVE("mdev_fedc4916_1ca8_49ac_b176_871d16c13076"); DO_TEST("hba_vport_ops"); + DO_TEST("mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c"); + DO_TEST_INACTIVE("mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c"); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Allow to dump the XML of the persisted mdev when the mdev has been started instead of the current state only. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- docs/manpages/virsh.rst | 7 +++++-- tools/virsh-nodedev.c | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ nodedev-dumpxml :: - nodedev-dumpxml [--xpath EXPRESSION] [--wrap] device + nodedev-dumpxml [--inactive] [--xpath EXPRESSION] [--wrap] device Dump a <device> XML representation for the given node device, including such information as the device name, which bus owns the device, the vendor and product id, and any capabilities of the device usable by libvirt (such as whether device reset is supported). *device* can be either device name or wwn pair in "wwnn,wwpn" format (only works -for HBA). +for HBA). An additional option affecting the XML dump may be +used. *--inactive* tells virsh to dump the node device configuration +that will be used on next start of the node device as opposed to the +current node device configuration. If the **--xpath** argument provides an XPath expression, it will be evaluated against the output XML and only those matching nodes will diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ static const vshCmdOptDef opts_node_device_dumpxml[] = { .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, }, + {.name = "inactive", + .type = VSH_OT_BOOL, + .help = N_("show inactive defined XML"), + }, {.name = "xpath", .type = VSH_OT_STRING, .flags = VSH_OFLAG_REQ_OPT, @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) g_autoptr(virshNodeDevice) device = NULL; g_autofree char *xml = NULL; const char *device_value = NULL; + unsigned int flags = 0; bool wrap = vshCommandOptBool(cmd, "wrap"); const char *xpath = NULL; @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) if (!device) return false; - if (!(xml = virNodeDeviceGetXMLDesc(device, 0))) + if (vshCommandOptBool(cmd, "inactive")) + flags |= VIR_NODE_DEVICE_XML_INACTIVE; + + if (!(xml = virNodeDeviceGetXMLDesc(device, flags))) return false; return virshDumpXML(ctl, xml, "node-device", xpath, wrap); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Allow to filter node devices based on their persisted or transient states. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- include/libvirt/libvirt-nodedev.h | 2 ++ src/conf/node_device_conf.h | 7 ++++++- src/conf/virnodedeviceobj.c | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -XXX,XX +XXX,XX @@ typedef enum { VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX = 1 << 20, /* s390 AP Matrix (Since: 7.0.0) */ VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD = 1 << 21, /* Device with VPD (Since: 7.9.0) */ + VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT = 1 << 28, /* Persisted devices (Since: 10.1.0) */ + VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT = 1 << 29, /* Transient devices (Since: 10.1.0) */ VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE = 1 << 30, /* Inactive devices (Since: 7.3.0) */ VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE = 1U << 31, /* Active devices (Since: 7.3.0) */ } virConnectListAllNodeDeviceFlags; diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNodeDevCapsDef, virNodeDevCapsDefFree); VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE | \ VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE +#define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_PERSISTENT \ + VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT | \ + VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT + #define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ALL \ VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP | \ - VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE + VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_PERSISTENT int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHost *scsi_host); diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceObjMatch(virNodeDeviceObj *obj, return false; } + if (flags & (VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_PERSISTENT)) { + if (!((MATCH(VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT) && + virNodeDeviceObjIsPersistent(obj)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT) && + !virNodeDeviceObjIsPersistent(obj)))) + return false; + } + return true; } #undef MATCH -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Now that we can filter persisted and transient node devices in virConnectListAllNodeDevices(), add these switches also to the virsh nodedev-list command. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- docs/manpages/virsh.rst | 8 ++++++-- tools/virsh-nodedev.c | 24 ++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ nodedev-list :: - nodedev-list [--cap capability] [--tree] [--inactive | --all] + nodedev-list [--cap capability] [--tree] [--inactive | --all] [--persistent | --transient] List all of the devices available on the node that are known by libvirt. *cap* is used to filter the list by capability types, the types must be @@ -XXX,XX +XXX,XX @@ separated by comma, e.g. --cap pci,scsi. Valid capability types include 'scsi', 'storage', 'fc_host', 'vports', 'scsi_generic', 'drm', 'mdev', 'mdev_types', 'ccw', 'css', 'ap_card', 'ap_queue', 'ap_matrix'. By default, only active devices are listed. *--inactive* is used to list only inactive -devices, and *-all* is used to list both active and inactive devices. +devices, and *--all* is used to list both active and inactive devices. +*--persistent* is used to list only persistent devices, and *--transient* is +used to list only transient devices. Not providing *--persistent* or +*--transient* will list all devices unless filtered otherwise. *--transient* +is mutually exclusive with *--persistent* and *--inactive*. If *--tree* is used, the output is formatted in a tree representing parents of each node. *--tree* is mutually exclusive with all other options. diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ static const vshCmdOptDef opts_node_list_devices[] = { .type = VSH_OT_BOOL, .help = N_("list inactive & active devices") }, + {.name = "persistent", + .type = VSH_OT_BOOL, + .help = N_("list persistent devices") + }, + {.name = "transient", + .type = VSH_OT_BOOL, + .help = N_("list transient devices") + }, {.name = NULL} }; @@ -XXX,XX +XXX,XX @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) int cap_type = -1; bool inactive = vshCommandOptBool(cmd, "inactive"); bool all = vshCommandOptBool(cmd, "all"); + bool persistent = vshCommandOptBool(cmd, "persistent"); + bool transient = vshCommandOptBool(cmd, "transient"); ignore_value(vshCommandOptStringQuiet(ctl, cmd, "cap", &cap_str)); @@ -XXX,XX +XXX,XX @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) return false; } - if (tree && (cap_str || inactive)) { - vshError(ctl, "%s", _("Option --tree is incompatible with --cap and --inactive")); + if (transient && (persistent || inactive)) { + vshError(ctl, "%s", _("Option --transient is incompatible with --persistent and --inactive")); + return false; + } + + if (tree && (cap_str || inactive || persistent || transient)) { + vshError(ctl, "%s", _("Option --tree is incompatible with --cap, --inactive, --persistent and --transient")); return false; } @@ -XXX,XX +XXX,XX @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) if (!inactive) flags |= VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE; + if (persistent) + flags |= VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT; + if (transient) + flags |= VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT; + if (!(list = virshNodeDeviceListCollect(ctl, caps, ncaps, flags))) { ret = false; goto cleanup; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Commit 26136e3 allowed to use option all with option tree but did not update the manpage. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- docs/manpages/virsh.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ used to list only transient devices. Not providing *--persistent* or *--transient* will list all devices unless filtered otherwise. *--transient* is mutually exclusive with *--persistent* and *--inactive*. If *--tree* is used, the output is formatted in a tree representing parents of -each node. *--tree* is mutually exclusive with all other options. +each node. *--tree* is mutually exclusive with all other options but *--all*. nodedev-reattach -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
A public API method which allows to update or modify objects is implemented for almost all other objects that have a concept of persistent definition and activatability. Currently node devices of type mdev can be persistent and active. This new method allows to update defined and active node devices as well. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- include/libvirt/libvirt-nodedev.h | 18 +++++++++++++ src/access/viraccessperm.c | 1 + src/access/viraccessperm.h | 6 +++++ src/conf/virnodedeviceobj.c | 42 +++++++++++++++++++++++++++++ src/conf/virnodedeviceobj.h | 3 +++ src/driver-nodedev.h | 6 +++++ src/libvirt-nodedev.c | 45 +++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 ++++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 17 +++++++++++- src/remote_protocol-structs | 6 +++++ 12 files changed, 150 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -XXX,XX +XXX,XX @@ int virNodeDeviceIsPersistent(virNodeDevicePtr dev); int virNodeDeviceIsActive(virNodeDevicePtr dev); +/** + * virNodeDeviceUpdateFlags: + * + * Flags to control options for virNodeDeviceUpdate() + * + * Since: 10.1.0 + */ +typedef enum { + VIR_NODE_DEVICE_UPDATE_AFFECT_CURRENT = 0, /* affect live if node device is active, + config if it's not active (Since: 10.1.0) */ + VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE = 1 << 0, /* affect live state of node device only (Since: 10.1.0) */ + VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG = 1 << 1, /* affect persistent config only (Since: 10.1.0) */ +} virNodeDeviceUpdateFlags; + +int virNodeDeviceUpdate(virNodeDevicePtr dev, + const char *xmlDesc, + unsigned int flags); + /** * VIR_NODE_DEVICE_EVENT_CALLBACK: * diff --git a/src/access/viraccessperm.c b/src/access/viraccessperm.c index XXXXXXX..XXXXXXX 100644 --- a/src/access/viraccessperm.c +++ b/src/access/viraccessperm.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virAccessPermNodeDevice, "getattr", "read", "write", "start", "stop", "detach", "delete", + "save", ); VIR_ENUM_IMPL(virAccessPermNWFilter, diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h index XXXXXXX..XXXXXXX 100644 --- a/src/access/viraccessperm.h +++ b/src/access/viraccessperm.h @@ -XXX,XX +XXX,XX @@ typedef enum { */ VIR_ACCESS_PERM_NODE_DEVICE_DELETE, + /** + * @desc: Save node device + * @message: Saving node device driver requires authorization + */ + VIR_ACCESS_PERM_NODE_DEVICE_SAVE, + VIR_ACCESS_PERM_NODE_DEVICE_LAST } virAccessPermNodeDevice; diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceObjListFind(virNodeDeviceObjList *devs, virNodeDeviceObjListFindHelper, &data); } + + +/** + * virNodeDeviceObjUpdateModificationImpact: + * @obj: Pointer to node device object + * @flags: flags to update the modification impact on + * + * Resolves virNodeDeviceUpdateFlags flags in @flags so that they correctly + * apply to the actual state of @obj. @flags may be modified after call to this + * function. + * + * Returns 0 on success if @flags point to a valid combination for @obj or -1 + * on error. + */ +int +virNodeDeviceObjUpdateModificationImpact(virNodeDeviceObj *obj, + unsigned int *flags) +{ + bool isActive = virNodeDeviceObjIsActive(obj); + + if ((*flags & (VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE | VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG)) == + VIR_NODE_DEVICE_UPDATE_AFFECT_CURRENT) { + if (isActive) + *flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE; + else + *flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG; + } + + if (!isActive && (*flags & VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("node device is not active")); + return -1; + } + + if (!virNodeDeviceObjIsPersistent(obj) && (*flags & VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("transient node devices do not have any persistent config")); + return -1; + } + + return 0; +} diff --git a/src/conf/virnodedeviceobj.h b/src/conf/virnodedeviceobj.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virnodedeviceobj.h +++ b/src/conf/virnodedeviceobj.h @@ -XXX,XX +XXX,XX @@ virNodeDeviceObj * virNodeDeviceObjListFind(virNodeDeviceObjList *devs, virNodeDeviceObjListPredicate callback, void *opaque); + +int virNodeDeviceObjUpdateModificationImpact(virNodeDeviceObj *obj, + unsigned int *flags); diff --git a/src/driver-nodedev.h b/src/driver-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/src/driver-nodedev.h +++ b/src/driver-nodedev.h @@ -XXX,XX +XXX,XX @@ typedef int typedef int (*virDrvNodeDeviceIsActive)(virNodeDevicePtr dev); +typedef int +(*virDrvNodeDeviceUpdate)(virNodeDevicePtr dev, + const char *xmlDesc, + unsigned int flags); + typedef int (*virDrvConnectNodeDeviceEventRegisterAny)(virConnectPtr conn, virNodeDevicePtr dev, @@ -XXX,XX +XXX,XX @@ struct _virNodeDeviceDriver { virDrvNodeDeviceGetAutostart nodeDeviceGetAutostart; virDrvNodeDeviceIsPersistent nodeDeviceIsPersistent; virDrvNodeDeviceIsActive nodeDeviceIsActive; + virDrvNodeDeviceUpdate nodeDeviceUpdate; }; diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -XXX,XX +XXX,XX @@ int virNodeDeviceIsActive(virNodeDevicePtr dev) virDispatchError(dev->conn); return -1; } + + +/** + * virNodeDeviceUpdate: + * @dev: pointer to the node device object + * @xmlDesc: string containing an XML description of the device to be defined + * @flags: bitwise OR of virNodeDeviceUpdateFlags + * + * Update the definition of an existing node device, either its live running + * configuration, its persistent configuration, or both. + * + * Returns 0 in case of success, -1 in case of error + * + * Since: 10.1.0 + */ +int +virNodeDeviceUpdate(virNodeDevicePtr dev, + const char *xmlDesc, + unsigned int flags) +{ + VIR_DEBUG("nodeDevice=%p, xmlDesc=%s, flags=0x%x", + dev, NULLSTR(xmlDesc), flags); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + + virCheckReadOnlyGoto(dev->conn->flags, error); + virCheckNonNullArgGoto(xmlDesc, error); + + if (dev->conn->nodeDeviceDriver && + dev->conn->nodeDeviceDriver->nodeDeviceUpdate) { + int retval = dev->conn->nodeDeviceDriver->nodeDeviceUpdate(dev, xmlDesc, flags); + if (retval < 0) + goto error; + + return 0; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -XXX,XX +XXX,XX @@ virNodeDeviceObjListRemoveLocked; virNodeDeviceObjSetActive; virNodeDeviceObjSetAutostart; virNodeDeviceObjSetPersistent; +virNodeDeviceObjUpdateModificationImpact; # conf/virnwfilterbindingdef.h diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -XXX,XX +XXX,XX @@ LIBVIRT_9.7.0 { virNetworkSetMetadata; } LIBVIRT_9.0.0; +LIBVIRT_10.1.0 { + global: + virNodeDeviceUpdate; +} LIBVIRT_9.7.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 XXXXXXX..XXXXXXX 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -XXX,XX +XXX,XX @@ static virNodeDeviceDriver node_device_driver = { .nodeDeviceSetAutostart = remoteNodeDeviceSetAutostart, /* 7.8.0 */ .nodeDeviceIsPersistent = remoteNodeDeviceIsPersistent, /* 7.8.0 */ .nodeDeviceIsActive = remoteNodeDeviceIsActive, /* 7.8.0 */ + .nodeDeviceUpdate = remoteNodeDeviceUpdate, /* 10.1.0 */ }; static virNWFilterDriver nwfilter_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index XXXXXXX..XXXXXXX 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -XXX,XX +XXX,XX @@ struct remote_node_device_is_active_ret { int active; }; +struct remote_node_device_update_args { + remote_nonnull_string name; + remote_nonnull_string xml_desc; + unsigned int flags; +}; + /* * Events Register/Deregister: @@ -XXX,XX +XXX,XX @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446 + REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446, + + /** + * @generate: both + * @priority: high + * @acl: node_device:write + * @acl: node_device:save:!VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG|VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE + * @acl: node_device:save:VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG + */ + REMOTE_PROC_NODE_DEVICE_UPDATE = 447 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index XXXXXXX..XXXXXXX 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -XXX,XX +XXX,XX @@ struct remote_node_device_is_active_args { struct remote_node_device_is_active_ret { int active; }; +struct remote_node_device_update_args { + remote_nonnull_string name; + remote_nonnull_string xml_desc; + u_int flags; +}; struct remote_connect_domain_event_register_ret { int cb_registered; }; @@ -XXX,XX +XXX,XX @@ enum remote_procedure { REMOTE_PROC_NETWORK_SET_METADATA = 444, REMOTE_PROC_NETWORK_GET_METADATA = 445, REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446, + REMOTE_PROC_NODE_DEVICE_UPDATE = 447, }; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Implement the API functions in the node device driver by using mdevctl modify with the options defined and live. Instead of increasing the minimum mdevctl version to 1.3.0 in spec file to ensure support exists in mdevctl the support is dynamically checked before using mdevctl. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- NEWS.rst | 7 + libvirt.spec.in | 1 + src/node_device/node_device_driver.c | 224 +++++++++++++++++- src/node_device/node_device_driver.h | 11 + src/node_device/node_device_udev.c | 1 + ...60c_c60c_c60c_c60c_c60cc60cc60c_update.xml | 16 ++ tests/nodedevmdevctldata/mdevctl-modify.argv | 25 ++ tests/nodedevmdevctldata/mdevctl-modify.json | 4 + tests/nodedevmdevctltest.c | 90 ++++++- 9 files changed, 376 insertions(+), 3 deletions(-) create mode 100644 tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.argv create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.json diff --git a/NEWS.rst b/NEWS.rst index XXXXXXX..XXXXXXX 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -XXX,XX +XXX,XX @@ v10.1.0 (unreleased) * **New features** + * nodedev: Support updating mdevs + + The node device driver has been extended to allow updating mediated node + devices. Options are available to target the update against the persisted, + active or both configurations of an mediated device. + **Note:** The support is only available with at least mdevctl v1.3.0 installed. + * qemu: Support clusters in CPU topology It is now possible to configure the guest CPU topology to use clusters. diff --git a/libvirt.spec.in b/libvirt.spec.in index XXXXXXX..XXXXXXX 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -XXX,XX +XXX,XX @@ Requires: libvirt-libs = %{version}-%{release} # needed for device enumeration Requires: systemd >= 185 # For managing persistent mediated devices +# Note: for nodedev-update support at least mdevctl v1.3.0 is required Requires: mdevctl # for modprobe of pci devices Requires: module-init-tools diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceDriverState *driver; VIR_ENUM_IMPL(virMdevctlCommand, MDEVCTL_CMD_LAST, - "start", "stop", "define", "undefine", "create" + "start", "stop", "define", "undefine", "create", "modify" ); @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, case MDEVCTL_CMD_START: case MDEVCTL_CMD_DEFINE: case MDEVCTL_CMD_UNDEFINE: + case MDEVCTL_CMD_MODIFY: cmd = virCommandNewArgList(MDEVCTL, subcommand, NULL); break; case MDEVCTL_CMD_LAST: @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, switch (cmd_type) { case MDEVCTL_CMD_CREATE: case MDEVCTL_CMD_DEFINE: + case MDEVCTL_CMD_MODIFY: if (!def->caps->data.mdev.parent_addr) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to find parent device '%1$s'"), def->parent); @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, virCommandAddArgPair(cmd, "--jsonfile", "/dev/stdin"); virCommandSetInputBuffer(cmd, inbuf); - virCommandSetOutputBuffer(cmd, outbuf); + if (outbuf) + virCommandSetOutputBuffer(cmd, outbuf); break; case MDEVCTL_CMD_UNDEFINE: @@ -XXX,XX +XXX,XX @@ virMdevctlDefine(virNodeDeviceDef *def, char **uuid) } +/* gets a virCommand object that executes a mdevctl command to modify a + * a device to an updated version + */ +virCommand* +nodeDeviceGetMdevctlModifyCommand(virNodeDeviceDef *def, + bool defined, + bool live, + char **errmsg) +{ + virCommand *cmd = nodeDeviceGetMdevctlCommand(def, + MDEVCTL_CMD_MODIFY, + NULL, errmsg); + + if (!cmd) + return NULL; + + if (defined) + virCommandAddArg(cmd, "--defined"); + + if (live) + virCommandAddArg(cmd, "--live"); + + return cmd; +} + + +/* checks if mdevctl supports on the command modify the options live, defined + * and jsonfile + */ +static int +nodeDeviceGetMdevctlModifySupportCheck(void) +{ + int status; + g_autoptr(virCommand) cmd = NULL; + const char *subcommand = virMdevctlCommandTypeToString(MDEVCTL_CMD_MODIFY); + + cmd = virCommandNewArgList(MDEVCTL, + subcommand, + "--defined", + "--live", + "--jsonfile", + "b", + "--help", + NULL); + + if (!cmd) + return -1; + + if (virCommandRun(cmd, &status) < 0) + return -1; + + if (status != 0) // update is unsupported + return -1; + + return 0; +} + + +static int +virMdevctlModify(virNodeDeviceDef *def, + bool defined, + bool live) +{ + int status; + g_autofree char *errmsg = NULL; + g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlModifyCommand(def, + defined, + live, + &errmsg); + + if (!cmd) + return -1; + + if (nodeDeviceGetMdevctlModifySupportCheck() < 0) { + VIR_WARN("Installed mdevctl version does not support modify with options jsonfile, defined and live"); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Unable to modify mediated device: modify unsupported")); + return -1; + } + + if (virCommandRun(cmd, &status) < 0) + return -1; + + if (status != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to modify mediated device: %1$s"), + MDEVCTL_ERROR(errmsg)); + return -1; + } + + return 0; +} + + static virNodeDevicePtr nodeDeviceCreateXMLMdev(virConnectPtr conn, virNodeDeviceDef *def) @@ -XXX,XX +XXX,XX @@ nodeDeviceIsActive(virNodeDevice *device) virNodeDeviceObjEndAPI(&obj); return ret; } + + +static int +nodeDeviceDefValidateUpdate(virNodeDeviceDef *def, + virNodeDeviceDef *new_def, + bool live) +{ + virNodeDevCapsDef *caps = NULL; + virNodeDevCapMdev *cap_mdev = NULL; + virNodeDevCapMdev *cap_new_mdev = NULL; + + for (caps = def->caps; caps != NULL; caps = caps->next) { + if (caps->data.type == VIR_NODE_DEV_CAP_MDEV) { + cap_mdev = &caps->data.mdev; + } + } + if (!cap_mdev) + return -1; + + for (caps = new_def->caps; caps != NULL; caps = caps->next) { + if (caps->data.type == VIR_NODE_DEV_CAP_MDEV) { + cap_new_mdev = &caps->data.mdev; + } + } + if (!cap_new_mdev) + return -1; + + if (STRNEQ_NULLABLE(cap_mdev->uuid, cap_new_mdev->uuid)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot update device '%1$s, uuid mismatch (current uuid '%2$s')"), + def->name, + cap_mdev->uuid); + return -1; + } + + /* A live update cannot change the mdev type. Since the new config is + * stored in defined_config, compare that to the mdev type of the current + * live config to make sure they match */ + if (live && + STRNEQ_NULLABLE(cap_mdev->active_config.type, cap_new_mdev->defined_config.type)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot update device '%1$s', type mismatch (current type '%2$s')"), + def->name, + cap_mdev->active_config.type); + return -1; + } + if (STRNEQ_NULLABLE(cap_mdev->parent_addr, cap_new_mdev->parent_addr)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot update device '%1$s', parent address mismatch (current parent address '%2$s')"), + def->name, + cap_mdev->parent_addr); + return -1; + } + + return 0; +} + + +int +nodeDeviceUpdate(virNodeDevice *device, + const char *xmlDesc, + unsigned int flags) +{ + int ret = -1; + virNodeDeviceObj *obj = NULL; + virNodeDeviceDef *def; + g_autoptr(virNodeDeviceDef) new_def = NULL; + const char *virt_type = NULL; + bool updated = false; + + virCheckFlags(VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE | + VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG, -1); + + if (nodeDeviceInitWait() < 0) + return -1; + + if (!(obj = nodeDeviceObjFindByName(device->name))) + return -1; + def = virNodeDeviceObjGetDef(obj); + + virt_type = virConnectGetType(device->conn); + + if (virNodeDeviceUpdateEnsureACL(device->conn, def, flags) < 0) + goto cleanup; + + if (!(new_def = virNodeDeviceDefParse(xmlDesc, NULL, EXISTING_DEVICE, virt_type, + &driver->parserCallbacks, NULL, true))) + goto cleanup; + + if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV) && + nodeDeviceHasCapability(new_def, VIR_NODE_DEV_CAP_MDEV)) { + // Checks flags are valid for the state and sets flags for current if flags not set + if (virNodeDeviceObjUpdateModificationImpact(obj, &flags) < 0) + goto cleanup; + + // Compare def and new_def for compatibility e.g. parent, type and uuid + if (nodeDeviceDefValidateUpdate(def, new_def, + (flags & VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE)) < 0) + goto cleanup; + + // Update now + VIR_DEBUG("Update node device '%s' with mdevctl", def->name); + if (virMdevctlModify(new_def, + (flags & VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG), + (flags & VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE)) < 0) { + goto cleanup; + }; + // Detect updates and also trigger events + updated = true; + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unsupported device type")); + goto cleanup; + } + + ret = 0; + cleanup: + virNodeDeviceObjEndAPI(&obj); + if (updated) + nodeDeviceUpdateMediatedDevices(); + + return ret; +} diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -XXX,XX +XXX,XX @@ typedef enum { * separation makes our code more readable in terms of knowing when we're * starting a defined device and when we're creating a transient one */ MDEVCTL_CMD_CREATE, + MDEVCTL_CMD_MODIFY, MDEVCTL_CMD_LAST, } virMdevctlCommand; @@ -XXX,XX +XXX,XX @@ virCommand* nodeDeviceGetMdevctlSetAutostartCommand(virNodeDeviceDef *def, bool autostart, char **errmsg); + +virCommand* +nodeDeviceGetMdevctlModifyCommand(virNodeDeviceDef *def, + bool defined, + bool live, + char **errmsg); +int +nodeDeviceUpdate(virNodeDevice *dev, + const char *xmlDesc, + unsigned int flags); diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -XXX,XX +XXX,XX @@ static virNodeDeviceDriver udevNodeDeviceDriver = { .nodeDeviceGetAutostart = nodeDeviceGetAutostart, /* 7.8.0 */ .nodeDeviceIsPersistent = nodeDeviceIsPersistent, /* 7.8.0 */ .nodeDeviceIsActive = nodeDeviceIsActive, /* 7.8.0 */ + .nodeDeviceUpdate = nodeDeviceUpdate, /* 10.1.0 */ }; diff --git a/tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml b/tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <path>/sys/devices/css0/0.0.0052/c60cc60c-c60c-c60c-c60c-c60cc60cc60c</path> + <parent>css_0_0_0052</parent> + <driver> + <name>vfio_ccw_mdev</name> + </driver> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <parent_addr>0.0.0052</parent_addr> + <attr name='add_attr_1' value='val1'/> + <attr name='add_attr_2' value='val2'/> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevmdevctldata/mdevctl-modify.argv b/tests/nodedevmdevctldata/mdevctl-modify.argv new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevmdevctldata/mdevctl-modify.argv @@ -XXX,XX +XXX,XX @@ +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--defined +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--live +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--live +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--defined \ +--live diff --git a/tests/nodedevmdevctldata/mdevctl-modify.json b/tests/nodedevmdevctldata/mdevctl-modify.json new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevmdevctldata/mdevctl-modify.json @@ -XXX,XX +XXX,XX @@ +{"mdev_type":"vfio_ccw-io","start":"manual"} +{"mdev_type":"vfio_ccw-io","start":"manual","attrs":[{"add_attr_1":"val1"},{"add_attr_2":"val2"}]} +{"mdev_type":"vfio_ccw-io","start":"manual"} +{"mdev_type":"vfio_ccw-io","start":"manual","attrs":[{"add_attr_1":"val1"},{"add_attr_2":"val2"}]} diff --git a/tests/nodedevmdevctltest.c b/tests/nodedevmdevctltest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/nodedevmdevctltest.c +++ b/tests/nodedevmdevctltest.c @@ -XXX,XX +XXX,XX @@ testCommandDryRunCallback(const char *const*args G_GNUC_UNUSED, { char **stdinbuf = opaque; - *stdinbuf = g_strdup(input); + if (*stdinbuf) + *stdinbuf = g_strconcat(*stdinbuf, "\n", input, NULL); + else + *stdinbuf = g_strdup(input); } typedef virCommand * (*MdevctlCmdFunc)(virNodeDeviceDef *, char **, char **); @@ -XXX,XX +XXX,XX @@ testMdevctlCmd(virMdevctlCommand cmd_type, case MDEVCTL_CMD_START: case MDEVCTL_CMD_STOP: case MDEVCTL_CMD_UNDEFINE: + case MDEVCTL_CMD_MODIFY: create = EXISTING_DEVICE; break; case MDEVCTL_CMD_LAST: @@ -XXX,XX +XXX,XX @@ testMdevctlAutostart(const void *data G_GNUC_UNUSED) return ret; } + +static int +testMdevctlModify(const void *data G_GNUC_UNUSED) +{ + g_autoptr(virNodeDeviceDef) def = NULL; + g_autoptr(virNodeDeviceDef) def_update = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + const char *actualCmdline = NULL; + int ret = -1; + g_autoptr(virCommand) definedcmd = NULL; + g_autoptr(virCommand) livecmd = NULL; + g_autoptr(virCommand) bothcmd = NULL; + g_autofree char *errmsg = NULL; + g_autofree char *stdinbuf = NULL; + g_autofree char *mdevxml = + g_strdup_printf("%s/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml", + abs_srcdir); + g_autofree char *mdevxml_update = + g_strdup_printf("%s/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml", + abs_srcdir); + /* just concatenate both calls into the same output files */ + g_autofree char *cmdlinefile = + g_strdup_printf("%s/nodedevmdevctldata/mdevctl-modify.argv", + abs_srcdir); + g_autofree char *jsonfile = + g_strdup_printf("%s/nodedevmdevctldata/mdevctl-modify.json", + abs_srcdir); + g_autoptr(virCommandDryRunToken) dryRunToken = virCommandDryRunTokenNew(); + + if (!(def = virNodeDeviceDefParse(NULL, mdevxml, CREATE_DEVICE, VIRT_TYPE, + &parser_callbacks, NULL, false))) + return -1; + + virCommandSetDryRun(dryRunToken, &buf, true, true, testCommandDryRunCallback, &stdinbuf); + + if (!(definedcmd = nodeDeviceGetMdevctlModifyCommand(def, true, false, &errmsg))) + goto cleanup; + + if (virCommandRun(definedcmd, NULL) < 0) + goto cleanup; + + if (!(def_update = virNodeDeviceDefParse(NULL, mdevxml_update, EXISTING_DEVICE, VIRT_TYPE, + &parser_callbacks, NULL, false))) + goto cleanup; + + if (!(livecmd = nodeDeviceGetMdevctlModifyCommand(def_update, false, true, &errmsg))) + goto cleanup; + + if (virCommandRun(livecmd, NULL) < 0) + goto cleanup; + + if (!(livecmd = nodeDeviceGetMdevctlModifyCommand(def, false, true, &errmsg))) + goto cleanup; + + if (virCommandRun(livecmd, NULL) < 0) + goto cleanup; + + if (!(bothcmd = nodeDeviceGetMdevctlModifyCommand(def_update, true, true, &errmsg))) + goto cleanup; + + if (virCommandRun(bothcmd, NULL) < 0) + goto cleanup; + + if (!(actualCmdline = virBufferCurrentContent(&buf))) + goto cleanup; + + if (virTestCompareToFileFull(actualCmdline, cmdlinefile, false) < 0) + goto cleanup; + + if (virTestCompareToFile(stdinbuf, jsonfile) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&buf); + return ret; +} + static int testMdevctlListDefined(const void *data G_GNUC_UNUSED) { @@ -XXX,XX +XXX,XX @@ mymain(void) #define DO_TEST_AUTOSTART() \ DO_TEST_FULL("autostart mdevs", testMdevctlAutostart, NULL) +#define DO_TEST_MODIFY() \ + DO_TEST_FULL("modify mdevs", testMdevctlModify, NULL) + #define DO_TEST_PARSE_JSON(filename) \ DO_TEST_FULL("parse mdevctl json " filename, testMdevctlParse, filename) @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST_AUTOSTART(); + DO_TEST_MODIFY(); + done: nodedevTestDriverFree(driver); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Add ability to update node devices. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- docs/drvnodedev.rst | 4 +- docs/manpages/virsh.rst | 19 ++++++++ tools/virsh-nodedev.c | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/docs/drvnodedev.rst b/docs/drvnodedev.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/drvnodedev.rst +++ b/docs/drvnodedev.rst @@ -XXX,XX +XXX,XX @@ NPIV) <https://wiki.libvirt.org/page/NPIV_in_libvirt>`__). Persistent virtual devices are managed with ``virsh nodedev-define`` and ``virsh nodedev-undefine``. Persistent devices can be configured to start manually or automatically using ``virsh nodedev-autostart``. Inactive devices -can be made active with ``virsh nodedev-start``. +can be made active with ``virsh nodedev-start``. ``virsh nodedev-update`` +allows to modify devices (:since:`Since 10.1.0`). Transient virtual devices are started and stopped with the commands ``virsh nodedev-create`` and ``virsh nodedev-destroy``. @@ -XXX,XX +XXX,XX @@ covers the following features: - display device details ( :since:`Since 3.4.0` ) - create transient mediated devices ( :since:`Since 6.5.0` ) - define persistent mediated devices ( :since:`Since 7.3.0` ) +- update mediated devices ( :since:`Since 10.1.0` ) Because mediated devices are instantiated from vendor specific templates, simply called 'types', information describing these types is contained within the diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ If *--validate* is specified, validates the format of the XML document against an internal RNG schema. +nodedev-update +-------------- + +**Syntax:** + +:: + + nodedev-update device FILE [[--live] [--config] | [--current]] + +Update a device on the host. *device* can be either device name or wwn pair +in "wwnn,wwpn" format (only works for vHBA currently). *file* +contains xml for a top-level <device> description of the node device. +*--current* can be either or both of *live* and *config*, depends on +the hypervisor's implementation. +Both *--live* and *--config* flags may be given, but *--current* is +exclusive. If no flag is specified, behavior is different depending +on hypervisor. + + nodedev-destroy --------------- diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceInfo(vshControl *ctl, const vshCmd *cmd) } +/* + * "nodedev-update" command + */ +static const vshCmdInfo info_node_device_update[] = { + {.name = "help", + .data = N_("Update a active and/or inactive node device") + }, + {.name = "desc", + .data = N_("Updates the configuration of a node device") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_node_device_update[] = { + {.name = "device", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), + .completer = virshNodeDeviceNameCompleter, + }, + VIRSH_COMMON_OPT_FILE(N_("file containing an XML description " + "of the device")), + VIRSH_COMMON_OPT_CONFIG(N_("affect next node device startup")), + VIRSH_COMMON_OPT_LIVE(N_("affect running node device")), + VIRSH_COMMON_OPT_CURRENT(N_("affect current state of node device")), + {.name = NULL} +}; + +static bool +cmdNodeDeviceUpdate(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + g_autoptr(virshNodeDevice) device = NULL; + const char *device_value = NULL; + const char *from = NULL; + g_autofree char *xml = NULL; + bool config = vshCommandOptBool(cmd, "config"); + bool live = vshCommandOptBool(cmd, "live"); + unsigned int flags = VIR_NODE_DEVICE_UPDATE_AFFECT_CURRENT; + + VSH_EXCLUSIVE_OPTIONS("current", "live"); + VSH_EXCLUSIVE_OPTIONS("current", "config"); + + if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0) + return false; + + device = vshFindNodeDevice(ctl, device_value); + + if (!device) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + goto cleanup; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &xml) < 0) + goto cleanup; + + if (config) + flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG; + if (live) + flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE; + + if (virNodeDeviceUpdate(device, xml, flags) < 0) { + vshError(ctl, _("Failed to update node device %1$s from '%2$s'"), + virNodeDeviceGetName(device), from); + goto cleanup; + } + + if (config) { + if (live) + vshPrintExtra(ctl, _("Updated node device %1$s persistent config and live state"), + virNodeDeviceGetName(device)); + else + vshPrintExtra(ctl, _("Updated node device %1$s persistent config"), + virNodeDeviceGetName(device)); + } else if (live) { + vshPrintExtra(ctl, _("Updated node device %1$s live state"), + virNodeDeviceGetName(device)); + } else if (virNodeDeviceIsActive(device)) { + vshPrintExtra(ctl, _("Updated node device %1$s live state"), + virNodeDeviceGetName(device)); + } else { + vshPrintExtra(ctl, _("Updated node device %1$s persistent config"), + virNodeDeviceGetName(device)); + } + + ret = true; + cleanup: + vshReportError(ctl); + return ret; +} + const vshCmdDef nodedevCmds[] = { {.name = "nodedev-create", @@ -XXX,XX +XXX,XX @@ const vshCmdDef nodedevCmds[] = { .info = info_node_device_info, .flags = 0 }, + {.name = "nodedev-update", + .handler = cmdNodeDeviceUpdate, + .opts = opts_node_device_update, + .info = info_node_device_update, + .flags = 0 + }, {.name = NULL} }; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Allow to modify a node device by using virNodeDeviceDefineXML() to align its behavior with other drivers define methods. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- NEWS.rst | 5 +++ src/libvirt-nodedev.c | 4 +- src/node_device/node_device_driver.c | 64 ++++++++++++++++++++++------ tools/virsh-nodedev.c | 8 ++-- 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index XXXXXXX..XXXXXXX 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -XXX,XX +XXX,XX @@ v10.1.0 (unreleased) * **Improvements** +* nodedev: Add ability to update persistent mediated devices by defining them + + Existing persistent mediated devices can now also be updated by + ``virNodeDeviceDefineXML()`` as long as parent and UUID remain unchanged. + * **Bug fixes** * qemu_process: Skip over non-virtio non-TAP NIC models when refreshing rx-filter diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceDestroy(virNodeDevicePtr dev) * @xmlDesc: string containing an XML description of the device to be defined * @flags: bitwise-OR of supported virNodeDeviceDefineXMLFlags * - * Define a new device on the VM host machine, for example, a mediated device + * Define a new inactive persistent device or modify an existing persistent + * one from the XML description on the VM host machine, for example, a mediated + * device. * * virNodeDeviceFree should be used to free the resources after the * node device object is no longer needed. diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceUpdateMediatedDevice(virNodeDeviceDef *def, } +static virNodeDeviceObj* +findPersistentMdevNodeDevice(virNodeDeviceDef *def) +{ + virNodeDeviceObj *obj = NULL; + + if (!nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV) && !def->parent) + return NULL; + + if (def->caps->data.mdev.uuid && def->caps->data.mdev.parent_addr) { + mdevGenerateDeviceName(def); + if ((obj = nodeDeviceObjFindByName(def->name)) && + virNodeDeviceObjIsPersistent(obj)) + return obj; + } + + return NULL; +} + + virNodeDevice* nodeDeviceDefineXML(virConnect *conn, const char *xmlDesc, unsigned int flags) { g_autoptr(virNodeDeviceDef) def = NULL; + virNodeDevicePtr new_nodedev = NULL; + virNodeDeviceObj *persistent_obj = NULL; const char *virt_type = NULL; g_autofree char *uuid = NULL; g_autofree char *name = NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceDefineXML(virConnect *conn, &driver->parserCallbacks, NULL, validate))) return NULL; + persistent_obj = findPersistentMdevNodeDevice(def); + if (virNodeDeviceDefineXMLEnsureACL(conn, def) < 0) - return NULL; + goto cleanup; if (!nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Unsupported device type")); - return NULL; + goto cleanup; } if (!def->parent) { virReportError(VIR_ERR_XML_ERROR, "%s", _("cannot define a mediated device without a parent")); - return NULL; + goto cleanup; } - if (virMdevctlDefine(def, &uuid) < 0) { - return NULL; - } + if (persistent_obj) { + // virNodeDeviceObjUpdateModificationImpact() is not required we will + // modify the persitent config only. + // nodeDeviceDefValidateUpdate() is not required as uuid and parent are + // machting if def was found and changing the type in the persistent + // config is allowed. + VIR_DEBUG("Update node device '%s' with mdevctl", def->name); + if (virMdevctlModify(def, true, false) < 0) + goto cleanup; - if (uuid && uuid[0]) { - g_free(def->caps->data.mdev.uuid); - def->caps->data.mdev.uuid = g_steal_pointer(&uuid); + virNodeDeviceObjEndAPI(&persistent_obj); + } else { + VIR_DEBUG("Define node device '%s' with mdevctl", def->name); + if (virMdevctlDefine(def, &uuid) < 0) + goto cleanup; + + if (uuid && uuid[0]) { + g_free(def->caps->data.mdev.uuid); + def->caps->data.mdev.uuid = g_steal_pointer(&uuid); + } } mdevGenerateDeviceName(def); @@ -XXX,XX +XXX,XX @@ nodeDeviceDefineXML(virConnect *conn, * add the provisional device to the list and return it immediately and * avoid this long delay. */ if (nodeDeviceUpdateMediatedDevice(g_steal_pointer(&def), true) < 0) - return NULL; + goto cleanup; + + new_nodedev = virGetNodeDevice(conn, name); - return virGetNodeDevice(conn, name); + cleanup: + virNodeDeviceObjEndAPI(&persistent_obj); + return new_nodedev; } @@ -XXX,XX +XXX,XX @@ nodeDeviceDefValidateUpdate(virNodeDeviceDef *def, cap_mdev->uuid); return -1; } - + /* A live update cannot change the mdev type. Since the new config is * stored in defined_config, compare that to the mdev type of the current * live config to make sure they match */ diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceUndefine(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) */ static const vshCmdInfo info_node_device_define[] = { {.name = "help", - .data = N_("Define a device by an xml file on a node") + .data = N_("Define or modify a device by an xml file on a node") }, {.name = "desc", - .data = N_("Defines a persistent device on the node that can be " - "assigned to a domain. The device must be started before " - "it can be assigned to a domain.") + .data = N_("Defines or modifies a persistent device on the node that " + "can be assigned to a domain. The device must be started " + "before it can be assigned to a domain.") }, {.name = NULL} }; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
The series adds a dual state to the mdev node devices as these objects can be active and defined at the same time. These two states can become different. To be able to also introspect the persistent and transient nodedevs filtering is added. To be able to also dump the XML of an inactive state while the node device is active a new option is added. The last four patches add the capability to update a mdev node device. This can be done on the persistent configuration, on the active configuration or on both. To support this v1.3.0 of mdevctl is required. nodeDeviceDefineXML() does now support modifying a persistent configuration. Changes since v4: * reworked findPersistentMdevNodeDevice() * changed the way the split into the modify path and the cleanup/unlocking is done in nodeDeviceDefineXML() Changes since v3: * replaced in all patches occurrences of persisted with persistent Changes since v2: * made error messages in virNodeDeviceObjUpdateModificationImpact() device type agnostic * renamed virNodeDeviceUpdateXML* into virNodeDeviceUpdate* * renamed nodeDeviceDefCompareMdevs() into nodeDeviceDefValidateUpdate() * renamed multiple local variable names * removed method for config cloning by commenting cross config compare in nodeDeviceDefValidateUpdate() * changed nodeDeviceDefineXML() to modify an existing persistent configuration Changes since v1: * replaced spec file requirement for v1.3.0 of mdevctl by a dynamic support check and an unsupported message if not available * renamed persisted and persist into persistent * removed persistent precheck in virsh * addressed all other review comments made on v1 * added NEWS Boris Fiuczynski (12): virmdev: prepare type and attributes for dual state node_device: refactor mdev attributes handling node_device: remove unnecessary checks in virNodeDeviceDefFormat nodedev: add an active config to mdev tools: add option inactive to nodedev-dumpxml nodedev: add persistent and transient filter on list tools: add switches persistent and transient to nodedev-list virsh: doc fix on nodedev-list api: add virNodeDeviceUpdate() nodedev: Implement virNodeDeviceUpdate virsh: add nodedev-update nodedev: allow modify on define of a persistent node device NEWS.rst | 12 + docs/drvnodedev.rst | 4 +- docs/manpages/virsh.rst | 36 +- include/libvirt/libvirt-nodedev.h | 31 ++ libvirt.spec.in | 1 + src/access/viraccessperm.c | 1 + src/access/viraccessperm.h | 6 + src/conf/node_device_conf.c | 76 +-- src/conf/node_device_conf.h | 14 +- src/conf/virnodedeviceobj.c | 50 ++ src/conf/virnodedeviceobj.h | 3 + src/driver-nodedev.h | 6 + src/libvirt-nodedev.c | 51 +- src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 + src/node_device/node_device_driver.c | 474 ++++++++++++++---- src/node_device/node_device_driver.h | 17 +- src/node_device/node_device_udev.c | 5 +- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 17 +- src/remote_protocol-structs | 6 + src/test/test_driver.c | 6 +- src/util/virmdev.h | 6 + ...60c_c60c_c60c_c60c_c60cc60cc60c_update.xml | 16 + tests/nodedevmdevctldata/mdevctl-modify.argv | 25 + tests/nodedevmdevctldata/mdevctl-modify.json | 4 + tests/nodedevmdevctltest.c | 94 +++- ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 14 + ...d_b7f0_4fea_b468_f1da537d301b_inactive.xml | 1 + ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 10 + ...c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml | 9 + ...9_36ea_4111_8f0a_8c9a70e21366_inactive.xml | 1 + ...9_495e_4243_ad9f_beb3f14c23d9_inactive.xml | 1 + ...4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml | 8 + ...6_1ca8_49ac_b176_871d16c13076_inactive.xml | 1 + tests/nodedevxml2xmltest.c | 59 ++- tools/virsh-nodedev.c | 140 +++++- 37 files changed, 1057 insertions(+), 155 deletions(-) create mode 100644 tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.argv create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.json create mode 100644 tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 120000 tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Create a new structure holding type and attributes as these are modifiable in a persistent mdev configuration and run out of sync with the active mdev configuration. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- src/conf/node_device_conf.c | 18 +++---- src/conf/node_device_conf.h | 4 +- src/node_device/node_device_driver.c | 70 ++++++++++++++-------------- src/node_device/node_device_udev.c | 2 +- src/util/virmdev.h | 6 +++ 5 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapMdevDefFormat(virBuffer *buf, { size_t i; - virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.type); + virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.dev_config.type); virBufferEscapeString(buf, "<uuid>%s</uuid>\n", data->mdev.uuid); virBufferEscapeString(buf, "<parent_addr>%s</parent_addr>\n", data->mdev.parent_addr); virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n", data->mdev.iommuGroupNumber); - for (i = 0; i < data->mdev.nattributes; i++) { - virMediatedDeviceAttr *attr = data->mdev.attributes[i]; + for (i = 0; i < data->mdev.dev_config.nattributes; i++) { + virMediatedDeviceAttr *attr = data->mdev.dev_config.attributes[i]; virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n", attr->name, attr->value); } @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt, return -1; } - VIR_APPEND_ELEMENT(mdev->attributes, mdev->nattributes, attr); + VIR_APPEND_ELEMENT(mdev->dev_config.attributes, mdev->dev_config.nattributes, attr); return 0; } @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, ctxt->node = node; - if (!(mdev->type = virXPathString("string(./type[1]/@id)", ctxt))) { + if (!(mdev->dev_config.type = virXPathString("string(./type[1]/@id)", ctxt))) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("missing type id attribute for '%1$s'"), def->name); return -1; @@ -XXX,XX +XXX,XX @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps) g_free(data->sg.path); break; case VIR_NODE_DEV_CAP_MDEV: - g_free(data->mdev.type); + g_free(data->mdev.dev_config.type); g_free(data->mdev.uuid); - for (i = 0; i < data->mdev.nattributes; i++) - virMediatedDeviceAttrFree(data->mdev.attributes[i]); - g_free(data->mdev.attributes); + for (i = 0; i < data->mdev.dev_config.nattributes; i++) + virMediatedDeviceAttrFree(data->mdev.dev_config.attributes[i]); + g_free(data->mdev.dev_config.attributes); g_free(data->mdev.parent_addr); break; case VIR_NODE_DEV_CAP_CSS_DEV: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -XXX,XX +XXX,XX @@ struct _virNodeDevCapSystem { typedef struct _virNodeDevCapMdev virNodeDevCapMdev; struct _virNodeDevCapMdev { - char *type; unsigned int iommuGroupNumber; char *uuid; - virMediatedDeviceAttr **attributes; - size_t nattributes; + virMediatedDeviceConfig dev_config; char *parent_addr; bool autostart; }; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) g_autoptr(virJSONValue) json = virJSONValueNewObject(); const char *startval = mdev->autostart ? "auto" : "manual"; - if (virJSONValueObjectAppendString(json, "mdev_type", mdev->type) < 0) + if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) return -1; if (virJSONValueObjectAppendString(json, "start", startval) < 0) return -1; - if (mdev->attributes) { + if (mdev->dev_config.attributes) { g_autoptr(virJSONValue) attributes = virJSONValueNewArray(); - for (i = 0; i < mdev->nattributes; i++) { - virMediatedDeviceAttr *attr = mdev->attributes[i]; + for (i = 0; i < mdev->dev_config.nattributes; i++) { + virMediatedDeviceAttr *attr = mdev->dev_config.attributes[i]; g_autoptr(virJSONValue) jsonattr = virJSONValueNewObject(); if (virJSONValueObjectAppendString(jsonattr, attr->name, attr->value) < 0) @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, mdev = &child->caps->data.mdev; mdev->uuid = g_strdup(uuid); mdev->parent_addr = g_strdup(parent); - mdev->type = + mdev->dev_config.type = g_strdup(virJSONValueObjectGetString(props, "mdev_type")); start = virJSONValueObjectGetString(props, "start"); mdev->autostart = STREQ_NULLABLE(start, "auto"); @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, size_t i; int nattrs = virJSONValueArraySize(attrs); - mdev->attributes = g_new0(virMediatedDeviceAttr*, nattrs); - mdev->nattributes = nattrs; + mdev->dev_config.attributes = g_new0(virMediatedDeviceAttr*, nattrs); + mdev->dev_config.nattributes = nattrs; for (i = 0; i < nattrs; i++) { virJSONValue *attr = virJSONValueArrayGet(attrs, i); @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0)); value = virJSONValueObjectGetValue(attr, 0); attribute->value = g_strdup(virJSONValueGetString(value)); - mdev->attributes[i] = attribute; + mdev->dev_config.attributes[i] = attribute; } } mdevGenerateDeviceName(child); @@ -XXX,XX +XXX,XX @@ nodeDeviceUpdateMediatedDevices(void) /* returns true if any attributes were copied, else returns false */ static bool -virMediatedDeviceAttrsCopy(virNodeDevCapMdev *dst, - virNodeDevCapMdev *src) +virMediatedDeviceAttrsCopy(virMediatedDeviceConfig *dst_config, + virMediatedDeviceConfig *src_config) { bool ret = false; size_t i; - if (src->nattributes != dst->nattributes) { + if (src_config->nattributes != dst_config->nattributes) { ret = true; - for (i = 0; i < dst->nattributes; i++) - virMediatedDeviceAttrFree(dst->attributes[i]); - g_free(dst->attributes); - - dst->nattributes = src->nattributes; - dst->attributes = g_new0(virMediatedDeviceAttr*, - src->nattributes); - for (i = 0; i < dst->nattributes; i++) - dst->attributes[i] = virMediatedDeviceAttrNew(); + for (i = 0; i < dst_config->nattributes; i++) + virMediatedDeviceAttrFree(dst_config->attributes[i]); + g_free(dst_config->attributes); + + dst_config->nattributes = src_config->nattributes; + dst_config->attributes = g_new0(virMediatedDeviceAttr*, + src_config->nattributes); + for (i = 0; i < dst_config->nattributes; i++) + dst_config->attributes[i] = virMediatedDeviceAttrNew(); } - for (i = 0; i < src->nattributes; i++) { - if (STRNEQ_NULLABLE(src->attributes[i]->name, - dst->attributes[i]->name)) { + for (i = 0; i < src_config->nattributes; i++) { + if (STRNEQ_NULLABLE(src_config->attributes[i]->name, + dst_config->attributes[i]->name)) { ret = true; - g_free(dst->attributes[i]->name); - dst->attributes[i]->name = - g_strdup(src->attributes[i]->name); + g_free(dst_config->attributes[i]->name); + dst_config->attributes[i]->name = + g_strdup(src_config->attributes[i]->name); } - if (STRNEQ_NULLABLE(src->attributes[i]->value, - dst->attributes[i]->value)) { + if (STRNEQ_NULLABLE(src_config->attributes[i]->value, + dst_config->attributes[i]->value)) { ret = true; - g_free(dst->attributes[i]->value); - dst->attributes[i]->value = - g_strdup(src->attributes[i]->value); + g_free(dst_config->attributes[i]->value); + dst_config->attributes[i]->value = + g_strdup(src_config->attributes[i]->value); } } @@ -XXX,XX +XXX,XX @@ nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, virNodeDevCapMdev *srcmdev = &src->caps->data.mdev; virNodeDevCapMdev *dstmdev = &dst->caps->data.mdev; - if (STRNEQ_NULLABLE(dstmdev->type, srcmdev->type)) { + if (STRNEQ_NULLABLE(dstmdev->dev_config.type, srcmdev->dev_config.type)) { ret = true; - g_free(dstmdev->type); - dstmdev->type = g_strdup(srcmdev->type); + g_free(dstmdev->dev_config.type); + dstmdev->dev_config.type = g_strdup(srcmdev->dev_config.type); } if (STRNEQ_NULLABLE(dstmdev->uuid, srcmdev->uuid)) { @@ -XXX,XX +XXX,XX @@ nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, dstmdev->uuid = g_strdup(srcmdev->uuid); } - if (virMediatedDeviceAttrsCopy(dstmdev, srcmdev)) + if (virMediatedDeviceAttrsCopy(&dstmdev->dev_config, &srcmdev->dev_config)) ret = true; if (dstmdev->autostart != srcmdev->autostart) { diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -XXX,XX +XXX,XX @@ udevProcessMediatedDevice(struct udev_device *dev, return -1; } - data->type = g_path_get_basename(canonicalpath); + data->dev_config.type = g_path_get_basename(canonicalpath); data->uuid = g_strdup(udev_device_get_sysname(dev)); if ((iommugrp = virMediatedDeviceGetIOMMUGroupNum(data->uuid)) < 0) diff --git a/src/util/virmdev.h b/src/util/virmdev.h index XXXXXXX..XXXXXXX 100644 --- a/src/util/virmdev.h +++ b/src/util/virmdev.h @@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceAttr, virMediatedDeviceAttrFree); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceList, virObjectUnref); +typedef struct _virMediatedDeviceConfig virMediatedDeviceConfig; +struct _virMediatedDeviceConfig { + char *type; + virMediatedDeviceAttr **attributes; + size_t nattributes; +}; typedef struct _virMediatedDeviceType virMediatedDeviceType; struct _virMediatedDeviceType { -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Refactor attribute handling code into methods for easier reuse. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- src/conf/node_device_conf.c | 27 ++++--- src/node_device/node_device_driver.c | 104 ++++++++++++++++----------- 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapStorageDefFormat(virBuffer *buf, } static void -virNodeDeviceCapMdevDefFormat(virBuffer *buf, - const virNodeDevCapData *data) +virNodeDeviceCapMdevAttrFormat(virBuffer *buf, + const virMediatedDeviceConfig *config) { size_t i; + for (i = 0; i < config->nattributes; i++) { + virMediatedDeviceAttr *attr = config->attributes[i]; + virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n", + attr->name, attr->value); + } +} + +static void +virNodeDeviceCapMdevDefFormat(virBuffer *buf, + const virNodeDevCapData *data) +{ virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.dev_config.type); virBufferEscapeString(buf, "<uuid>%s</uuid>\n", data->mdev.uuid); virBufferEscapeString(buf, "<parent_addr>%s</parent_addr>\n", @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapMdevDefFormat(virBuffer *buf, virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n", data->mdev.iommuGroupNumber); - for (i = 0; i < data->mdev.dev_config.nattributes; i++) { - virMediatedDeviceAttr *attr = data->mdev.dev_config.attributes[i]; - virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n", - attr->name, attr->value); - } + virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.dev_config); } static void @@ -XXX,XX +XXX,XX @@ virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt, static int virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt, xmlNodePtr node, - virNodeDevCapMdev *mdev) + virMediatedDeviceConfig *config) { VIR_XPATH_NODE_AUTORESTORE(ctxt) g_autoptr(virMediatedDeviceAttr) attr = virMediatedDeviceAttrNew(); @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt, return -1; } - VIR_APPEND_ELEMENT(mdev->dev_config.attributes, mdev->dev_config.nattributes, attr); + VIR_APPEND_ELEMENT(config->attributes, config->nattributes, attr); return 0; } @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, return -1; for (i = 0; i < nattrs; i++) - virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], mdev); + virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->dev_config); return 0; } diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceHasCapability(virNodeDeviceDef *def, virNodeDevCapType type) } -/* format a json string that provides configuration information about this mdev - * to the mdevctl utility */ static int -nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) +nodeDeviceAttributesToJSON(virJSONValue *json, + virMediatedDeviceConfig *config) { size_t i; - virNodeDevCapMdev *mdev = &def->caps->data.mdev; - g_autoptr(virJSONValue) json = virJSONValueNewObject(); - const char *startval = mdev->autostart ? "auto" : "manual"; - - if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) - return -1; - - if (virJSONValueObjectAppendString(json, "start", startval) < 0) - return -1; - - if (mdev->dev_config.attributes) { + if (config->attributes) { g_autoptr(virJSONValue) attributes = virJSONValueNewArray(); - for (i = 0; i < mdev->dev_config.nattributes; i++) { - virMediatedDeviceAttr *attr = mdev->dev_config.attributes[i]; + for (i = 0; i < config->nattributes; i++) { + virMediatedDeviceAttr *attr = config->attributes[i]; g_autoptr(virJSONValue) jsonattr = virJSONValueNewObject(); if (virJSONValueObjectAppendString(jsonattr, attr->name, attr->value) < 0) @@ -XXX,XX +XXX,XX @@ nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) return -1; } + return 0; +} + + +/* format a json string that provides configuration information about this mdev + * to the mdevctl utility */ +static int +nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) +{ + virNodeDevCapMdev *mdev = &def->caps->data.mdev; + g_autoptr(virJSONValue) json = virJSONValueNewObject(); + const char *startval = mdev->autostart ? "auto" : "manual"; + + if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) + return -1; + + if (virJSONValueObjectAppendString(json, "start", startval) < 0) + return -1; + + if (nodeDeviceAttributesToJSON(json, &mdev->dev_config) < 0) + return -1; + *buf = virJSONValueToString(json, false); if (!*buf) return -1; @@ -XXX,XX +XXX,XX @@ matchDeviceAddress(virNodeDeviceObj *obj, } +static int +nodeDeviceParseMdevctlAttributes(virMediatedDeviceConfig *config, + virJSONValue *attrs) +{ + size_t i; + + if (attrs && virJSONValueIsArray(attrs)) { + int nattrs = virJSONValueArraySize(attrs); + + config->attributes = g_new0(virMediatedDeviceAttr*, nattrs); + config->nattributes = nattrs; + + for (i = 0; i < nattrs; i++) { + virJSONValue *attr = virJSONValueArrayGet(attrs, i); + virMediatedDeviceAttr *attribute; + virJSONValue *value; + + if (!virJSONValueIsObject(attr) || + virJSONValueObjectKeysNumber(attr) != 1) + return -1; + + attribute = g_new0(virMediatedDeviceAttr, 1); + attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0)); + value = virJSONValueObjectGetValue(attr, 0); + attribute->value = g_strdup(virJSONValueGetString(value)); + config->attributes[i] = attribute; + } + } + + return 0; +} + + static virNodeDeviceDef* nodeDeviceParseMdevctlChildDevice(const char *parent, virJSONValue *json) @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, virNodeDevCapMdev *mdev; const char *uuid; virJSONValue *props; - virJSONValue *attrs; g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1); virNodeDeviceObj *parent_obj; const char *start = NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, start = virJSONValueObjectGetString(props, "start"); mdev->autostart = STREQ_NULLABLE(start, "auto"); - attrs = virJSONValueObjectGet(props, "attrs"); - - if (attrs && virJSONValueIsArray(attrs)) { - size_t i; - int nattrs = virJSONValueArraySize(attrs); - - mdev->dev_config.attributes = g_new0(virMediatedDeviceAttr*, nattrs); - mdev->dev_config.nattributes = nattrs; - - for (i = 0; i < nattrs; i++) { - virJSONValue *attr = virJSONValueArrayGet(attrs, i); - virMediatedDeviceAttr *attribute; - virJSONValue *value; - - if (!virJSONValueIsObject(attr) || - virJSONValueObjectKeysNumber(attr) != 1) - return NULL; + if (nodeDeviceParseMdevctlAttributes(&mdev->dev_config, + virJSONValueObjectGet(props, "attrs")) < 0) + return NULL; - attribute = g_new0(virMediatedDeviceAttr, 1); - attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0)); - value = virJSONValueObjectGetValue(attr, 0); - attribute->value = g_strdup(virJSONValueGetString(value)); - mdev->dev_config.attributes[i] = attribute; - } - } mdevGenerateDeviceName(child); return g_steal_pointer(&child); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
virBufferEscapeString already contains the null check. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- src/conf/node_device_conf.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def) virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->name); virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path); - if (def->devnode) - virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", - def->devnode); + virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", + def->devnode); if (def->devlinks) { for (i = 0; def->devlinks[i]; i++) virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n", def->devlinks[i]); } - if (def->parent) - virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent); + virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent); if (def->driver) { virBufferAddLit(&buf, "<driver>\n"); virBufferAdjustIndent(&buf, 2); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
The configuration of a defined mdev can be modified after the mdev is started. The defined configuration and the active configuration can therefore run out of sync. Handle this by storing the modifiable data which is the mdev type and attributes in two separate active and defined configurations. mdevctl supports with callout scripts to do an attribute retrieval of started mdevs which is already implemented in libvirt. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- include/libvirt/libvirt-nodedev.h | 11 ++++ src/conf/node_device_conf.c | 53 ++++++++++------ src/conf/node_device_conf.h | 5 +- src/libvirt-nodedev.c | 2 +- src/node_device/node_device_driver.c | 61 +++++++++++++------ src/node_device/node_device_driver.h | 6 +- src/node_device/node_device_udev.c | 4 +- src/test/test_driver.c | 6 +- tests/nodedevmdevctltest.c | 4 +- ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 14 +++++ ...d_b7f0_4fea_b468_f1da537d301b_inactive.xml | 1 + ...v_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml | 10 +++ ...c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml | 9 +++ ...9_36ea_4111_8f0a_8c9a70e21366_inactive.xml | 1 + ...9_495e_4243_ad9f_beb3f14c23d9_inactive.xml | 1 + ...4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml | 8 +++ ...6_1ca8_49ac_b176_871d16c13076_inactive.xml | 1 + tests/nodedevxml2xmltest.c | 59 +++++++++++++++--- 18 files changed, 197 insertions(+), 59 deletions(-) create mode 100644 tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 120000 tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml create mode 100644 tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml create mode 100644 tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml create mode 120000 tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -XXX,XX +XXX,XX @@ int virNodeDeviceListCaps (virNodeDevicePtr dev, char **const names, int maxnames); +/** + * virNodeDeviceXMLFlags: + * + * Flags used to provide the state of the returned node device configuration. + * + * Since: 10.1.0 + */ +typedef enum { + VIR_NODE_DEVICE_XML_INACTIVE = 1 << 0, /* dump inactive device configuration (Since: 10.1.0) */ +} virNodeDeviceXMLFlags; + char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev, unsigned int flags); diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapMdevAttrFormat(virBuffer *buf, static void virNodeDeviceCapMdevDefFormat(virBuffer *buf, - const virNodeDevCapData *data) + const virNodeDevCapData *data, + bool defined) { - virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.dev_config.type); + if (defined) + virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.defined_config.type); + else + virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.active_config.type); virBufferEscapeString(buf, "<uuid>%s</uuid>\n", data->mdev.uuid); virBufferEscapeString(buf, "<parent_addr>%s</parent_addr>\n", data->mdev.parent_addr); virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n", data->mdev.iommuGroupNumber); - - virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.dev_config); + if (defined) + virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.defined_config); + else + virNodeDeviceCapMdevAttrFormat(buf, &data->mdev.active_config); } static void @@ -XXX,XX +XXX,XX @@ virNodeDeviceCapCSSDefFormat(virBuffer *buf, char * -virNodeDeviceDefFormat(const virNodeDeviceDef *def) +virNodeDeviceDefFormat(const virNodeDeviceDef *def, unsigned int flags) { g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; virNodeDevCapsDef *caps; size_t i = 0; + bool inactive_state = flags & VIR_NODE_DEVICE_XML_INACTIVE; virBufferAddLit(&buf, "<device>\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->name); - virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path); - virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", - def->devnode); - if (def->devlinks) { - for (i = 0; def->devlinks[i]; i++) - virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n", - def->devlinks[i]); + if (!inactive_state) { + virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path); + virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n", + def->devnode); + if (def->devlinks) { + for (i = 0; def->devlinks[i]; i++) + virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n", + def->devlinks[i]); + } } virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent); - if (def->driver) { + if (def->driver && !inactive_state) { virBufferAddLit(&buf, "<driver>\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->driver); @@ -XXX,XX +XXX,XX @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def) virBufferEscapeString(&buf, "<type>%s</type>\n", virNodeDevDRMTypeToString(data->drm.type)); break; case VIR_NODE_DEV_CAP_MDEV: - virNodeDeviceCapMdevDefFormat(&buf, data); + virNodeDeviceCapMdevDefFormat(&buf, data, inactive_state); break; case VIR_NODE_DEV_CAP_CCW_DEV: virNodeDeviceCapCCWDefFormat(&buf, data); @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, ctxt->node = node; - if (!(mdev->dev_config.type = virXPathString("string(./type[1]/@id)", ctxt))) { + if (!(mdev->defined_config.type = virXPathString("string(./type[1]/@id)", ctxt))) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("missing type id attribute for '%1$s'"), def->name); return -1; @@ -XXX,XX +XXX,XX @@ virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, return -1; for (i = 0; i < nattrs; i++) - virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->dev_config); + virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->defined_config); return 0; } @@ -XXX,XX +XXX,XX @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps) g_free(data->sg.path); break; case VIR_NODE_DEV_CAP_MDEV: - g_free(data->mdev.dev_config.type); + g_free(data->mdev.defined_config.type); + g_free(data->mdev.active_config.type); g_free(data->mdev.uuid); - for (i = 0; i < data->mdev.dev_config.nattributes; i++) - virMediatedDeviceAttrFree(data->mdev.dev_config.attributes[i]); - g_free(data->mdev.dev_config.attributes); + for (i = 0; i < data->mdev.defined_config.nattributes; i++) + virMediatedDeviceAttrFree(data->mdev.defined_config.attributes[i]); + g_free(data->mdev.defined_config.attributes); + for (i = 0; i < data->mdev.active_config.nattributes; i++) + virMediatedDeviceAttrFree(data->mdev.active_config.attributes[i]); + g_free(data->mdev.active_config.attributes); g_free(data->mdev.parent_addr); break; case VIR_NODE_DEV_CAP_CSS_DEV: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -XXX,XX +XXX,XX @@ typedef struct _virNodeDevCapMdev virNodeDevCapMdev; struct _virNodeDevCapMdev { unsigned int iommuGroupNumber; char *uuid; - virMediatedDeviceConfig dev_config; + virMediatedDeviceConfig defined_config; + virMediatedDeviceConfig active_config; char *parent_addr; bool autostart; }; @@ -XXX,XX +XXX,XX @@ struct _virNodeDeviceDef { }; char * -virNodeDeviceDefFormat(const virNodeDeviceDef *def); +virNodeDeviceDefFormat(const virNodeDeviceDef *def, unsigned int flags); typedef int (*virNodeDeviceDefPostParseCallback)(virNodeDeviceDef *dev, diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, /** * virNodeDeviceGetXMLDesc: * @dev: pointer to the node device - * @flags: extra flags; not used yet, so callers should always pass 0 + * @flags: bitwise-OR of virNodeDeviceXMLFlags * * Fetch an XML document describing all aspects of * the device. diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceGetXMLDesc(virNodeDevicePtr device, virNodeDeviceDef *def; char *ret = NULL; - virCheckFlags(0, NULL); + virCheckFlags(VIR_NODE_DEVICE_XML_INACTIVE, NULL); if (nodeDeviceInitWait() < 0) return NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceGetXMLDesc(virNodeDevicePtr device, if (virNodeDeviceUpdateCaps(def) < 0) goto cleanup; - ret = virNodeDeviceDefFormat(def); + if (flags & VIR_NODE_DEVICE_XML_INACTIVE) { + if (!virNodeDeviceObjIsPersistent(obj)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("node device '%1$s' is not persistent"), + def->name); + goto cleanup; + } + } else { + if (!virNodeDeviceObjIsActive(obj)) + flags |= VIR_NODE_DEVICE_XML_INACTIVE; + } + + ret = virNodeDeviceDefFormat(def, flags); cleanup: virNodeDeviceObjEndAPI(&obj); @@ -XXX,XX +XXX,XX @@ nodeDeviceAttributesToJSON(virJSONValue *json, /* format a json string that provides configuration information about this mdev * to the mdevctl utility */ static int -nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf) +nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf, bool defined) { virNodeDevCapMdev *mdev = &def->caps->data.mdev; + virMediatedDeviceConfig *mdev_config = defined ? &mdev->defined_config : &mdev->active_config; g_autoptr(virJSONValue) json = virJSONValueNewObject(); const char *startval = mdev->autostart ? "auto" : "manual"; - if (virJSONValueObjectAppendString(json, "mdev_type", mdev->dev_config.type) < 0) + if (virJSONValueObjectAppendString(json, "mdev_type", mdev_config->type) < 0) return -1; if (virJSONValueObjectAppendString(json, "start", startval) < 0) return -1; - if (nodeDeviceAttributesToJSON(json, &mdev->dev_config) < 0) + if (nodeDeviceAttributesToJSON(json, mdev_config) < 0) return -1; *buf = virJSONValueToString(json, false); @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, return NULL; } - if (nodeDeviceDefToMdevctlConfig(def, &inbuf) < 0) { + if (nodeDeviceDefToMdevctlConfig(def, &inbuf, true) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("couldn't convert node device def to mdevctl JSON")); return NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlAttributes(virMediatedDeviceConfig *config, static virNodeDeviceDef* nodeDeviceParseMdevctlChildDevice(const char *parent, - virJSONValue *json) + virJSONValue *json, + bool defined) { virNodeDevCapMdev *mdev; + virMediatedDeviceConfig *mdev_config; const char *uuid; virJSONValue *props; g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1); @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, child->caps->data.type = VIR_NODE_DEV_CAP_MDEV; mdev = &child->caps->data.mdev; + mdev_config = defined ? &mdev->defined_config : &mdev->active_config; mdev->uuid = g_strdup(uuid); mdev->parent_addr = g_strdup(parent); - mdev->dev_config.type = + mdev_config->type = g_strdup(virJSONValueObjectGetString(props, "mdev_type")); start = virJSONValueObjectGetString(props, "start"); mdev->autostart = STREQ_NULLABLE(start, "auto"); - if (nodeDeviceParseMdevctlAttributes(&mdev->dev_config, + if (nodeDeviceParseMdevctlAttributes(mdev_config, virJSONValueObjectGet(props, "attrs")) < 0) return NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlChildDevice(const char *parent, int nodeDeviceParseMdevctlJSON(const char *jsonstring, - virNodeDeviceDef ***devs) + virNodeDeviceDef ***devs, + bool defined) { int n; g_autoptr(virJSONValue) json_devicelist = NULL; @@ -XXX,XX +XXX,XX @@ nodeDeviceParseMdevctlJSON(const char *jsonstring, g_autoptr(virNodeDeviceDef) child = NULL; virJSONValue *child_obj = virJSONValueArrayGet(child_array, j); - if (!(child = nodeDeviceParseMdevctlChildDevice(parent, child_obj))) { + if (!(child = nodeDeviceParseMdevctlChildDevice(parent, child_obj, defined))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to parse child device")); goto error; @@ -XXX,XX +XXX,XX @@ nodeDeviceUpdateMediatedDevice(virNodeDeviceDef *def, /* Active devices contain some additional information (e.g. sysfs * path) that is not provided by mdevctl, so re-use the existing * definition and copy over new mdev data */ - changed = nodeDeviceDefCopyFromMdevctl(olddef, owned); + changed = nodeDeviceDefCopyFromMdevctl(olddef, owned, defined); if (was_defined && !changed) { /* if this device was already defined and the definition @@ -XXX,XX +XXX,XX @@ virMdevctlList(bool defined, return -1; } - return nodeDeviceParseMdevctlJSON(output, devs); + return nodeDeviceParseMdevctlJSON(output, devs, defined); } @@ -XXX,XX +XXX,XX @@ virMediatedDeviceAttrsCopy(virMediatedDeviceConfig *dst_config, * Returns true if anything was copied, else returns false */ bool nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, - virNodeDeviceDef *src) + virNodeDeviceDef *src, + bool defined) { bool ret = false; virNodeDevCapMdev *srcmdev = &src->caps->data.mdev; virNodeDevCapMdev *dstmdev = &dst->caps->data.mdev; + virMediatedDeviceConfig *srcmdevconfig = &src->caps->data.mdev.active_config; + virMediatedDeviceConfig *dstmdevconfig = &dst->caps->data.mdev.active_config; + + if (defined) { + srcmdevconfig = &src->caps->data.mdev.defined_config; + dstmdevconfig = &dst->caps->data.mdev.defined_config; + } - if (STRNEQ_NULLABLE(dstmdev->dev_config.type, srcmdev->dev_config.type)) { + if (STRNEQ_NULLABLE(dstmdevconfig->type, srcmdevconfig->type)) { ret = true; - g_free(dstmdev->dev_config.type); - dstmdev->dev_config.type = g_strdup(srcmdev->dev_config.type); + g_free(dstmdevconfig->type); + dstmdevconfig->type = g_strdup(srcmdevconfig->type); } if (STRNEQ_NULLABLE(dstmdev->uuid, srcmdev->uuid)) { @@ -XXX,XX +XXX,XX @@ nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, dstmdev->uuid = g_strdup(srcmdev->uuid); } - if (virMediatedDeviceAttrsCopy(&dstmdev->dev_config, &srcmdev->dev_config)) + if (virMediatedDeviceAttrsCopy(dstmdevconfig, srcmdevconfig)) ret = true; if (dstmdev->autostart != srcmdev->autostart) { diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlListCommand(bool defined, int nodeDeviceParseMdevctlJSON(const char *jsonstring, - virNodeDeviceDef ***devs); + virNodeDeviceDef ***devs, + bool defined); int nodeDeviceUpdateMediatedDevices(void); @@ -XXX,XX +XXX,XX @@ nodeDeviceGenerateName(virNodeDeviceDef *def, const char *s); bool nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst, - virNodeDeviceDef *src); + virNodeDeviceDef *src, + bool defined); int nodeDeviceCreate(virNodeDevice *dev, diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -XXX,XX +XXX,XX @@ udevProcessMediatedDevice(struct udev_device *dev, return -1; } - data->dev_config.type = g_path_get_basename(canonicalpath); + data->active_config.type = g_path_get_basename(canonicalpath); data->uuid = g_strdup(udev_device_get_sysname(dev)); if ((iommugrp = virMediatedDeviceGetIOMMUGroupNum(data->uuid)) < 0) @@ -XXX,XX +XXX,XX @@ udevAddOneDevice(struct udev_device *device) objdef = virNodeDeviceObjGetDef(obj); if (is_mdev) - nodeDeviceDefCopyFromMdevctl(def, objdef); + nodeDeviceDefCopyFromMdevctl(def, objdef, false); persistent = virNodeDeviceObjIsPersistent(obj); autostart = virNodeDeviceObjIsAutostart(obj); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -XXX,XX +XXX,XX @@ testNodeDeviceGetXMLDesc(virNodeDevicePtr dev, virNodeDeviceObj *obj; char *ret = NULL; - virCheckFlags(0, NULL); + virCheckFlags(VIR_NODE_DEVICE_XML_INACTIVE, NULL); if (!(obj = testNodeDeviceObjFindByName(driver, dev->name))) return NULL; - ret = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(obj)); + ret = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(obj), flags); virNodeDeviceObjEndAPI(&obj); return ret; @@ -XXX,XX +XXX,XX @@ testNodeDeviceMockCreateVport(testDriver *driver, "scsi_host11"))) goto cleanup; - xml = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(objcopy)); + xml = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(objcopy), 0); virNodeDeviceObjEndAPI(&objcopy); if (!xml) goto cleanup; diff --git a/tests/nodedevmdevctltest.c b/tests/nodedevmdevctltest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/nodedevmdevctltest.c +++ b/tests/nodedevmdevctltest.c @@ -XXX,XX +XXX,XX @@ testMdevctlParse(const void *data) return -1; } - if ((nmdevs = nodeDeviceParseMdevctlJSON(buf, &mdevs)) < 0) { + if ((nmdevs = nodeDeviceParseMdevctlJSON(buf, &mdevs, true)) < 0) { VIR_TEST_DEBUG("Unable to parse json for %s", filename); return -1; } for (i = 0; i < nmdevs; i++) { - g_autofree char *devxml = virNodeDeviceDefFormat(mdevs[i]); + g_autofree char *devxml = virNodeDeviceDefFormat(mdevs[i], VIR_NODE_DEVICE_XML_INACTIVE); if (!devxml) goto cleanup; virBufferAddStr(&xmloutbuf, devxml); diff --git a/tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml b/tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <path>/sys/devices/css0/0.0.0052/c60cc60c-c60c-c60c-c60c-c60cc60cc60c</path> + <parent>css_0_0_0052</parent> + <driver> + <name>vfio_ccw_mdev</name> + </driver> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <parent_addr>0.0.0052</parent_addr> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml b/tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_3627463d_b7f0_4fea_b468_f1da537d301b_inactive.xml @@ -0,0 +1 @@ +mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <path>/sys/devices/css0/0.0.0052/c60cc60c-c60c-c60c-c60c-c60cc60cc60c</path> + <parent>css_0_0_0052</parent> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_inactive.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <parent>css_0_0_0052</parent> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml b/tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_d069d019_36ea_4111_8f0a_8c9a70e21366_inactive.xml @@ -0,0 +1 @@ +mdev_d069d019_36ea_4111_8f0a_8c9a70e21366.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml b/tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9_inactive.xml @@ -0,0 +1 @@ +mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml b/tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad_inactive.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_ee0b88c4-f554-4dc1-809d-b2a01e8e48ad</name> + <parent>ap_matrix</parent> + <capability type='mdev'> + <type id='vfio_ap-passthrough'/> + <iommuGroup number='0'/> + </capability> +</device> diff --git a/tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml b/tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevxml2xmlout/mdev_fedc4916_1ca8_49ac_b176_871d16c13076_inactive.xml @@ -0,0 +1 @@ +mdev_fedc4916_1ca8_49ac_b176_871d16c13076.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/nodedevxml2xmltest.c +++ b/tests/nodedevxml2xmltest.c @@ -XXX,XX +XXX,XX @@ #define VIR_FROM_THIS VIR_FROM_NONE +struct TestData { + const char *filename; + unsigned int flags; +}; + static int -testCompareXMLToXMLFiles(const char *xml, const char *outfile) +testCompareXMLToXMLFiles(const char *xml, const char *outfile, unsigned int flags) { g_autofree char *xmlData = NULL; g_autofree char *actual = NULL; int ret = -1; virNodeDeviceDef *dev = NULL; virNodeDevCapsDef *caps; + size_t i; if (virTestLoadFile(xml, &xmlData) < 0) goto fail; @@ -XXX,XX +XXX,XX @@ testCompareXMLToXMLFiles(const char *xml, const char *outfile) data->storage.logical_block_size; } } + + if (caps->data.type == VIR_NODE_DEV_CAP_MDEV && + !(flags & VIR_NODE_DEVICE_XML_INACTIVE)) { + data->mdev.active_config.type = g_strdup(data->mdev.defined_config.type); + for (i = 0; i < data->mdev.defined_config.nattributes; i++) { + g_autoptr(virMediatedDeviceAttr) attr = g_new0(virMediatedDeviceAttr, 1); + attr->name = g_strdup(data->mdev.defined_config.attributes[i]->name); + attr->value = g_strdup(data->mdev.defined_config.attributes[i]->value); + VIR_APPEND_ELEMENT(data->mdev.active_config.attributes, + data->mdev.active_config.nattributes, + attr); + } + } } - if (!(actual = virNodeDeviceDefFormat(dev))) + if (!(actual = virNodeDeviceDefFormat(dev, flags))) goto fail; if (virTestCompareToFile(actual, outfile) < 0) @@ -XXX,XX +XXX,XX @@ static int testCompareXMLToXMLHelper(const void *data) { int result = -1; + const struct TestData *tdata = data; g_autofree char *xml = NULL; g_autofree char *outfile = NULL; xml = g_strdup_printf("%s/nodedevschemadata/%s.xml", abs_srcdir, - (const char *)data); + tdata->filename); - outfile = g_strdup_printf("%s/nodedevxml2xmlout/%s.xml", abs_srcdir, - (const char *)data); + if (tdata->flags & VIR_NODE_DEVICE_XML_INACTIVE) + outfile = g_strdup_printf("%s/nodedevxml2xmlout/%s_inactive.xml", abs_srcdir, + tdata->filename); + else + outfile = g_strdup_printf("%s/nodedevxml2xmlout/%s.xml", abs_srcdir, + tdata->filename); - result = testCompareXMLToXMLFiles(xml, outfile); + result = testCompareXMLToXMLFiles(xml, outfile, tdata->flags); return result; } @@ -XXX,XX +XXX,XX @@ mymain(void) { int ret = 0; +#define DO_TEST_FLAGS(desc, filename, flags) \ + do { \ + struct TestData data = { filename, flags }; \ + if (virTestRun(desc, testCompareXMLToXMLHelper, &data) < 0) \ + ret = -1; \ + } \ + while (0) + #define DO_TEST(name) \ - if (virTestRun("Node device XML-2-XML " name, \ - testCompareXMLToXMLHelper, (name)) < 0) \ - ret = -1 + DO_TEST_FLAGS("Node device XML-2-XML " name, name, 0) + +#define DO_TEST_INACTIVE(name) \ + DO_TEST_FLAGS("Node device XML-2-XML INACTIVE " name, \ + name, VIR_NODE_DEVICE_XML_INACTIVE) DO_TEST("computer"); DO_TEST("DVD_GCC_4247N"); @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST("pci_0000_02_10_7_mdev_types"); DO_TEST("pci_0000_42_00_0_vpd"); DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); + DO_TEST_INACTIVE("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); DO_TEST("ccw_0_0_ffff"); DO_TEST("css_0_0_ffff"); DO_TEST("css_0_0_ffff_channel_dev_addr"); @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST("mdev_d069d019_36ea_4111_8f0a_8c9a70e21366"); DO_TEST("mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9"); DO_TEST("mdev_fedc4916_1ca8_49ac_b176_871d16c13076"); + DO_TEST_INACTIVE("mdev_ee0b88c4_f554_4dc1_809d_b2a01e8e48ad"); + DO_TEST_INACTIVE("mdev_d069d019_36ea_4111_8f0a_8c9a70e21366"); + DO_TEST_INACTIVE("mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9"); + DO_TEST_INACTIVE("mdev_fedc4916_1ca8_49ac_b176_871d16c13076"); DO_TEST("hba_vport_ops"); + DO_TEST("mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c"); + DO_TEST_INACTIVE("mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c"); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Allow to dump the XML of the persistent mdev when the mdev has been started instead of the current state only. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- docs/manpages/virsh.rst | 7 +++++-- tools/virsh-nodedev.c | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ nodedev-dumpxml :: - nodedev-dumpxml [--xpath EXPRESSION] [--wrap] device + nodedev-dumpxml [--inactive] [--xpath EXPRESSION] [--wrap] device Dump a <device> XML representation for the given node device, including such information as the device name, which bus owns the device, the vendor and product id, and any capabilities of the device usable by libvirt (such as whether device reset is supported). *device* can be either device name or wwn pair in "wwnn,wwpn" format (only works -for HBA). +for HBA). An additional option affecting the XML dump may be +used. *--inactive* tells virsh to dump the node device configuration +that will be used on next start of the node device as opposed to the +current node device configuration. If the **--xpath** argument provides an XPath expression, it will be evaluated against the output XML and only those matching nodes will diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ static const vshCmdOptDef opts_node_device_dumpxml[] = { .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, }, + {.name = "inactive", + .type = VSH_OT_BOOL, + .help = N_("show inactive defined XML"), + }, {.name = "xpath", .type = VSH_OT_STRING, .flags = VSH_OFLAG_REQ_OPT, @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) g_autoptr(virshNodeDevice) device = NULL; g_autofree char *xml = NULL; const char *device_value = NULL; + unsigned int flags = 0; bool wrap = vshCommandOptBool(cmd, "wrap"); const char *xpath = NULL; @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) if (!device) return false; - if (!(xml = virNodeDeviceGetXMLDesc(device, 0))) + if (vshCommandOptBool(cmd, "inactive")) + flags |= VIR_NODE_DEVICE_XML_INACTIVE; + + if (!(xml = virNodeDeviceGetXMLDesc(device, flags))) return false; return virshDumpXML(ctl, xml, "node-device", xpath, wrap); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Allow to filter node devices based on their persistent or transient states. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- include/libvirt/libvirt-nodedev.h | 2 ++ src/conf/node_device_conf.h | 7 ++++++- src/conf/virnodedeviceobj.c | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -XXX,XX +XXX,XX @@ typedef enum { VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX = 1 << 20, /* s390 AP Matrix (Since: 7.0.0) */ VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD = 1 << 21, /* Device with VPD (Since: 7.9.0) */ + VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT = 1 << 28, /* Persisted devices (Since: 10.1.0) */ + VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT = 1 << 29, /* Transient devices (Since: 10.1.0) */ VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE = 1 << 30, /* Inactive devices (Since: 7.3.0) */ VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE = 1U << 31, /* Active devices (Since: 7.3.0) */ } virConnectListAllNodeDeviceFlags; diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNodeDevCapsDef, virNodeDevCapsDefFree); VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE | \ VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE +#define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_PERSISTENT \ + VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT | \ + VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT + #define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ALL \ VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP | \ - VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE + VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_PERSISTENT int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHost *scsi_host); diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceObjMatch(virNodeDeviceObj *obj, return false; } + if (flags & (VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_PERSISTENT)) { + if (!((MATCH(VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT) && + virNodeDeviceObjIsPersistent(obj)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT) && + !virNodeDeviceObjIsPersistent(obj)))) + return false; + } + return true; } #undef MATCH -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Now that we can filter persistent and transient node devices in virConnectListAllNodeDevices(), add these switches also to the virsh nodedev-list command. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- docs/manpages/virsh.rst | 8 ++++++-- tools/virsh-nodedev.c | 24 ++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ nodedev-list :: - nodedev-list [--cap capability] [--tree] [--inactive | --all] + nodedev-list [--cap capability] [--tree] [--inactive | --all] [--persistent | --transient] List all of the devices available on the node that are known by libvirt. *cap* is used to filter the list by capability types, the types must be @@ -XXX,XX +XXX,XX @@ separated by comma, e.g. --cap pci,scsi. Valid capability types include 'scsi', 'storage', 'fc_host', 'vports', 'scsi_generic', 'drm', 'mdev', 'mdev_types', 'ccw', 'css', 'ap_card', 'ap_queue', 'ap_matrix'. By default, only active devices are listed. *--inactive* is used to list only inactive -devices, and *-all* is used to list both active and inactive devices. +devices, and *--all* is used to list both active and inactive devices. +*--persistent* is used to list only persistent devices, and *--transient* is +used to list only transient devices. Not providing *--persistent* or +*--transient* will list all devices unless filtered otherwise. *--transient* +is mutually exclusive with *--persistent* and *--inactive*. If *--tree* is used, the output is formatted in a tree representing parents of each node. *--tree* is mutually exclusive with all other options. diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ static const vshCmdOptDef opts_node_list_devices[] = { .type = VSH_OT_BOOL, .help = N_("list inactive & active devices") }, + {.name = "persistent", + .type = VSH_OT_BOOL, + .help = N_("list persistent devices") + }, + {.name = "transient", + .type = VSH_OT_BOOL, + .help = N_("list transient devices") + }, {.name = NULL} }; @@ -XXX,XX +XXX,XX @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) int cap_type = -1; bool inactive = vshCommandOptBool(cmd, "inactive"); bool all = vshCommandOptBool(cmd, "all"); + bool persistent = vshCommandOptBool(cmd, "persistent"); + bool transient = vshCommandOptBool(cmd, "transient"); ignore_value(vshCommandOptStringQuiet(ctl, cmd, "cap", &cap_str)); @@ -XXX,XX +XXX,XX @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) return false; } - if (tree && (cap_str || inactive)) { - vshError(ctl, "%s", _("Option --tree is incompatible with --cap and --inactive")); + if (transient && (persistent || inactive)) { + vshError(ctl, "%s", _("Option --transient is incompatible with --persistent and --inactive")); + return false; + } + + if (tree && (cap_str || inactive || persistent || transient)) { + vshError(ctl, "%s", _("Option --tree is incompatible with --cap, --inactive, --persistent and --transient")); return false; } @@ -XXX,XX +XXX,XX @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) if (!inactive) flags |= VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE; + if (persistent) + flags |= VIR_CONNECT_LIST_NODE_DEVICES_PERSISTENT; + if (transient) + flags |= VIR_CONNECT_LIST_NODE_DEVICES_TRANSIENT; + if (!(list = virshNodeDeviceListCollect(ctl, caps, ncaps, flags))) { ret = false; goto cleanup; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Commit 26136e3 allowed to use option all with option tree but did not update the manpage. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- docs/manpages/virsh.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ used to list only transient devices. Not providing *--persistent* or *--transient* will list all devices unless filtered otherwise. *--transient* is mutually exclusive with *--persistent* and *--inactive*. If *--tree* is used, the output is formatted in a tree representing parents of -each node. *--tree* is mutually exclusive with all other options. +each node. *--tree* is mutually exclusive with all other options but *--all*. nodedev-reattach -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
A public API method which allows to update or modify objects is implemented for almost all other objects that have a concept of persistent definition and activatability. Currently node devices of type mdev can be persistent and active. This new method allows to update defined and active node devices as well. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- include/libvirt/libvirt-nodedev.h | 18 +++++++++++++ src/access/viraccessperm.c | 1 + src/access/viraccessperm.h | 6 +++++ src/conf/virnodedeviceobj.c | 42 +++++++++++++++++++++++++++++ src/conf/virnodedeviceobj.h | 3 +++ src/driver-nodedev.h | 6 +++++ src/libvirt-nodedev.c | 45 +++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 ++++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 17 +++++++++++- src/remote_protocol-structs | 6 +++++ 12 files changed, 150 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -XXX,XX +XXX,XX @@ int virNodeDeviceIsPersistent(virNodeDevicePtr dev); int virNodeDeviceIsActive(virNodeDevicePtr dev); +/** + * virNodeDeviceUpdateFlags: + * + * Flags to control options for virNodeDeviceUpdate() + * + * Since: 10.1.0 + */ +typedef enum { + VIR_NODE_DEVICE_UPDATE_AFFECT_CURRENT = 0, /* affect live if node device is active, + config if it's not active (Since: 10.1.0) */ + VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE = 1 << 0, /* affect live state of node device only (Since: 10.1.0) */ + VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG = 1 << 1, /* affect persistent config only (Since: 10.1.0) */ +} virNodeDeviceUpdateFlags; + +int virNodeDeviceUpdate(virNodeDevicePtr dev, + const char *xmlDesc, + unsigned int flags); + /** * VIR_NODE_DEVICE_EVENT_CALLBACK: * diff --git a/src/access/viraccessperm.c b/src/access/viraccessperm.c index XXXXXXX..XXXXXXX 100644 --- a/src/access/viraccessperm.c +++ b/src/access/viraccessperm.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virAccessPermNodeDevice, "getattr", "read", "write", "start", "stop", "detach", "delete", + "save", ); VIR_ENUM_IMPL(virAccessPermNWFilter, diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h index XXXXXXX..XXXXXXX 100644 --- a/src/access/viraccessperm.h +++ b/src/access/viraccessperm.h @@ -XXX,XX +XXX,XX @@ typedef enum { */ VIR_ACCESS_PERM_NODE_DEVICE_DELETE, + /** + * @desc: Save node device + * @message: Saving node device driver requires authorization + */ + VIR_ACCESS_PERM_NODE_DEVICE_SAVE, + VIR_ACCESS_PERM_NODE_DEVICE_LAST } virAccessPermNodeDevice; diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceObjListFind(virNodeDeviceObjList *devs, virNodeDeviceObjListFindHelper, &data); } + + +/** + * virNodeDeviceObjUpdateModificationImpact: + * @obj: Pointer to node device object + * @flags: flags to update the modification impact on + * + * Resolves virNodeDeviceUpdateFlags flags in @flags so that they correctly + * apply to the actual state of @obj. @flags may be modified after call to this + * function. + * + * Returns 0 on success if @flags point to a valid combination for @obj or -1 + * on error. + */ +int +virNodeDeviceObjUpdateModificationImpact(virNodeDeviceObj *obj, + unsigned int *flags) +{ + bool isActive = virNodeDeviceObjIsActive(obj); + + if ((*flags & (VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE | VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG)) == + VIR_NODE_DEVICE_UPDATE_AFFECT_CURRENT) { + if (isActive) + *flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE; + else + *flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG; + } + + if (!isActive && (*flags & VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("node device is not active")); + return -1; + } + + if (!virNodeDeviceObjIsPersistent(obj) && (*flags & VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("transient node devices do not have any persistent config")); + return -1; + } + + return 0; +} diff --git a/src/conf/virnodedeviceobj.h b/src/conf/virnodedeviceobj.h index XXXXXXX..XXXXXXX 100644 --- a/src/conf/virnodedeviceobj.h +++ b/src/conf/virnodedeviceobj.h @@ -XXX,XX +XXX,XX @@ virNodeDeviceObj * virNodeDeviceObjListFind(virNodeDeviceObjList *devs, virNodeDeviceObjListPredicate callback, void *opaque); + +int virNodeDeviceObjUpdateModificationImpact(virNodeDeviceObj *obj, + unsigned int *flags); diff --git a/src/driver-nodedev.h b/src/driver-nodedev.h index XXXXXXX..XXXXXXX 100644 --- a/src/driver-nodedev.h +++ b/src/driver-nodedev.h @@ -XXX,XX +XXX,XX @@ typedef int typedef int (*virDrvNodeDeviceIsActive)(virNodeDevicePtr dev); +typedef int +(*virDrvNodeDeviceUpdate)(virNodeDevicePtr dev, + const char *xmlDesc, + unsigned int flags); + typedef int (*virDrvConnectNodeDeviceEventRegisterAny)(virConnectPtr conn, virNodeDevicePtr dev, @@ -XXX,XX +XXX,XX @@ struct _virNodeDeviceDriver { virDrvNodeDeviceGetAutostart nodeDeviceGetAutostart; virDrvNodeDeviceIsPersistent nodeDeviceIsPersistent; virDrvNodeDeviceIsActive nodeDeviceIsActive; + virDrvNodeDeviceUpdate nodeDeviceUpdate; }; diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -XXX,XX +XXX,XX @@ int virNodeDeviceIsActive(virNodeDevicePtr dev) virDispatchError(dev->conn); return -1; } + + +/** + * virNodeDeviceUpdate: + * @dev: pointer to the node device object + * @xmlDesc: string containing an XML description of the device to be defined + * @flags: bitwise OR of virNodeDeviceUpdateFlags + * + * Update the definition of an existing node device, either its live running + * configuration, its persistent configuration, or both. + * + * Returns 0 in case of success, -1 in case of error + * + * Since: 10.1.0 + */ +int +virNodeDeviceUpdate(virNodeDevicePtr dev, + const char *xmlDesc, + unsigned int flags) +{ + VIR_DEBUG("nodeDevice=%p, xmlDesc=%s, flags=0x%x", + dev, NULLSTR(xmlDesc), flags); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + + virCheckReadOnlyGoto(dev->conn->flags, error); + virCheckNonNullArgGoto(xmlDesc, error); + + if (dev->conn->nodeDeviceDriver && + dev->conn->nodeDeviceDriver->nodeDeviceUpdate) { + int retval = dev->conn->nodeDeviceDriver->nodeDeviceUpdate(dev, xmlDesc, flags); + if (retval < 0) + goto error; + + return 0; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -XXX,XX +XXX,XX @@ virNodeDeviceObjListRemoveLocked; virNodeDeviceObjSetActive; virNodeDeviceObjSetAutostart; virNodeDeviceObjSetPersistent; +virNodeDeviceObjUpdateModificationImpact; # conf/virnwfilterbindingdef.h diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -XXX,XX +XXX,XX @@ LIBVIRT_9.7.0 { virNetworkSetMetadata; } LIBVIRT_9.0.0; +LIBVIRT_10.1.0 { + global: + virNodeDeviceUpdate; +} LIBVIRT_9.7.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 XXXXXXX..XXXXXXX 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -XXX,XX +XXX,XX @@ static virNodeDeviceDriver node_device_driver = { .nodeDeviceSetAutostart = remoteNodeDeviceSetAutostart, /* 7.8.0 */ .nodeDeviceIsPersistent = remoteNodeDeviceIsPersistent, /* 7.8.0 */ .nodeDeviceIsActive = remoteNodeDeviceIsActive, /* 7.8.0 */ + .nodeDeviceUpdate = remoteNodeDeviceUpdate, /* 10.1.0 */ }; static virNWFilterDriver nwfilter_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index XXXXXXX..XXXXXXX 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -XXX,XX +XXX,XX @@ struct remote_node_device_is_active_ret { int active; }; +struct remote_node_device_update_args { + remote_nonnull_string name; + remote_nonnull_string xml_desc; + unsigned int flags; +}; + /* * Events Register/Deregister: @@ -XXX,XX +XXX,XX @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446 + REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446, + + /** + * @generate: both + * @priority: high + * @acl: node_device:write + * @acl: node_device:save:!VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG|VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE + * @acl: node_device:save:VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG + */ + REMOTE_PROC_NODE_DEVICE_UPDATE = 447 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index XXXXXXX..XXXXXXX 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -XXX,XX +XXX,XX @@ struct remote_node_device_is_active_args { struct remote_node_device_is_active_ret { int active; }; +struct remote_node_device_update_args { + remote_nonnull_string name; + remote_nonnull_string xml_desc; + u_int flags; +}; struct remote_connect_domain_event_register_ret { int cb_registered; }; @@ -XXX,XX +XXX,XX @@ enum remote_procedure { REMOTE_PROC_NETWORK_SET_METADATA = 444, REMOTE_PROC_NETWORK_GET_METADATA = 445, REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446, + REMOTE_PROC_NODE_DEVICE_UPDATE = 447, }; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Implement the API functions in the node device driver by using mdevctl modify with the options defined and live. Instead of increasing the minimum mdevctl version to 1.3.0 in the spec file to ensure support exists in mdevctl the support is dynamically checked before using mdevctl. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com> --- NEWS.rst | 7 + libvirt.spec.in | 1 + src/node_device/node_device_driver.c | 224 +++++++++++++++++- src/node_device/node_device_driver.h | 11 + src/node_device/node_device_udev.c | 1 + ...60c_c60c_c60c_c60c_c60cc60cc60c_update.xml | 16 ++ tests/nodedevmdevctldata/mdevctl-modify.argv | 25 ++ tests/nodedevmdevctldata/mdevctl-modify.json | 4 + tests/nodedevmdevctltest.c | 90 ++++++- 9 files changed, 376 insertions(+), 3 deletions(-) create mode 100644 tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.argv create mode 100644 tests/nodedevmdevctldata/mdevctl-modify.json diff --git a/NEWS.rst b/NEWS.rst index XXXXXXX..XXXXXXX 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -XXX,XX +XXX,XX @@ v10.1.0 (unreleased) * **New features** + * nodedev: Support updating mdevs + + The node device driver has been extended to allow updating mediated node + devices. Options are available to target the update against the persistent, + active or both configurations of a mediated device. + **Note:** The support is only available with at least mdevctl v1.3.0 installed. + * qemu: Add support for /dev/userfaultfd On hosts with new enough kernel which supports /dev/userfaultfd libvirt will diff --git a/libvirt.spec.in b/libvirt.spec.in index XXXXXXX..XXXXXXX 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -XXX,XX +XXX,XX @@ Requires: libvirt-libs = %{version}-%{release} # needed for device enumeration Requires: systemd >= 185 # For managing persistent mediated devices +# Note: for nodedev-update support at least mdevctl v1.3.0 is required Requires: mdevctl # for modprobe of pci devices Requires: module-init-tools diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceDriverState *driver; VIR_ENUM_IMPL(virMdevctlCommand, MDEVCTL_CMD_LAST, - "start", "stop", "define", "undefine", "create" + "start", "stop", "define", "undefine", "create", "modify" ); @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, case MDEVCTL_CMD_START: case MDEVCTL_CMD_DEFINE: case MDEVCTL_CMD_UNDEFINE: + case MDEVCTL_CMD_MODIFY: cmd = virCommandNewArgList(MDEVCTL, subcommand, NULL); break; case MDEVCTL_CMD_LAST: @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, switch (cmd_type) { case MDEVCTL_CMD_CREATE: case MDEVCTL_CMD_DEFINE: + case MDEVCTL_CMD_MODIFY: if (!def->caps->data.mdev.parent_addr) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to find parent device '%1$s'"), def->parent); @@ -XXX,XX +XXX,XX @@ nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def, virCommandAddArgPair(cmd, "--jsonfile", "/dev/stdin"); virCommandSetInputBuffer(cmd, inbuf); - virCommandSetOutputBuffer(cmd, outbuf); + if (outbuf) + virCommandSetOutputBuffer(cmd, outbuf); break; case MDEVCTL_CMD_UNDEFINE: @@ -XXX,XX +XXX,XX @@ virMdevctlDefine(virNodeDeviceDef *def, char **uuid) } +/* gets a virCommand object that executes a mdevctl command to modify a + * a device to an updated version + */ +virCommand* +nodeDeviceGetMdevctlModifyCommand(virNodeDeviceDef *def, + bool defined, + bool live, + char **errmsg) +{ + virCommand *cmd = nodeDeviceGetMdevctlCommand(def, + MDEVCTL_CMD_MODIFY, + NULL, errmsg); + + if (!cmd) + return NULL; + + if (defined) + virCommandAddArg(cmd, "--defined"); + + if (live) + virCommandAddArg(cmd, "--live"); + + return cmd; +} + + +/* checks if mdevctl supports on the command modify the options live, defined + * and jsonfile + */ +static int +nodeDeviceGetMdevctlModifySupportCheck(void) +{ + int status; + g_autoptr(virCommand) cmd = NULL; + const char *subcommand = virMdevctlCommandTypeToString(MDEVCTL_CMD_MODIFY); + + cmd = virCommandNewArgList(MDEVCTL, + subcommand, + "--defined", + "--live", + "--jsonfile", + "b", + "--help", + NULL); + + if (!cmd) + return -1; + + if (virCommandRun(cmd, &status) < 0) + return -1; + + if (status != 0) // update is unsupported + return -1; + + return 0; +} + + +static int +virMdevctlModify(virNodeDeviceDef *def, + bool defined, + bool live) +{ + int status; + g_autofree char *errmsg = NULL; + g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlModifyCommand(def, + defined, + live, + &errmsg); + + if (!cmd) + return -1; + + if (nodeDeviceGetMdevctlModifySupportCheck() < 0) { + VIR_WARN("Installed mdevctl version does not support modify with options jsonfile, defined and live"); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Unable to modify mediated device: modify unsupported")); + return -1; + } + + if (virCommandRun(cmd, &status) < 0) + return -1; + + if (status != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to modify mediated device: %1$s"), + MDEVCTL_ERROR(errmsg)); + return -1; + } + + return 0; +} + + static virNodeDevicePtr nodeDeviceCreateXMLMdev(virConnectPtr conn, virNodeDeviceDef *def) @@ -XXX,XX +XXX,XX @@ nodeDeviceIsActive(virNodeDevice *device) virNodeDeviceObjEndAPI(&obj); return ret; } + + +static int +nodeDeviceDefValidateUpdate(virNodeDeviceDef *def, + virNodeDeviceDef *new_def, + bool live) +{ + virNodeDevCapsDef *caps = NULL; + virNodeDevCapMdev *cap_mdev = NULL; + virNodeDevCapMdev *cap_new_mdev = NULL; + + for (caps = def->caps; caps != NULL; caps = caps->next) { + if (caps->data.type == VIR_NODE_DEV_CAP_MDEV) { + cap_mdev = &caps->data.mdev; + } + } + if (!cap_mdev) + return -1; + + for (caps = new_def->caps; caps != NULL; caps = caps->next) { + if (caps->data.type == VIR_NODE_DEV_CAP_MDEV) { + cap_new_mdev = &caps->data.mdev; + } + } + if (!cap_new_mdev) + return -1; + + if (STRNEQ_NULLABLE(cap_mdev->uuid, cap_new_mdev->uuid)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot update device '%1$s, uuid mismatch (current uuid '%2$s')"), + def->name, + cap_mdev->uuid); + return -1; + } + + /* A live update cannot change the mdev type. Since the new config is + * stored in defined_config, compare that to the mdev type of the current + * live config to make sure they match */ + if (live && + STRNEQ_NULLABLE(cap_mdev->active_config.type, cap_new_mdev->defined_config.type)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot update device '%1$s', type mismatch (current type '%2$s')"), + def->name, + cap_mdev->active_config.type); + return -1; + } + if (STRNEQ_NULLABLE(cap_mdev->parent_addr, cap_new_mdev->parent_addr)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot update device '%1$s', parent address mismatch (current parent address '%2$s')"), + def->name, + cap_mdev->parent_addr); + return -1; + } + + return 0; +} + + +int +nodeDeviceUpdate(virNodeDevice *device, + const char *xmlDesc, + unsigned int flags) +{ + int ret = -1; + virNodeDeviceObj *obj = NULL; + virNodeDeviceDef *def; + g_autoptr(virNodeDeviceDef) new_def = NULL; + const char *virt_type = NULL; + bool updated = false; + + virCheckFlags(VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE | + VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG, -1); + + if (nodeDeviceInitWait() < 0) + return -1; + + if (!(obj = nodeDeviceObjFindByName(device->name))) + return -1; + def = virNodeDeviceObjGetDef(obj); + + virt_type = virConnectGetType(device->conn); + + if (virNodeDeviceUpdateEnsureACL(device->conn, def, flags) < 0) + goto cleanup; + + if (!(new_def = virNodeDeviceDefParse(xmlDesc, NULL, EXISTING_DEVICE, virt_type, + &driver->parserCallbacks, NULL, true))) + goto cleanup; + + if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV) && + nodeDeviceHasCapability(new_def, VIR_NODE_DEV_CAP_MDEV)) { + // Checks flags are valid for the state and sets flags for current if flags not set + if (virNodeDeviceObjUpdateModificationImpact(obj, &flags) < 0) + goto cleanup; + + // Compare def and new_def for compatibility e.g. parent, type and uuid + if (nodeDeviceDefValidateUpdate(def, new_def, + (flags & VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE)) < 0) + goto cleanup; + + // Update now + VIR_DEBUG("Update node device '%s' with mdevctl", def->name); + if (virMdevctlModify(new_def, + (flags & VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG), + (flags & VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE)) < 0) { + goto cleanup; + }; + // Detect updates and also trigger events + updated = true; + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unsupported device type")); + goto cleanup; + } + + ret = 0; + cleanup: + virNodeDeviceObjEndAPI(&obj); + if (updated) + nodeDeviceUpdateMediatedDevices(); + + return ret; +} diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -XXX,XX +XXX,XX @@ typedef enum { * separation makes our code more readable in terms of knowing when we're * starting a defined device and when we're creating a transient one */ MDEVCTL_CMD_CREATE, + MDEVCTL_CMD_MODIFY, MDEVCTL_CMD_LAST, } virMdevctlCommand; @@ -XXX,XX +XXX,XX @@ virCommand* nodeDeviceGetMdevctlSetAutostartCommand(virNodeDeviceDef *def, bool autostart, char **errmsg); + +virCommand* +nodeDeviceGetMdevctlModifyCommand(virNodeDeviceDef *def, + bool defined, + bool live, + char **errmsg); +int +nodeDeviceUpdate(virNodeDevice *dev, + const char *xmlDesc, + unsigned int flags); diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -XXX,XX +XXX,XX @@ static virNodeDeviceDriver udevNodeDeviceDriver = { .nodeDeviceGetAutostart = nodeDeviceGetAutostart, /* 7.8.0 */ .nodeDeviceIsPersistent = nodeDeviceIsPersistent, /* 7.8.0 */ .nodeDeviceIsActive = nodeDeviceIsActive, /* 7.8.0 */ + .nodeDeviceUpdate = nodeDeviceUpdate, /* 10.1.0 */ }; diff --git a/tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml b/tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml @@ -XXX,XX +XXX,XX @@ +<device> + <name>mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_0_0_0052</name> + <path>/sys/devices/css0/0.0.0052/c60cc60c-c60c-c60c-c60c-c60cc60cc60c</path> + <parent>css_0_0_0052</parent> + <driver> + <name>vfio_ccw_mdev</name> + </driver> + <capability type='mdev'> + <type id='vfio_ccw-io'/> + <uuid>c60cc60c-c60c-c60c-c60c-c60cc60cc60c</uuid> + <parent_addr>0.0.0052</parent_addr> + <attr name='add_attr_1' value='val1'/> + <attr name='add_attr_2' value='val2'/> + <iommuGroup number='4'/> + </capability> +</device> diff --git a/tests/nodedevmdevctldata/mdevctl-modify.argv b/tests/nodedevmdevctldata/mdevctl-modify.argv new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevmdevctldata/mdevctl-modify.argv @@ -XXX,XX +XXX,XX @@ +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--defined +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--live +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--live +mdevctl \ +modify \ +--parent=0.0.0052 \ +--jsonfile=/dev/stdin \ +--uuid=c60cc60c-c60c-c60c-c60c-c60cc60cc60c \ +--defined \ +--live diff --git a/tests/nodedevmdevctldata/mdevctl-modify.json b/tests/nodedevmdevctldata/mdevctl-modify.json new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/nodedevmdevctldata/mdevctl-modify.json @@ -XXX,XX +XXX,XX @@ +{"mdev_type":"vfio_ccw-io","start":"manual"} +{"mdev_type":"vfio_ccw-io","start":"manual","attrs":[{"add_attr_1":"val1"},{"add_attr_2":"val2"}]} +{"mdev_type":"vfio_ccw-io","start":"manual"} +{"mdev_type":"vfio_ccw-io","start":"manual","attrs":[{"add_attr_1":"val1"},{"add_attr_2":"val2"}]} diff --git a/tests/nodedevmdevctltest.c b/tests/nodedevmdevctltest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/nodedevmdevctltest.c +++ b/tests/nodedevmdevctltest.c @@ -XXX,XX +XXX,XX @@ testCommandDryRunCallback(const char *const*args G_GNUC_UNUSED, { char **stdinbuf = opaque; - *stdinbuf = g_strdup(input); + if (*stdinbuf) + *stdinbuf = g_strconcat(*stdinbuf, "\n", input, NULL); + else + *stdinbuf = g_strdup(input); } typedef virCommand * (*MdevctlCmdFunc)(virNodeDeviceDef *, char **, char **); @@ -XXX,XX +XXX,XX @@ testMdevctlCmd(virMdevctlCommand cmd_type, case MDEVCTL_CMD_START: case MDEVCTL_CMD_STOP: case MDEVCTL_CMD_UNDEFINE: + case MDEVCTL_CMD_MODIFY: create = EXISTING_DEVICE; break; case MDEVCTL_CMD_LAST: @@ -XXX,XX +XXX,XX @@ testMdevctlAutostart(const void *data G_GNUC_UNUSED) return ret; } + +static int +testMdevctlModify(const void *data G_GNUC_UNUSED) +{ + g_autoptr(virNodeDeviceDef) def = NULL; + g_autoptr(virNodeDeviceDef) def_update = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + const char *actualCmdline = NULL; + int ret = -1; + g_autoptr(virCommand) definedcmd = NULL; + g_autoptr(virCommand) livecmd = NULL; + g_autoptr(virCommand) bothcmd = NULL; + g_autofree char *errmsg = NULL; + g_autofree char *stdinbuf = NULL; + g_autofree char *mdevxml = + g_strdup_printf("%s/nodedevschemadata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c.xml", + abs_srcdir); + g_autofree char *mdevxml_update = + g_strdup_printf("%s/nodedevmdevctldata/mdev_c60cc60c_c60c_c60c_c60c_c60cc60cc60c_update.xml", + abs_srcdir); + /* just concatenate both calls into the same output files */ + g_autofree char *cmdlinefile = + g_strdup_printf("%s/nodedevmdevctldata/mdevctl-modify.argv", + abs_srcdir); + g_autofree char *jsonfile = + g_strdup_printf("%s/nodedevmdevctldata/mdevctl-modify.json", + abs_srcdir); + g_autoptr(virCommandDryRunToken) dryRunToken = virCommandDryRunTokenNew(); + + if (!(def = virNodeDeviceDefParse(NULL, mdevxml, CREATE_DEVICE, VIRT_TYPE, + &parser_callbacks, NULL, false))) + return -1; + + virCommandSetDryRun(dryRunToken, &buf, true, true, testCommandDryRunCallback, &stdinbuf); + + if (!(definedcmd = nodeDeviceGetMdevctlModifyCommand(def, true, false, &errmsg))) + goto cleanup; + + if (virCommandRun(definedcmd, NULL) < 0) + goto cleanup; + + if (!(def_update = virNodeDeviceDefParse(NULL, mdevxml_update, EXISTING_DEVICE, VIRT_TYPE, + &parser_callbacks, NULL, false))) + goto cleanup; + + if (!(livecmd = nodeDeviceGetMdevctlModifyCommand(def_update, false, true, &errmsg))) + goto cleanup; + + if (virCommandRun(livecmd, NULL) < 0) + goto cleanup; + + if (!(livecmd = nodeDeviceGetMdevctlModifyCommand(def, false, true, &errmsg))) + goto cleanup; + + if (virCommandRun(livecmd, NULL) < 0) + goto cleanup; + + if (!(bothcmd = nodeDeviceGetMdevctlModifyCommand(def_update, true, true, &errmsg))) + goto cleanup; + + if (virCommandRun(bothcmd, NULL) < 0) + goto cleanup; + + if (!(actualCmdline = virBufferCurrentContent(&buf))) + goto cleanup; + + if (virTestCompareToFileFull(actualCmdline, cmdlinefile, false) < 0) + goto cleanup; + + if (virTestCompareToFile(stdinbuf, jsonfile) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&buf); + return ret; +} + static int testMdevctlListDefined(const void *data G_GNUC_UNUSED) { @@ -XXX,XX +XXX,XX @@ mymain(void) #define DO_TEST_AUTOSTART() \ DO_TEST_FULL("autostart mdevs", testMdevctlAutostart, NULL) +#define DO_TEST_MODIFY() \ + DO_TEST_FULL("modify mdevs", testMdevctlModify, NULL) + #define DO_TEST_PARSE_JSON(filename) \ DO_TEST_FULL("parse mdevctl json " filename, testMdevctlParse, filename) @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST_AUTOSTART(); + DO_TEST_MODIFY(); + done: nodedevTestDriverFree(driver); -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Add ability to update node devices. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- docs/drvnodedev.rst | 4 +- docs/manpages/virsh.rst | 19 ++++++++ tools/virsh-nodedev.c | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/docs/drvnodedev.rst b/docs/drvnodedev.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/drvnodedev.rst +++ b/docs/drvnodedev.rst @@ -XXX,XX +XXX,XX @@ NPIV) <https://wiki.libvirt.org/page/NPIV_in_libvirt>`__). Persistent virtual devices are managed with ``virsh nodedev-define`` and ``virsh nodedev-undefine``. Persistent devices can be configured to start manually or automatically using ``virsh nodedev-autostart``. Inactive devices -can be made active with ``virsh nodedev-start``. +can be made active with ``virsh nodedev-start``. ``virsh nodedev-update`` +allows to modify devices (:since:`Since 10.1.0`). Transient virtual devices are started and stopped with the commands ``virsh nodedev-create`` and ``virsh nodedev-destroy``. @@ -XXX,XX +XXX,XX @@ covers the following features: - display device details ( :since:`Since 3.4.0` ) - create transient mediated devices ( :since:`Since 6.5.0` ) - define persistent mediated devices ( :since:`Since 7.3.0` ) +- update mediated devices ( :since:`Since 10.1.0` ) Because mediated devices are instantiated from vendor specific templates, simply called 'types', information describing these types is contained within the diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -XXX,XX +XXX,XX @@ If *--validate* is specified, validates the format of the XML document against an internal RNG schema. +nodedev-update +-------------- + +**Syntax:** + +:: + + nodedev-update device FILE [[--live] [--config] | [--current]] + +Update a device on the host. *device* can be either device name or wwn pair +in "wwnn,wwpn" format (only works for vHBA currently). *file* +contains xml for a top-level <device> description of the node device. +*--current* can be either or both of *live* and *config*, depends on +the hypervisor's implementation. +Both *--live* and *--config* flags may be given, but *--current* is +exclusive. If no flag is specified, behavior is different depending +on hypervisor. + + nodedev-destroy --------------- diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceInfo(vshControl *ctl, const vshCmd *cmd) } +/* + * "nodedev-update" command + */ +static const vshCmdInfo info_node_device_update[] = { + {.name = "help", + .data = N_("Update a active and/or inactive node device") + }, + {.name = "desc", + .data = N_("Updates the configuration of a node device") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_node_device_update[] = { + {.name = "device", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), + .completer = virshNodeDeviceNameCompleter, + }, + VIRSH_COMMON_OPT_FILE(N_("file containing an XML description " + "of the device")), + VIRSH_COMMON_OPT_CONFIG(N_("affect next node device startup")), + VIRSH_COMMON_OPT_LIVE(N_("affect running node device")), + VIRSH_COMMON_OPT_CURRENT(N_("affect current state of node device")), + {.name = NULL} +}; + +static bool +cmdNodeDeviceUpdate(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + g_autoptr(virshNodeDevice) device = NULL; + const char *device_value = NULL; + const char *from = NULL; + g_autofree char *xml = NULL; + bool config = vshCommandOptBool(cmd, "config"); + bool live = vshCommandOptBool(cmd, "live"); + unsigned int flags = VIR_NODE_DEVICE_UPDATE_AFFECT_CURRENT; + + VSH_EXCLUSIVE_OPTIONS("current", "live"); + VSH_EXCLUSIVE_OPTIONS("current", "config"); + + if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0) + return false; + + device = vshFindNodeDevice(ctl, device_value); + + if (!device) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + goto cleanup; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &xml) < 0) + goto cleanup; + + if (config) + flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_CONFIG; + if (live) + flags |= VIR_NODE_DEVICE_UPDATE_AFFECT_LIVE; + + if (virNodeDeviceUpdate(device, xml, flags) < 0) { + vshError(ctl, _("Failed to update node device %1$s from '%2$s'"), + virNodeDeviceGetName(device), from); + goto cleanup; + } + + if (config) { + if (live) + vshPrintExtra(ctl, _("Updated node device %1$s persistent config and live state"), + virNodeDeviceGetName(device)); + else + vshPrintExtra(ctl, _("Updated node device %1$s persistent config"), + virNodeDeviceGetName(device)); + } else if (live) { + vshPrintExtra(ctl, _("Updated node device %1$s live state"), + virNodeDeviceGetName(device)); + } else if (virNodeDeviceIsActive(device)) { + vshPrintExtra(ctl, _("Updated node device %1$s live state"), + virNodeDeviceGetName(device)); + } else { + vshPrintExtra(ctl, _("Updated node device %1$s persistent config"), + virNodeDeviceGetName(device)); + } + + ret = true; + cleanup: + vshReportError(ctl); + return ret; +} + const vshCmdDef nodedevCmds[] = { {.name = "nodedev-create", @@ -XXX,XX +XXX,XX @@ const vshCmdDef nodedevCmds[] = { .info = info_node_device_info, .flags = 0 }, + {.name = "nodedev-update", + .handler = cmdNodeDeviceUpdate, + .opts = opts_node_device_update, + .info = info_node_device_update, + .flags = 0 + }, {.name = NULL} }; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org
Allow to modify a node device by using virNodeDeviceDefineXML() to align its behavior with other drivers define methods. Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com> --- NEWS.rst | 5 +++ src/libvirt-nodedev.c | 4 ++- src/node_device/node_device_driver.c | 47 ++++++++++++++++++++++++---- tools/virsh-nodedev.c | 8 ++--- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index XXXXXXX..XXXXXXX 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -XXX,XX +XXX,XX @@ v10.1.0 (unreleased) * **Improvements** +* nodedev: Add ability to update persistent mediated devices by defining them + + Existing persistent mediated devices can now also be updated by + ``virNodeDeviceDefineXML()`` as long as parent and UUID remain unchanged. + * **Bug fixes** * qemu_process: Skip over non-virtio non-TAP NIC models when refreshing rx-filter diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -XXX,XX +XXX,XX @@ virNodeDeviceDestroy(virNodeDevicePtr dev) * @xmlDesc: string containing an XML description of the device to be defined * @flags: bitwise-OR of supported virNodeDeviceDefineXMLFlags * - * Define a new device on the VM host machine, for example, a mediated device + * Define a new inactive persistent device or modify an existing persistent + * one from the XML description on the VM host machine, for example, a mediated + * device. * * virNodeDeviceFree should be used to free the resources after the * node device object is no longer needed. diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index XXXXXXX..XXXXXXX 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -XXX,XX +XXX,XX @@ nodeDeviceUpdateMediatedDevice(virNodeDeviceDef *def, } +static virNodeDeviceObj* +findPersistentMdevNodeDevice(virNodeDeviceDef *def) +{ + virNodeDeviceObj *obj = NULL; + + if (!nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) + return NULL; + + if (def->caps->data.mdev.uuid && + def->caps->data.mdev.parent_addr && + (obj = virNodeDeviceObjListFindMediatedDeviceByUUID(driver->devs, + def->caps->data.mdev.uuid, + def->caps->data.mdev.parent_addr)) && + !virNodeDeviceObjIsPersistent(obj)) + virNodeDeviceObjEndAPI(&obj); + + return obj; +} + + virNodeDevice* nodeDeviceDefineXML(virConnect *conn, const char *xmlDesc, unsigned int flags) { g_autoptr(virNodeDeviceDef) def = NULL; + virNodeDeviceObj *persistent_obj = NULL; const char *virt_type = NULL; g_autofree char *uuid = NULL; g_autofree char *name = NULL; bool validate = flags & VIR_NODE_DEVICE_DEFINE_XML_VALIDATE; + bool modify_failed = false; virCheckFlags(VIR_NODE_DEVICE_DEFINE_XML_VALIDATE, NULL); @@ -XXX,XX +XXX,XX @@ nodeDeviceDefineXML(virConnect *conn, return NULL; } - if (virMdevctlDefine(def, &uuid) < 0) { - return NULL; - } + if ((persistent_obj = findPersistentMdevNodeDevice(def))) { + // virNodeDeviceObjUpdateModificationImpact() is not required we will + // modify the persistent config only. + // nodeDeviceDefValidateUpdate() is not required as uuid and parent are + // matching if def was found and changing the type in the persistent + // config is allowed. + VIR_DEBUG("Update node device '%s' with mdevctl", def->name); + modify_failed = (virMdevctlModify(def, true, false) < 0); + virNodeDeviceObjEndAPI(&persistent_obj); + if (modify_failed) + return NULL; + } else { + VIR_DEBUG("Define node device '%s' with mdevctl", def->name); + if (virMdevctlDefine(def, &uuid) < 0) + return NULL; - if (uuid && uuid[0]) { - g_free(def->caps->data.mdev.uuid); - def->caps->data.mdev.uuid = g_steal_pointer(&uuid); + if (uuid && uuid[0]) { + g_free(def->caps->data.mdev.uuid); + def->caps->data.mdev.uuid = g_steal_pointer(&uuid); + } } mdevGenerateDeviceName(def); diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index XXXXXXX..XXXXXXX 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -XXX,XX +XXX,XX @@ cmdNodeDeviceUndefine(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) */ static const vshCmdInfo info_node_device_define[] = { {.name = "help", - .data = N_("Define a device by an xml file on a node") + .data = N_("Define or modify a device by an xml file on a node") }, {.name = "desc", - .data = N_("Defines a persistent device on the node that can be " - "assigned to a domain. The device must be started before " - "it can be assigned to a domain.") + .data = N_("Defines or modifies a persistent device on the node that " + "can be assigned to a domain. The device must be started " + "before it can be assigned to a domain.") }, {.name = NULL} }; -- 2.42.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org