[libvirt] [PATCH 05/11] util: Add util to parse the stable scsi host address

John Ferlan jferlan at redhat.com
Wed Jun 19 15:32:18 UTC 2013


On 06/07/2013 01:03 PM, Osier Yang wrote:
> 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'/>

Like my comment in 4/11 this code certainly assumes a specific directory
path.

> ---
>  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);

Is this the right error? Will it be confusing with errors from
virTraverseDirectory()?  I don't think it's multiple paths being returned.

> +        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;

Perhaps should have been part of 4/11...

>  
> -#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;
>  }

It seems this part of the change should have been squashed into 4/11 as
it's not related to this particular set of changes.... That includes the
test_sysfs modification...

Seems to be ACKable with nits resolved.

John
>  
>  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;
>  }
>  
> 




More information about the libvir-list mailing list