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

Han Cheng hanc.fnst at cn.fujitsu.com
Mon Apr 1 12:00:57 UTC 2013


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"
+
+/* 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 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);
+
+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




More information about the libvir-list mailing list