To be more flexible, except allowing to specify 'parent' with name produced by node device udev/HAL backends, this supports to specify 'parent' with PCI address directly (e.g. 0000:00:1f:2). The specified address will be padded if it's not consistent with what sysfs exposed. (e.g 0:0:2:2 will be padded to 0000:00:02:2). --- src/storage/storage_backend_scsi.c | 117 +++++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 24 deletions(-) diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index a77b9ae..5635f73 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -604,51 +604,120 @@ out: static char * getScsiHostParentAddress(const char *parent) { + virBuffer buf = VIR_BUFFER_INITIALIZER; char **tokens = NULL; char *vendor = NULL; char *product = NULL; char *ret = NULL; - int len; + int length; + int i; - if (!strchr(parent, '_')) { + if (!strchr(parent, '_') && + !strchr(parent, ':')) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("'parent' of scsi_host adapter must " - "be consistent with name of node device")); + _("'parent' of scsi_host adapter must be " + "either consistent with name of mode " + "device, or in domain:bus:slot:function " + "format")); return NULL; } - if (!(tokens = virStringSplit(parent, "_", 0))) - return NULL; + if (strchr(parent, '_')) { + if (!(tokens = virStringSplit(parent, "_", 0))) + return NULL; - len = virStringListLength(tokens); + length = virStringListLength(tokens); + + switch (length) { + case 4: + if (!(ret = virStringJoin((const char **)(&tokens[1]), ":"))) + goto cleanup; + break; - switch (len) { - case 4: - if (!(ret = virStringJoin((const char **)(&tokens[1]), ":"))) + case 2: + vendor = tokens[1]; + product = tokens[2]; + if (!(ret = virFindPCIDeviceByVPD(NULL, vendor, product))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to find PCI device with vendor '%s' " + "product '%s'"), vendor, product); + goto cleanup; + } + + break; + default: + virReportError(VIR_ERR_XML_ERROR, "%s", + _("'parent' of scsi_host adapter must be " + "either consistent with name of mode " + "device, or in domain:bus:slot:function " + "format")); goto cleanup; - break; + } + } else if (strchr(parent, ':')) { + char *padstr = NULL; + + if (!(tokens = virStringSplit(parent, ":", 0))) + return NULL; - case 2: - vendor = tokens[1]; - product = tokens[2]; - if (!(ret = virFindPCIDeviceByVPD(NULL, vendor, product))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find PCI device with vendor '%s' " - "product '%s'"), vendor, product); + length = virStringListLength(tokens); + + if (length != 4) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid PCI address for scsi_host " + "'parent' '%s'"), parent); goto cleanup; } - break; - default: - virReportError(VIR_ERR_XML_ERROR, "%s", - _("'parent' of scsi_host adapter must " - "be consistent with name of node device")); - goto cleanup; + for (i = 0; i < length; i++) { + if (strlen(tokens[i]) == 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid PCI address for scsi_host " + "'parent' '%s'"), parent); + goto cleanup; + } + } + + /* sysfs always exposes the PCI address like "0000:00:1f:2", + * this do the padding if the address prodived by user is + * not padded (e.g. 0:0:2:0). + */ + if (strlen(tokens[0]) != 4) { + if (!(padstr = virStringPad(tokens[0], '0', 4, false))) + goto cleanup; + + virBufferAsprintf(&buf, "%s", padstr); + VIR_FREE(padstr); + } else { + virBufferAsprintf(&buf, "%s", tokens[0]); + } + + for (i = 1; i < 3; i++) { + if (strlen(tokens[i]) != 2) { + if (!(padstr = virStringPad(tokens[i], '0', 2, false))) + goto error; + virBufferAsprintf(&buf, "%s", padstr); + VIR_FREE(padstr); + } else { + virBufferAsprintf(&buf, "%s", tokens[i]); + } + } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + goto cleanup; + } + + ret = virBufferContentAndReset(&buf); } cleanup: virStringFreeList(tokens); return ret; + +error: + virBufferFreeAndReset(&buf); + goto cleanup; } static int -- 1.8.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list