return -1;
}
+ if (disk->src->type == VIR_STORAGE_TYPE_NVME) {
+ if (disk->src->nvme->managed == VIR_TRISTATE_BOOL_ABSENT)
+ disk->src->nvme->managed = VIR_TRISTATE_BOOL_YES;
+ }
+
if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
virDomainDiskDefAssignAddress(xmlopt, disk, def) < 0) {
return -1;
return -1;
}
+ if (disk->src->type == VIR_STORAGE_TYPE_NVME) {
+ /* NVMe namespaces start from 1 */
+ if (disk->src->nvme->namespace == 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("NVMe namespace can't be zero"));
+ return -1;
+ }
+ }
+
for (next = disk->src; next; next = next->backingStore) {
if (virSecurityDeviceLabelDefValidateXML(next->seclabels,
next->nseclabels,
}
+static int
+virDomainDiskSourceNVMeParse(xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virStorageSourcePtr src)
+{
+ g_autoptr(virStorageSourceNVMeDef) nvme = NULL;
+ g_autofree char *type = NULL;
+ g_autofree char *namespace = NULL;
+ g_autofree char *managed = NULL;
+ xmlNodePtr address;
+
+ nvme = g_new0(virStorageSourceNVMeDef, 1);
+
+ if (!(type = virXMLPropString(node, "type"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing 'type' attribute to disk source"));
+ return -1;
+ }
+
+ if (STRNEQ(type, "pci")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unsupported source type '%s'"),
+ type);
+ return -1;
+ }
+
+ if (!(namespace = virXMLPropString(node, "namespace"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing 'namespace' attribute to disk source"));
+ return -1;
+ }
+
+ if (virStrToLong_ull(namespace, NULL, 10, &nvme->namespace) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("malformed namespace '%s'"),
+ namespace);
+ return -1;
+ }
+
+ if ((managed = virXMLPropString(node, "managed"))) {
+ if ((nvme->managed = virTristateBoolTypeFromString(managed)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("malformed managed value '%s'"),
+ managed);
+ return -1;
+ }
+ }
+
+ if (!(address = virXPathNode("./address", ctxt))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("NVMe disk source is missing address"));
+ return -1;
+ }
+
+ if (virPCIDeviceAddressParseXML(address, &nvme->pciAddr) < 0)
+ return -1;
+
+ src->nvme = g_steal_pointer(&nvme);
+ return 0;
+}
+
+
static int
virDomainDiskSourcePRParse(xmlNodePtr node,
xmlXPathContextPtr ctxt,
if (virDomainDiskSourcePoolDefParse(node, &src->srcpool) < 0)
return -1;
break;
+ case VIR_STORAGE_TYPE_NVME:
+ if (virDomainDiskSourceNVMeParse(node, ctxt, src) < 0)
+ return -1;
+ break;
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
}
+static void
+virDomainDiskSourceNVMeFormat(virBufferPtr attrBuf,
+ virBufferPtr childBuf,
+ const virStorageSourceNVMeDef *nvme)
+{
+ virBufferAddLit(attrBuf, " type='pci'");
+ virBufferAsprintf(attrBuf, " managed='%s'",
+ virTristateBoolTypeToString(nvme->managed));
+ virBufferAsprintf(attrBuf, " namespace='%llu'", nvme->namespace);
+ virPCIDeviceAddressFormat(childBuf, nvme->pciAddr, false);
+}
+
+
static int
virDomainDiskSourceFormatPrivateData(virBufferPtr buf,
virStorageSourcePtr src,
break;
+ case VIR_STORAGE_TYPE_NVME:
+ virDomainDiskSourceNVMeFormat(&attrBuf, &childBuf, src->nvme);
+ break;
+
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
virStorageSourceNew;
virStorageSourceNewFromBacking;
virStorageSourceNewFromBackingAbsolute;
+virStorageSourceNVMeDefFree;
virStorageSourceParseRBDColonString;
virStorageSourcePoolDefFree;
virStorageSourcePoolModeTypeFromString;
break;
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
break;
break;
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
return NULL;
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_DIR:
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
return 0;
case VIR_STORAGE_TYPE_NONE:
break;
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
break;
case VIR_STORAGE_TYPE_DIR:
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
case VIR_STORAGE_TYPE_NETWORK:
case VIR_STORAGE_TYPE_DIR:
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
case VIR_STORAGE_TYPE_DIR:
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
case VIR_STORAGE_TYPE_DIR:
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_DIR:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
/* But network disks are safe again. */
continue;
+ case VIR_STORAGE_TYPE_NVME:
+ unsafe = true;
+ break;
+
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_DIR:
"dir",
"network",
"volume",
+ "nvme",
);
VIR_ENUM_IMPL(virStorageFileFormat,
}
+static virStorageSourceNVMeDefPtr
+virStorageSourceNVMeDefCopy(const virStorageSourceNVMeDef *src)
+{
+ virStorageSourceNVMeDefPtr ret = NULL;
+
+ ret = g_new0(virStorageSourceNVMeDef, 1);
+
+ ret->namespace = src->namespace;
+ ret->managed = src->managed;
+ virPCIDeviceAddressCopy(&ret->pciAddr, &src->pciAddr);
+ return ret;
+}
+
+
+static bool
+virStorageSourceNVMeDefIsEqual(const virStorageSourceNVMeDef *a,
+ const virStorageSourceNVMeDef *b)
+{
+ if (!a && !b)
+ return true;
+
+ if (!a || !b)
+ return false;
+
+ if (a->namespace != b->namespace ||
+ a->managed != b->managed ||
+ !virPCIDeviceAddressEqual(&a->pciAddr, &b->pciAddr))
+ return false;
+
+ return true;
+}
+
+
+void
+virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def);
+}
+
+
virSecurityDeviceLabelDefPtr
virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
const char *model)
!(def->pr = virStoragePRDefCopy(src->pr)))
return NULL;
+ if (src->nvme)
+ def->nvme = virStorageSourceNVMeDefCopy(src->nvme);
+
if (virStorageSourceInitiatorCopy(&def->initiator, &src->initiator) < 0)
return NULL;
}
}
+ if (a->type == VIR_STORAGE_TYPE_NVME &&
+ !virStorageSourceNVMeDefIsEqual(a->nvme, b->nvme))
+ return false;
+
return true;
}
case VIR_STORAGE_TYPE_NETWORK:
case VIR_STORAGE_TYPE_VOLUME:
+ /* While NVMe disks are local, they are not accessible via src->path.
+ * Therefore, we have to return false here. */
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_LAST:
case VIR_STORAGE_TYPE_NONE:
return false;
VIR_FREE(def->compat);
virStorageEncryptionFree(def->encryption);
virStoragePRDefFree(def->pr);
+ virStorageSourceNVMeDefFree(def->nvme);
virStorageSourceSeclabelsClear(def);
virStoragePermsFree(def->perms);
VIR_FREE(def->timestamps);
/* We shouldn't get VOLUME, but the switch requires all cases */
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
return -1;
case VIR_STORAGE_TYPE_NETWORK:
case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
return false;
#include "virutil.h"
#include "virsecret.h"
#include "virenum.h"
+#include "virpci.h"
/* Minimum header size required to probe all known formats with
* virStorageFileProbeFormat, or obtain metadata from a known format.
VIR_STORAGE_TYPE_DIR,
VIR_STORAGE_TYPE_NETWORK,
VIR_STORAGE_TYPE_VOLUME,
+ VIR_STORAGE_TYPE_NVME,
VIR_STORAGE_TYPE_LAST
} virStorageType;
char *iqn; /* Initiator IQN */
};
+typedef struct _virStorageSourceNVMeDef virStorageSourceNVMeDef;
+typedef virStorageSourceNVMeDef *virStorageSourceNVMeDefPtr;
+struct _virStorageSourceNVMeDef {
+ unsigned long long namespace;
+ int managed; /* enum virTristateBool */
+ virPCIDeviceAddress pciAddr;
+
+ /* Don't forget to update virStorageSourceNVMeDefCopy */
+};
+
typedef struct _virStorageDriverData virStorageDriverData;
typedef virStorageDriverData *virStorageDriverDataPtr;
bool encryptionInherited;
virStoragePRDefPtr pr;
+ virStorageSourceNVMeDefPtr nvme; /* type == VIR_STORAGE_TYPE_NVME */
+
virStorageSourceInitiatorDef initiator;
virObjectPtr privateData;
bool
virStorageSourceChainHasManagedPR(virStorageSourcePtr src);
+void virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSourceNVMeDef, virStorageSourceNVMeDefFree);
+
virSecurityDeviceLabelDefPtr
virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
const char *model);
--- /dev/null
+../qemuxml2argvdata/disk-nvme.xml
\ No newline at end of file
DO_TEST("disk-network-sheepdog", NONE);
DO_TEST("disk-network-vxhs", NONE);
DO_TEST("disk-network-tlsx509", NONE);
+ DO_TEST("disk-nvme", QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_QCOW2_LUKS);
DO_TEST("disk-scsi", QEMU_CAPS_SCSI_LSI, QEMU_CAPS_SCSI_MEGASAS,
QEMU_CAPS_SCSI_MPTSAS1068, QEMU_CAPS_SCSI_DISK_WWN);
DO_TEST("disk-virtio-scsi-reservations",