]> xenbits.xensource.com Git - libvirt.git/commitdiff
utils: util functions for scsi hostdev
authorHan Cheng <hanc.fnst@cn.fujitsu.com>
Fri, 3 May 2013 18:07:22 +0000 (02:07 +0800)
committerOsier Yang <jyang@redhat.com>
Mon, 13 May 2013 10:40:50 +0000 (18:40 +0800)
This patch adds util functions for scsi hostdev.

Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
po/POTFILES.in
src/Makefile.am
src/libvirt_private.syms
src/util/virscsi.c [new file with mode: 0644]
src/util/virscsi.h [new file with mode: 0644]

index bf5a864199faf5e964216cb19ecfc79318696352..f3ea4da07a3a8a0572979502457df9934546cedc 100644 (file)
@@ -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
index fd0b4765f75dcf0dccfb540f32c1d9ab7ec279a3..4312c3c17d21d562a63141d6b46e054c6d1456c8 100644 (file)
@@ -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       \
index ef65a8be38e782c454c0791f83bc2bdbd4ceb42d..d38d17dd9a3069bb0a0c3595a179346f0cd7b2a1 100644 (file)
@@ -1721,6 +1721,28 @@ virRandomGenerateWWN;
 virRandomInt;
 
 
+# util/virscsi.h
+virSCSIDeviceFileIterate;
+virSCSIDeviceFree;
+virSCSIDeviceGetAdapter;
+virSCSIDeviceGetBus;
+virSCSIDeviceGetName;
+virSCSIDeviceGetReadonly;
+virSCSIDeviceGetSgName;
+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 (file)
index 0000000..d6685fa
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * 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@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 "virfile.h"
+#include "virutil.h"
+#include "virstring.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 *sg_path; /* e.g. /dev/sg2 */
+    const char *used_by; /* name of the domain using this dev */
+
+    bool readonly;
+};
+
+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(const char *adapter,
+                          unsigned int *adapter_id)
+{
+    if (STRPREFIX(adapter, "scsi_host")) {
+        if (virStrToLong_ui(adapter + strlen("scsi_host"),
+                            NULL, 0, adapter_id) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Cannot parse adapter '%s'"), adapter);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+char *
+virSCSIDeviceGetSgName(const 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 adapter_id;
+
+    if (virSCSIDeviceGetAdapterId(adapter, &adapter_id) < 0)
+        return NULL;
+
+    if (virAsprintf(&path,
+                    SYSFS_SCSI_DEVICES "/%d:%d:%d:%d/scsi_generic",
+                    adapter_id, bus, target, unit) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    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 (VIR_STRDUP(sg, entry->d_name) < 0)
+            goto cleanup;
+    }
+
+cleanup:
+    closedir(dir);
+    VIR_FREE(path);
+    return sg;
+}
+
+virSCSIDevicePtr
+virSCSIDeviceNew(const char *adapter,
+                 unsigned int bus,
+                 unsigned int target,
+                 unsigned int unit,
+                 bool readonly)
+{
+    virSCSIDevicePtr dev, ret = NULL;
+    char *sg = NULL;
+    char *vendor_path = NULL;
+    char *model_path = NULL;
+    char *vendor = NULL;
+    char *model = NULL;
+
+    if (VIR_ALLOC(dev) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    dev->bus = bus;
+    dev->target = target;
+    dev->unit = unit;
+    dev->readonly = readonly;
+
+    if (!(sg = virSCSIDeviceGetSgName(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 ||
+        virAsprintf(&dev->sg_path, "/dev/%s", sg) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (access(dev->sg_path, F_OK) != 0) {
+        virReportSystemError(errno,
+                             _("SCSI device '%s': could not access %s"),
+                             dev->name, dev->sg_path);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&vendor_path,
+                    SYSFS_SCSI_DEVICES "/%s/vendor", dev->name) < 0 ||
+        virAsprintf(&model_path,
+                    SYSFS_SCSI_DEVICES "/%s/model", dev->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virFileReadAll(vendor_path, 1024, &vendor) < 0)
+        goto cleanup;
+
+    if (virFileReadAll(model_path, 1024, &model) < 0)
+        goto cleanup;
+
+    virTrimSpaces(vendor, NULL);
+    virTrimSpaces(model, NULL);
+
+    if (virAsprintf(&dev->id, "%s:%s", vendor, model) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    ret = dev;
+cleanup:
+    VIR_FREE(sg);
+    VIR_FREE(vendor);
+    VIR_FREE(model);
+    VIR_FREE(vendor_path);
+    VIR_FREE(model_path);
+    if (!ret)
+        virSCSIDeviceFree(dev);
+    return ret;
+}
+
+void
+virSCSIDeviceFree(virSCSIDevicePtr dev)
+{
+    if (!dev)
+        return;
+
+    VIR_FREE(dev->id);
+    VIR_FREE(dev->name);
+    VIR_FREE(dev->sg_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;
+}
+
+bool
+virSCSIDeviceGetReadonly(virSCSIDevicePtr dev)
+{
+    return dev->readonly;
+}
+
+int
+virSCSIDeviceFileIterate(virSCSIDevicePtr dev,
+                         virSCSIDeviceFileActor actor,
+                         void *opaque)
+{
+    return (actor)(dev, dev->sg_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 (file)
index 0000000..8268cdf
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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@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 *virSCSIDeviceGetSgName(const char *adapter,
+                             unsigned int bus,
+                             unsigned int target,
+                             unsigned int unit);
+
+virSCSIDevicePtr virSCSIDeviceNew(const char *adapter,
+                                  unsigned int bus,
+                                  unsigned int target,
+                                  unsigned int unit,
+                                  bool 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);
+bool 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__ */