[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