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