diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng index e0a2c5032f..924f73861b 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -83,6 +83,7 @@ + @@ -580,6 +581,22 @@ + + + mdev + + + + + + + + + + + + + diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 7eeeff7932..9cb63860f5 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -577,6 +577,10 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def) virBufferEscapeString(&buf, "%s\n", virNodeDevDRMTypeToString(data->drm.type)); break; case VIR_NODE_DEV_CAP_MDEV: + virBufferEscapeString(&buf, "\n", data->mdev.type); + virBufferAsprintf(&buf, "\n", + data->mdev.iommuGroupNumber); + break; case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_VPORTS: @@ -1647,6 +1651,39 @@ virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt, } +static int +virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + virNodeDevCapMdevPtr mdev) +{ + xmlNodePtr orignode; + int ret = -1; + + orignode = ctxt->node; + ctxt->node = node; + + if (!(mdev->type = virXPathString("string(./type[1]/@id)", ctxt))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("missing type id attribute for '%s'"), def->name); + goto out; + } + + if (virNodeDevCapsDefParseULong("number(./iommuGroup[1]/@number)", ctxt, + &mdev->iommuGroupNumber, def, + _("missing iommuGroup number attribute for " + "'%s'"), + _("invalid iommuGroup number attribute for " + "'%s'")) < 0) + goto out; + + ret = 0; + out: + ctxt->node = orignode; + return ret; +} + + static virNodeDevCapsDefPtr virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt, virNodeDeviceDefPtr def, @@ -1715,6 +1752,8 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt, ret = virNodeDevCapDRMParseXML(ctxt, def, node, &caps->data.drm); break; case VIR_NODE_DEV_CAP_MDEV: + ret = virNodeDevCapMdevParseXML(ctxt, def, node, &caps->data.mdev); + break; case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_VPORTS: @@ -2038,6 +2077,8 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) VIR_FREE(data->sg.path); break; case VIR_NODE_DEV_CAP_MDEV: + VIR_FREE(data->mdev.type); + break; case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_DRM: case VIR_NODE_DEV_CAP_FC_HOST: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 18aaff8b52..5743f9d3e2 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -143,6 +143,13 @@ struct _virNodeDevCapMdevType { unsigned int available_instances; }; +typedef struct _virNodeDevCapMdev virNodeDevCapMdev; +typedef virNodeDevCapMdev *virNodeDevCapMdevPtr; +struct _virNodeDevCapMdev { + char *type; + unsigned int iommuGroupNumber; +}; + typedef struct _virNodeDevCapPCIDev virNodeDevCapPCIDev; typedef virNodeDevCapPCIDev *virNodeDevCapPCIDevPtr; struct _virNodeDevCapPCIDev { @@ -276,6 +283,7 @@ struct _virNodeDevCapData { virNodeDevCapStorage storage; virNodeDevCapSCSIGeneric sg; virNodeDevCapDRM drm; + virNodeDevCapMdev mdev; }; }; diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 4c75dec2bc..8288be1cba 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1068,6 +1068,42 @@ udevProcessSCSIGeneric(struct udev_device *dev, return 0; } +static int +udevProcessMediatedDevice(struct udev_device *dev, + virNodeDeviceDefPtr def) +{ + int ret = -1; + const char *uuidstr = NULL; + int iommugrp = -1; + char *linkpath = NULL; + char *realpath = NULL; + virNodeDevCapMdevPtr data = &def->caps->data.mdev; + + if (virAsprintf(&linkpath, "%s/mdev_type", udev_device_get_syspath(dev)) < 0) + goto cleanup; + + if (virFileResolveLink(linkpath, &realpath) < 0) + goto cleanup; + + if (VIR_STRDUP(data->type, last_component(realpath)) < 0) + goto cleanup; + + uuidstr = udev_device_get_sysname(dev); + if ((iommugrp = virMediatedDeviceGetIOMMUGroupNum(uuidstr)) < 0) + goto cleanup; + + if (udevGenerateDeviceName(dev, def, NULL) != 0) + goto cleanup; + + data->iommuGroupNumber = iommugrp; + + ret = 0; + cleanup: + VIR_FREE(linkpath); + VIR_FREE(realpath); + return ret; +} + static int udevGetDeviceNodes(struct udev_device *device, virNodeDeviceDefPtr def) @@ -1136,12 +1172,16 @@ udevGetDeviceType(struct udev_device *device, if (udevHasDeviceProperty(device, "INTERFACE")) *type = VIR_NODE_DEV_CAP_NET; - /* SCSI generic device doesn't set DEVTYPE property */ + /* Neither SCSI generic devices nor mediated devices set DEVTYPE + * property, therefore we need to rely on the SUBSYSTEM property */ if (udevGetStringProperty(device, "SUBSYSTEM", &subsystem) < 0) return -1; if (STREQ_NULLABLE(subsystem, "scsi_generic")) *type = VIR_NODE_DEV_CAP_SCSI_GENERIC; + else if (STREQ_NULLABLE(subsystem, "mdev")) + *type = VIR_NODE_DEV_CAP_MDEV; + VIR_FREE(subsystem); } @@ -1181,6 +1221,7 @@ static int udevGetDeviceDetails(struct udev_device *device, case VIR_NODE_DEV_CAP_DRM: return udevProcessDRMDevice(device, def); case VIR_NODE_DEV_CAP_MDEV: + return udevProcessMediatedDevice(device, def); case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_SYSTEM: case VIR_NODE_DEV_CAP_FC_HOST: diff --git a/tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml b/tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml new file mode 100644 index 0000000000..470e5917ec --- /dev/null +++ b/tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml @@ -0,0 +1,8 @@ + + mdev_3627463d_b7f0_4fea_b468_f1da537d301b + computer + + + + + diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c index e3a77646c1..a2aad518d3 100644 --- a/tests/nodedevxml2xmltest.c +++ b/tests/nodedevxml2xmltest.c @@ -102,6 +102,7 @@ mymain(void) DO_TEST("pci_0000_02_10_7_sriov_pf_vfs_all_header_type"); DO_TEST("drm_renderD129"); DO_TEST("pci_0000_02_10_7_mdev_types"); + DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }