[libvirt] [PATCH v2 05/10] utils: util functions for scsi hostdev

Osier Yang jyang at redhat.com
Wed Apr 3 09:04:37 UTC 2013


On 01/04/13 20:00, Han Cheng wrote:
> This patch add util functions for scsi hostdev.
>
> Signed-off-by: Han Cheng <hanc.fnst at cn.fujitsu.com>
> ---
>   po/POTFILES.in           |    1 +
>   src/Makefile.am          |    1 +
>   src/libvirt_private.syms |   22 +++
>   src/util/virscsi.c       |  399 ++++++++++++++++++++++++++++++++++++++++++++++
>   src/util/virscsi.h       |   83 ++++++++++
>   5 files changed, 506 insertions(+), 0 deletions(-)
>   create mode 100644 src/util/virscsi.c
>   create mode 100644 src/util/virscsi.h
>
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 91e5c02..39a0a19 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -174,6 +174,7 @@ src/util/virportallocator.c
>   src/util/virprocess.c
>   src/util/virrandom.c
>   src/util/virsexpr.c
> +src/util/virscsi.c
>   src/util/virsocketaddr.c
>   src/util/virstatslinux.c
>   src/util/virstoragefile.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 3f69d39..49d7f88 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -111,6 +111,7 @@ UTIL_SOURCES =							\
>   		util/virportallocator.c util/virportallocator.h \
>   		util/virprocess.c util/virprocess.h		\
>   		util/virrandom.h util/virrandom.c		\
> +		util/virscsi.c util/virscsi.h			\
>   		util/virsexpr.c util/virsexpr.h			\
>   		util/virsocketaddr.h util/virsocketaddr.c	\
>   		util/virstatslinux.c util/virstatslinux.h	\
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index f2eefc3..6a5962e 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1665,6 +1665,28 @@ virRandomGenerateWWN;
>   virRandomInt;
>   
>   
> +# util/virscsi.h
> +virSCSIDeviceFileIterate;
> +virSCSIDeviceFree;
> +virSCSIDeviceGetAdapter;
> +virSCSIDeviceGetBus;
> +virSCSIDeviceGetDevStr;
> +virSCSIDeviceGetName;
> +virSCSIDeviceGetReadonly;
> +virSCSIDeviceGetTarget;
> +virSCSIDeviceGetUnit;
> +virSCSIDeviceGetUsedBy;
> +virSCSIDeviceListAdd;
> +virSCSIDeviceListCount;
> +virSCSIDeviceListDel;
> +virSCSIDeviceListFind;
> +virSCSIDeviceListGet;
> +virSCSIDeviceListNew;
> +virSCSIDeviceListSteal;
> +virSCSIDeviceNew;
> +virSCSIDeviceSetUsedBy;
> +
> +
>   # util/virsexpr.h
>   sexpr2string;
>   sexpr_append;
> diff --git a/src/util/virscsi.c b/src/util/virscsi.c
> new file mode 100644
> index 0000000..5d0dcd7
> --- /dev/null
> +++ b/src/util/virscsi.c
> @@ -0,0 +1,399 @@
> +/*
> + * virscsi.c: helper APIs for managing host SCSI devices
> + *
> + * Copyright (C) 2013 Fujitsu, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + *     Han Cheng <hanc.fnst at cn.fujitsu.com>
> + */
> +
> +#include <config.h>
> +
> +#include <dirent.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <limits.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +#include "virscsi.h"
> +#include "virlog.h"
> +#include "viralloc.h"
> +#include "virutil.h"
> +#include "virerror.h"
> +
> +#define SCSI_DEVFS "/sys/bus/scsi/devices"

Generally we name macro like this as "SYSFS_SCSI_DEVICES".  virpci.c
is too old.

> +
> +/* For virReportOOMError()  and virReportSystemError() */
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +struct _virSCSIDevice {
> +    unsigned int      adapter;
> +    unsigned int      bus;
> +    unsigned int      target;
> +    unsigned int      unit;
> +
> +    char          *name;   /* adapter:bus:target:unit */
> +    char          *id;     /* model vendor */
> +    char          *path;
> +    const char    *used_by;           /* name of the domain using this dev */
> +
> +    unsigned int      readonly : 1;
> +};
> +
> +struct _virSCSIDeviceList {
> +    virObjectLockable parent;
> +    unsigned int count;
> +    virSCSIDevicePtr *devs;
> +};
> +
> +static virClassPtr virSCSIDeviceListClass;
> +
> +static void virSCSIDeviceListDispose(void *obj);
> +
> +static int virSCSIOnceInit(void)
> +{
> +    if (!(virSCSIDeviceListClass = virClassNew(virClassForObjectLockable(),
> +                                              "virSCSIDeviceList",
> +                                              sizeof(virSCSIDeviceList),
> +                                              virSCSIDeviceListDispose)))
> +        return -1;
> +
> +    return 0;
> +}
> +
> +VIR_ONCE_GLOBAL_INIT(virSCSI)
> +
> +static int virSCSIDeviceGetAdapterId(char *adapter, unsigned int *adapterid)
> +{
> +    if (STRSKIP(adapter, "scsi_host") &&
> +        virStrToLong_ui(adapter + strlen("scsi_host"), NULL, 0,
> +                        adapterid) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse adapter %s"), adapter);
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +char *
> +virSCSIDeviceGetDevStr(char *adapter,
> +                      unsigned int bus,
> +                      unsigned int target,
> +                      unsigned int unit)

Indentions?

> +{
> +    DIR *dir = NULL;
> +    struct dirent *entry;
> +    char *path = NULL;
> +    char *sg = NULL;
> +    unsigned int adapterid;
> +
> +    if (virSCSIDeviceGetAdapterId(adapter, &adapterid) < 0)
> +        goto out;
> +
> +    if (virAsprintf(&path,
> +                    SCSI_DEVFS "/%d:%d:%d:%d/scsi_generic",
> +                    adapterid, bus, target, unit) < 0) {
> +        virReportOOMError();
> +        goto out;
> +    }
> +    if (!(dir = opendir(path))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Failed to open %s"), path);
> +        goto out;
> +    }
> +
> +    while ((entry = readdir(dir))) {
> +        if (entry->d_name[0] == '.')
> +            continue;
> +
> +        if (virAsprintf(&sg, "%s", entry->d_name) < 0) {
> +            virReportOOMError();
> +            goto out;
> +        }
> +    }
> +
> +out:
> +    closedir(dir);
> +    VIR_FREE(path);
> +    return sg;
> +}
> +
> +virSCSIDevicePtr
> +virSCSIDeviceNew(char *adapter,
> +                 unsigned int bus,
> +                 unsigned int target,
> +                 unsigned int unit,
> +                 unsigned int readonly)
> +{
> +    virSCSIDevicePtr dev;
> +    char *sg = NULL;
> +    char *vendor = NULL;
> +    char *model = NULL;
> +    char *tmp = NULL;
> +
> +    if (VIR_ALLOC(dev) < 0) {
> +        virReportOOMError();
> +        return NULL;
> +    }
> +
> +    dev->bus = bus;
> +    dev->target = target;
> +    dev->unit = unit;
> +    dev->readonly = readonly;
> +
> +    if (!(sg = virSCSIDeviceGetDevStr(adapter, bus, target, unit))) {
> +        goto out;
> +    }

if (!(sg = virSCSIDeviceGetDevStr(adapter, bus, target, unit)))
     goto out;


> ve
> +    if (virSCSIDeviceGetAdapterId(adapter, &dev->adapter) < 0) {
> +        goto out;
> +    }

Likewise.

> v
> +    if (virAsprintf(&dev->name, "%d:%d:%d:%d",
> +                    dev->adapter, dev->bus, dev->bus,
> +                    dev->unit) < 0) {
> +        virReportOOMError();
> +        goto out;
> +    }
> +    if (virAsprintf(&dev->path, "/dev/%s", sg) < 0) {
> +        virReportOOMError();
> +        goto out;
> +    }
> +    if (access(dev->path, F_OK) != 0) {
> +        virReportSystemError(errno,
> +                             _("Device %s not found: could not access %s"),
> +                             dev->name, dev->path);
> +        goto out;
> +    }
> +    if (virAsprintf(&tmp, SCSI_DEVFS "/%s/vendor", dev->name) < 0) {
> +        virReportOOMError();
> +        goto out;
> +    }
> +    if (virFileReadAll(tmp, 1024, &vendor) < 0)
> +        goto out;
> +    VIR_FREE(tmp);
> +    tmp = NULL;
> +    if (virAsprintf(&tmp, SCSI_DEVFS "/%s/model", dev->name) < 0) {
> +        virReportOOMError();
> +        goto out;
> +    }
> +    if (virFileReadAll(tmp, 1024, &model) < 0)
> +        goto out;
> +    *(vendor + strlen(vendor) - 1) = '\0';

This should be right after reading "vendor"

> +    *(model + strlen(model) - 1) = '\0';
> +    if (virAsprintf(&dev->id, "%s %s", vendor, model) < 0) {

Is it possible for the "vendor" and "name" contains white space(s)? if 
it is,
then separating them  by one space has problem.

> +        virReportOOMError();
> +        goto out;
> +    }
> +    VIR_FREE(tmp);
> +    VIR_FREE(vendor);
> +    VIR_FREE(model);

Redundant code, these 3 frees can be removed if you do as following....

> +
> +    VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
> +
> +    return dev;

ret = dev;

> +
> +out:
> +    VIR_FREE(tmp);
> +    VIR_FREE(vendor);
> +    VIR_FREE(model);
> +    virSCSIDeviceFree(dev);

if (!ret)
      virSCSIDeviceFree(dev);

> +    return NULL;

return ret;

> +}
> +
> +void
> +virSCSIDeviceFree(virSCSIDevicePtr dev)
> +{
> +    if (!dev)
> +        return;
> +    VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
> +    VIR_FREE(dev->id);
> +    VIR_FREE(dev->name);
> +    VIR_FREE(dev->path);
> +    VIR_FREE(dev);
> +}
> +
> +
> +void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev,
> +                            const char *name)
> +{
> +    dev->used_by = name;
> +}
> +
> +const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev)
> +{
> +    return dev->used_by;
> +}
> +
> +const char *virSCSIDeviceGetName(virSCSIDevicePtr dev)
> +{
> +    return dev->name;
> +}
> +
> +unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev)
> +{
> +    return dev->adapter;
> +}
> +
> +unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev)
> +{
> +    return dev->bus;
> +}
> +
> +unsigned int virSCSIDeviceGetTarget(virSCSIDevicePtr dev)
> +{
> +    return dev->target;
> +}
> +
> +unsigned int virSCSIDeviceGetUnit(virSCSIDevicePtr dev)
> +{
> +    return dev->unit;
> +}
> +
> +unsigned int virSCSIDeviceGetReadonly(virSCSIDevicePtr dev)
> +{
> +    return dev->readonly;
> +}
> +
> +int virSCSIDeviceFileIterate(virSCSIDevicePtr dev,
> +                             virSCSIDeviceFileActor actor,
> +                             void *opaque)
> +{
> +    return (actor)(dev, dev->path, opaque);
> +}
> +
> +virSCSIDeviceListPtr
> +virSCSIDeviceListNew(void)
> +{
> +    virSCSIDeviceListPtr list;
> +
> +    if (virSCSIInitialize() < 0)
> +        return NULL;
> +
> +    if (!(list = virObjectLockableNew(virSCSIDeviceListClass)))
> +        return NULL;
> +
> +    return list;
> +}
> +
> +static void
> +virSCSIDeviceListDispose(void *obj)
> +{
> +    virSCSIDeviceListPtr list = obj;
> +    int i;
> +
> +    for (i = 0; i < list->count; i++)
> +        virSCSIDeviceFree(list->devs[i]);
> +
> +    VIR_FREE(list->devs);
> +}
> +
> +int
> +virSCSIDeviceListAdd(virSCSIDeviceListPtr list,
> +                     virSCSIDevicePtr dev)
> +{
> +    if (virSCSIDeviceListFind(list, dev)) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Device %s is already in use"),

"Device %s already exists". It should be cut-n-paste from virpci.c.

> +                       dev->name);
> +        return -1;
> +    }
> +
> +    if (VIR_REALLOC_N(list->devs, list->count+1) < 0) {
> +        virReportOOMError();
> +        return -1;
> +    }
> +
> +    list->devs[list->count++] = dev;
> +
> +    return 0;
> +}
> +
> +virSCSIDevicePtr
> +virSCSIDeviceListGet(virSCSIDeviceListPtr list,
> +                     int idx)
> +{
> +    if (idx >= list->count ||
> +        idx < 0)
> +        return NULL;
> +
> +    return list->devs[idx];
> +}
> +
> +int
> +virSCSIDeviceListCount(virSCSIDeviceListPtr list)
> +{
> +    return list->count;
> +}
> +
> +virSCSIDevicePtr
> +virSCSIDeviceListSteal(virSCSIDeviceListPtr list,
> +                       virSCSIDevicePtr dev)
> +{
> +    virSCSIDevicePtr ret = NULL;
> +    int i;
> +
> +    for (i = 0; i < list->count; i++) {
> +        if (list->devs[i]->adapter != dev->adapter ||
> +            list->devs[i]->bus != dev->bus ||
> +            list->devs[i]->target != dev->target ||
> +            list->devs[i]->unit != dev->unit)
> +            continue;
> +
> +        ret = list->devs[i];
> +
> +        if (i != list->count--)
> +            memmove(&list->devs[i],
> +                    &list->devs[i+1],
> +                    sizeof(*list->devs) * (list->count - i));
> +
> +        if (VIR_REALLOC_N(list->devs, list->count) < 0) {
> +            ; /* not fatal */
> +        }
> +
> +        break;
> +    }
> +    return ret;
> +}
> +
> +void
> +virSCSIDeviceListDel(virSCSIDeviceListPtr list,
> +                     virSCSIDevicePtr dev)
> +{
> +    virSCSIDevicePtr ret = virSCSIDeviceListSteal(list, dev);
> +    virSCSIDeviceFree(ret);
> +}
> +
> +virSCSIDevicePtr
> +virSCSIDeviceListFind(virSCSIDeviceListPtr list,
> +                      virSCSIDevicePtr dev)
> +{
> +    int i;
> +
> +    for (i = 0; i < list->count; i++) {
> +        if (list->devs[i]->adapter == dev->adapter &&
> +            list->devs[i]->bus == dev->bus &&
> +            list->devs[i]->target == dev->target &&
> +            list->devs[i]->unit == dev->unit)
> +            return list->devs[i];
> +    }
> +
> +    return NULL;
> +}
> diff --git a/src/util/virscsi.h b/src/util/virscsi.h
> new file mode 100644
> index 0000000..fbf143c
> --- /dev/null
> +++ b/src/util/virscsi.h
> @@ -0,0 +1,83 @@
> +/*
> + * virscsi.h: helper APIs for managing host SCSI devices
> + *
> + * Copyright (C) 2013 Fujitsu, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + *     Han Cheng <hanc.fnst at cn.fujitsu.com>
> + */
> +
> +#ifndef __VIR_SCSI_H__
> +# define __VIR_SCSI_H__
> +
> +# include "internal.h"
> +# include "virobject.h"
> +
> +typedef struct _virSCSIDevice virSCSIDevice;
> +typedef virSCSIDevice *virSCSIDevicePtr;
> +typedef struct _virSCSIDeviceList virSCSIDeviceList;
> +typedef virSCSIDeviceList *virSCSIDeviceListPtr;
> +
> +char *virSCSIDeviceGetDevStr(char *adapter,
> +                            unsigned int bus,
> +                            unsigned int target,
> +                            unsigned int unit);
> +
> +virSCSIDevicePtr virSCSIDeviceNew(char *adapter,
> +                                  unsigned int bus,
> +                                  unsigned int target,
> +                                  unsigned int unit,
> +                                  unsigned int readonly);

