This patch add util functions for scsi hostdev. Signed-off-by: Han Cheng <hanc.fnst@xxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxx> + */ + +#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" + +/* 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) +{ + 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 (virSCSIDeviceGetAdapterId(adapter, &dev->adapter) < 0) { + goto out; + } + 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'; + *(model + strlen(model) - 1) = '\0'; + if (virAsprintf(&dev->id, "%s %s", vendor, model) < 0) { + virReportOOMError(); + goto out; + } + VIR_FREE(tmp); + VIR_FREE(vendor); + VIR_FREE(model); + + VIR_DEBUG("%s %s: initialized", dev->id, dev->name); + + return dev; + +out: + VIR_FREE(tmp); + VIR_FREE(vendor); + VIR_FREE(model); + virSCSIDeviceFree(dev); + return NULL; +} + +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"), + 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@xxxxxxxxxxxxxx> + */ + +#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); + +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__ */ -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list