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);
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
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);
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);
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;
return -1;
for (i = 0; i < nattrs; i++)
- virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->dev_config);
+ virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], &mdev->defined_config);
return 0;
}
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:
struct _virNodeDevCapMdev {
unsigned int iommuGroupNumber;
char *uuid;
- virMediatedDeviceConfig dev_config;
+ virMediatedDeviceConfig defined_config;
+ virMediatedDeviceConfig active_config;
char *parent_addr;
bool autostart;
};
};
char *
-virNodeDeviceDefFormat(const virNodeDeviceDef *def);
+virNodeDeviceDefFormat(const virNodeDeviceDef *def, unsigned int flags);
typedef int (*virNodeDeviceDefPostParseCallback)(virNodeDeviceDef *dev,
/**
* 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.
virNodeDeviceDef *def;
char *ret = NULL;
- virCheckFlags(0, NULL);
+ virCheckFlags(VIR_NODE_DEVICE_XML_INACTIVE, NULL);
if (nodeDeviceInitWait() < 0)
return NULL;
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);
/* 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);
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;
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);
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;
int
nodeDeviceParseMdevctlJSON(const char *jsonstring,
- virNodeDeviceDef ***devs)
+ virNodeDeviceDef ***devs,
+ bool defined)
{
int n;
g_autoptr(virJSONValue) json_devicelist = NULL;
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;
/* 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
return -1;
}
- return nodeDeviceParseMdevctlJSON(output, devs);
+ return nodeDeviceParseMdevctlJSON(output, devs, defined);
}
* 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)) {
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) {
int
nodeDeviceParseMdevctlJSON(const char *jsonstring,
- virNodeDeviceDef ***devs);
+ virNodeDeviceDef ***devs,
+ bool defined);
int
nodeDeviceUpdateMediatedDevices(void);
const char *s);
bool nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst,
- virNodeDeviceDef *src);
+ virNodeDeviceDef *src,
+ bool defined);
int
nodeDeviceCreate(virNodeDevice *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)
objdef = virNodeDeviceObjGetDef(obj);
if (is_mdev)
- nodeDeviceDefCopyFromMdevctl(def, objdef);
+ nodeDeviceDefCopyFromMdevctl(def, objdef, false);
persistent = virNodeDeviceObjIsPersistent(obj);
autostart = virNodeDeviceObjIsAutostart(obj);
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;
"scsi_host11")))
goto cleanup;
- xml = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(objcopy));
+ xml = virNodeDeviceDefFormat(virNodeDeviceObjGetDef(objcopy), 0);
virNodeDeviceObjEndAPI(&objcopy);
if (!xml)
goto cleanup;
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);
--- /dev/null
+<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>
--- /dev/null
+mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml
\ No newline at end of file
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+mdev_d069d019_36ea_4111_8f0a_8c9a70e21366.xml
\ No newline at end of file
--- /dev/null
+mdev_d2441d39_495e_4243_ad9f_beb3f14c23d9.xml
\ No newline at end of file
--- /dev/null
+<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>
--- /dev/null
+mdev_fedc4916_1ca8_49ac_b176_871d16c13076.xml
\ No newline at end of file
#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;
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)
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;
}
{
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");
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");
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;
}