I'm wondering if we can abstract a common list object, at least we can 
reduce the
redundant code in virpci.c, virusb.c, virscsi.c. But it can be future 
patch.

> +
> +void virSCSIDeviceFree(virSCSIDevicePtr dev);
> +void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name);
> +const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev);
> +const char *virSCSIDeviceGetName(virSCSIDevicePtr dev);
> +unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev);
> +unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev);
> +unsigned int virSCSIDeviceGetTarget(virSCSIDevicePtr dev);
> +unsigned int virSCSIDeviceGetUnit(virSCSIDevicePtr dev);
> +unsigned int virSCSIDeviceGetReadonly(virSCSIDevicePtr dev);
> +
> +/*
> + * Callback that will be invoked once for each file
> + * associated with / used for SCSI host device access.
> + *
> + * Should return 0 if successfully processed, or
> + * -1 to indicate error and abort iteration
> + */
> +typedef int (*virSCSIDeviceFileActor)(virSCSIDevicePtr dev,
> +                                      const char *path, void *opaque);
> +
> +int virSCSIDeviceFileIterate(virSCSIDevicePtr dev,
> +                             virSCSIDeviceFileActor actor,
> +                             void *opaque);
> +
> +virSCSIDeviceListPtr virSCSIDeviceListNew(void);
> +int virSCSIDeviceListAdd(virSCSIDeviceListPtr list,
> +                         virSCSIDevicePtr dev);
> +virSCSIDevicePtr virSCSIDeviceListGet(virSCSIDeviceListPtr list,
> +                                      int idx);
> +int virSCSIDeviceListCount(virSCSIDeviceListPtr list);
> +virSCSIDevicePtr virSCSIDeviceListSteal(virSCSIDeviceListPtr list,
> +                                        virSCSIDevicePtr dev);
> +void virSCSIDeviceListDel(virSCSIDeviceListPtr list,
> +                          virSCSIDevicePtr dev);
> +virSCSIDevicePtr virSCSIDeviceListFind(virSCSIDeviceListPtr list,
> +                                       virSCSIDevicePtr dev);
> +
> +#endif /* __VIR_SCSI_H__ */




More information about the libvir-list mailing list