This patch adds util functions for scsi hostdev.
Signed-off-by: Han Cheng <hanc.fnst(a)cn.fujitsu.com>
---
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/libvirt_private.syms | 22 +++
src/util/virscsi.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/virscsi.h | 83 ++++++++++
5 files changed, 499 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 fc6b846..97eeef6 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 449696d..24c4a61 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1666,6 +1666,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..d80c55f
--- /dev/null
+++ b/src/util/virscsi.c
@@ -0,0 +1,392 @@
+/*
+ * 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(a)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 SYSFS_SCSI_DEVICES "/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 cleanup;
+
+ if (virAsprintf(&path,
+ SYSFS_SCSI_DEVICES "/%d:%d:%d:%d/scsi_generic",
+ adapterid, bus, target, unit) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (!(dir = opendir(path))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to open %s"), path);
+ goto cleanup;
+ }
+
+ while ((entry = readdir(dir))) {
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (virAsprintf(&sg, "%s", entry->d_name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ 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, ret = NULL;
+ 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 cleanup;
+ if (virSCSIDeviceGetAdapterId(adapter, &dev->adapter) < 0)
+ goto cleanup;
+ if (virAsprintf(&dev->name, "%d:%d:%d:%d",
+ dev->adapter, dev->bus, dev->bus,
+ dev->unit) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (virAsprintf(&dev->path, "/dev/%s", sg) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (access(dev->path, F_OK) != 0) {
+ virReportSystemError(errno,
+ _("Device %s not found: could not access %s"),
+ dev->name, dev->path);
+ goto cleanup;
+ }
+ if (virAsprintf(&tmp, SYSFS_SCSI_DEVICES "/%s/vendor", dev->name)
< 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (virFileReadAll(tmp, 1024, &vendor) < 0)
+ goto cleanup;
+ virTrimSpaces(vendor, NULL);
+ VIR_FREE(tmp);
+ tmp = NULL;
+ if (virAsprintf(&tmp, SYSFS_SCSI_DEVICES "/%s/model", dev->name)
< 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (virFileReadAll(tmp, 1024, &model) < 0)
+ goto cleanup;
+ virTrimSpaces(model, NULL);
+ if (virAsprintf(&dev->id, "%s %s", vendor, model) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
+
+ ret = dev;
+
+cleanup:
+ VIR_FREE(tmp);
+ VIR_FREE(vendor);
+ VIR_FREE(model);
+ if (!ret)
+ virSCSIDeviceFree(dev);
+ 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 already exists"),
+ 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..1c0c00e
--- /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(a)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);
+
+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