By traversing sysfs directory like "/sys/bus/pci/devices/0000:00:1f:2/" to find out the scsi host whose "unique_id" has the specified value. And returns the host number. Address like "0000:00:1f:2" will be retrieved from the "parent" of scsi_host adapter. E.g. <adapter type='scsi_host' parent='pci_0000_00_1f_2' unique_id='2'/> --- src/libvirt_private.syms | 1 + src/util/virutil.c | 128 +++++++++++++++++++++ src/util/virutil.h | 6 + .../ata1/host0/scsi_host/host0/unique_id | 1 + .../ata2/host1/scsi_host/host1/unique_id | 1 + tests/utiltest.c | 65 +++++++++-- 6 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 tests/sysfs/bus/pci/devices/0000:00:1f.2/ata1/host0/scsi_host/host0/unique_id create mode 100644 tests/sysfs/bus/pci/devices/0000:00:1f.2/ata2/host1/scsi_host/host1/unique_id diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f6ae42d..ce39cc6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1954,6 +1954,7 @@ virIsCapableVport; virIsDevMapperDevice; virManageVport; virParseNumber; +virParseStableScsiHostAddress; virParseVersionString; virPipeReadUntilEOF; virReadFCHost; diff --git a/src/util/virutil.c b/src/util/virutil.c index 8309568..a80574f 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -2137,6 +2137,125 @@ cleanup: } return ret; } + +struct virParseStableScsiHostAddressData { + const char *filename; + unsigned int unique_id; +}; + +static int +virParseStableScsiHostAddressCallback(const char *fpath, + void *opaque) +{ + struct virParseStableScsiHostAddressData *data = opaque; + unsigned int unique_id; + char *buf = NULL; + char *p; + int ret = -1; + + p = strrchr(fpath, '/'); + p++; + + if (STRNEQ(p, data->filename)) + return -1; + + if (virFileReadAll(fpath, 1024, &buf) < 0) + return -1; + + if ((p = strchr(buf, '\n'))) + *p = 0; + + if (virStrToLong_ui(buf, NULL, 10, &unique_id) < 0) + goto cleanup; + + if (unique_id != data->unique_id) + goto cleanup; + + ret = 0; +cleanup: + VIR_FREE(buf); + return ret; +} + +# define SYSFS_BUS_PCI_DEVICES "/sys/bus/pci/devices" + +/** + * virParseStableScsiHostAddress: + * @sysfs_prefix: The directory path where starts to traverse, defaults + * to SYSFS_BUS_PCI_DEVICES. + * @addr: The parent's PCI address + * @unique_id: The value of sysfs "unique_id" of the scsi host. + * + * Returns the host name (e.g. host10) of the scsi host whose parent + * has address @addr, and "unique_id" has value @unique_id, on success. + * Or NULL on failure. + */ +char * +virParseStableScsiHostAddress(const char *sysfs_prefix, + const char *address, + unsigned int unique_id) +{ + const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_BUS_PCI_DEVICES; + unsigned int flags = 0; + char **paths = NULL; + int npaths = 0; + char *dir = NULL; + char *p1 = NULL; + char *p2 = NULL; + char *ret = NULL; + int i; + + struct virParseStableScsiHostAddressData data = { + .filename = "unique_id", + .unique_id = unique_id, + }; + + if (virAsprintf(&dir, "%s/%s", prefix, address) < 0) { + virReportOOMError(); + return NULL; + } + + flags |= (VIR_TRAVERSE_DIRECTORY_IGNORE_HIDDEN_FILES | + VIR_TRAVERSE_DIRECTORY_FALL_THROUGH); + + if ((npaths = virTraverseDirectory(dir, 4, flags, + virParseStableScsiHostAddressCallback, + NULL, &data, &paths)) < 0) { + goto cleanup; + } else if (npaths == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to find scsi host with PCI address " + "'%s' unique_id '%u'"), address, unique_id); + goto cleanup; + } else if (npaths != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected multiple paths returned for PCI address " + "'%s' unique_id '%u'"), address, unique_id); + goto cleanup; + } + + if (!(p1 = strstr(paths[0], "scsi_host"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected returned path '%s' for PCI address " + "'%s' unique_id '%u'"), paths[0], address, unique_id); + goto cleanup; + } + + p1 += strlen("scsi_host"); + p2 = strrchr(p1, '/'); + + if (VIR_STRNDUP(ret, p1 + 1, p2 - p1 -1) < 0) + goto cleanup; + +cleanup: + VIR_FREE(dir); + if (npaths > 0) { + for (i = 0; i < npaths; i++) + VIR_FREE(paths[i]); + VIR_FREE(paths); + } + return ret; +} #else int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, @@ -2198,6 +2317,15 @@ virFindPCIDeviceByVPD(const char *sysfs_prefix, virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); return NULL; } + +char * +virParseStableScsiHostAddress(const char *sysfs_prefix, + const char *address, + unsigned int unique_id) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return NULL; +} #endif /* __linux__ */ /** diff --git a/src/util/virutil.h b/src/util/virutil.h index 99d3ea2..2747cf1 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -223,4 +223,10 @@ char *virFindPCIDeviceByVPD(const char *sysfs_prefix, const char *product) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +char *virParseStableScsiHostAddress(const char *sysfs_prefix, + const char *address, + unsigned int unique_id) + + ATTRIBUTE_NONNULL(2); + #endif /* __VIR_UTIL_H__ */ diff --git a/tests/sysfs/bus/pci/devices/0000:00:1f.2/ata1/host0/scsi_host/host0/unique_id b/tests/sysfs/bus/pci/devices/0000:00:1f.2/ata1/host0/scsi_host/host0/unique_id new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/sysfs/bus/pci/devices/0000:00:1f.2/ata1/host0/scsi_host/host0/unique_id @@ -0,0 +1 @@ +1 diff --git a/tests/sysfs/bus/pci/devices/0000:00:1f.2/ata2/host1/scsi_host/host1/unique_id b/tests/sysfs/bus/pci/devices/0000:00:1f.2/ata2/host1/scsi_host/host1/unique_id new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/tests/sysfs/bus/pci/devices/0000:00:1f.2/ata2/host1/scsi_host/host1/unique_id @@ -0,0 +1 @@ +2 diff --git a/tests/utiltest.c b/tests/utiltest.c index 8d3dbfa..41fdd7e 100644 --- a/tests/utiltest.c +++ b/tests/utiltest.c @@ -11,10 +11,12 @@ #include "virutil.h" #include "virstring.h" #include "virfile.h" +#include "virerror.h" -static char *sysfs_devices_prefix; +static char *test_sysfs; -#define TEST_SYSFS_DEVICES_PREFIX sysfs_devices_prefix +#define VIR_FROM_THIS VIR_FROM_NONE +#define TEST_SYSFS test_sysfs static void testQuietError(void *userData ATTRIBUTE_UNUSED, @@ -158,36 +160,78 @@ testParseVersionString(const void *data ATTRIBUTE_UNUSED) static int testFindPCIDeviceByVPD(const void *data ATTRIBUTE_UNUSED) { - char *addr = NULL; const char *expected_addr = "0000:00:1f.2"; const char *vendor = "0x8086"; const char *device = "0x1e03"; + char *dir = NULL; + char *addr = NULL; int ret = -1; - if (!(addr = virFindPCIDeviceByVPD(TEST_SYSFS_DEVICES_PREFIX, - vendor, device))) + if (virAsprintf(&dir, "%s/%s", TEST_SYSFS, "devices") < 0) { + virReportOOMError(); return -1; + } + + if (!(addr = virFindPCIDeviceByVPD(dir, vendor, device))) + goto cleanup; if (STRNEQ(addr, expected_addr)) goto cleanup; - if ((addr = virFindPCIDeviceByVPD(TEST_SYSFS_DEVICES_PREFIX, - "0x7076", "0x2434"))) + if ((addr = virFindPCIDeviceByVPD(dir, "0x7076", "0x2434"))) goto cleanup; ret = 0; cleanup: + VIR_FREE(dir); VIR_FREE(addr); return ret; } static int +testParseStableScsiHostAddress(const void *data ATTRIBUTE_UNUSED) +{ + const char *addr = "0000:00:1f.2"; + unsigned int host0_unique_id = 1; + unsigned int host1_unique_id = 2; + char *rc0 = NULL; + char *rc1 = NULL; + char *dir = NULL; + int ret = -1; + + if (virAsprintf(&dir, "%s/%s", TEST_SYSFS, "bus/pci/devices") < 0) { + virReportOOMError(); + return -1; + } + + if (!(rc0 = virParseStableScsiHostAddress(dir, addr, + host0_unique_id))) + goto cleanup; + + if (STRNEQ(rc0, "host0")) + goto cleanup; + + if (!(rc1 = virParseStableScsiHostAddress(dir, addr, + host1_unique_id))) + goto cleanup; + + if (STRNEQ(rc1, "host1")) + goto cleanup; + ret = 0; +cleanup: + VIR_FREE(dir); + VIR_FREE(rc0); + VIR_FREE(rc1); + return ret; +} + +static int mymain(void) { int result = 0; - if (virAsprintf(&sysfs_devices_prefix, "%s/%s", abs_srcdir, - "sysfs/devices/") < 0) { + if (virAsprintf(&test_sysfs, "%s/%s", abs_srcdir, "sysfs/") < 0) { + virReportOOMError(); result = -1; goto cleanup; } @@ -206,9 +250,10 @@ mymain(void) DO_TEST(DiskNameToIndex); DO_TEST(ParseVersionString); DO_TEST(FindPCIDeviceByVPD); + DO_TEST(ParseStableScsiHostAddress); cleanup: - VIR_FREE(sysfs_devices_prefix); + VIR_FREE(test_sysfs); return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.8.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list