From: Clementine Hayat <clem@lse.epita.fr>
We need here libiscsi for the storgae pool backend.
For the iscsi-direct storage pool, only checkPool and refreshPool should
be necessary.
The pool is state-less and just need the informations within the volume
to work.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr>
---
m4/virt-storage-iscsi-direct.m4 | 3 +
src/storage/Makefile.inc.am | 3 +
src/storage/storage_backend_iscsi_direct.c | 407 ++++++++++++++++++++-
3 files changed, 410 insertions(+), 3 deletions(-)
diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4
index cc2d490352..dab4414169 100644
--- a/m4/virt-storage-iscsi-direct.m4
+++ b/m4/virt-storage-iscsi-direct.m4
@@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [
with_storage_iscsi_direct=$with_libiscsi
fi
if test "$with_storage_iscsi_direct" = "yes"; then
+ if test "$with_libiscsi" = "no"; then
+ AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver])
+ fi
AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1],
[whether iSCSI backend for storage driver is enabled])
fi
diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am
index d81864f5b9..bd5ea06f8b 100644
--- a/src/storage/Makefile.inc.am
+++ b/src/storage/Makefile.inc.am
@@ -202,6 +202,8 @@ endif WITH_STORAGE_ISCSI
if WITH_STORAGE_ISCSI_DIRECT
libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES)
libvirt_storage_backend_iscsi_direct_la_CFLAGS = \
+ -I$(srcdir)/conf \
+ -I$(srcdir)/secret \
$(LIBISCSI_CFLAGS) \
$(AM_CFLAGS) \
$(NULL)
@@ -210,6 +212,7 @@ storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la
libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD)
libvirt_storage_backend_iscsi_direct_la_LIBADD = \
libvirt.la \
+ $(LIBISCSI_LIBS) \
../gnulib/lib/libgnu.la \
$(NULL)
endif WITH_STORAGE_ISCSI_DIRECT
diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c
index e3c1f75b42..f93c8e1e67 100644
--- a/src/storage/storage_backend_iscsi_direct.c
+++ b/src/storage/storage_backend_iscsi_direct.c
@@ -1,34 +1,435 @@
#include <config.h>
#include <fcntl.h>
+#include <iscsi/iscsi.h>
+#include <iscsi/scsi-lowlevel.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include "datatypes.h"
#include "driver.h"
+#include "secret_util.h"
#include "storage_backend_iscsi_direct.h"
#include "storage_util.h"
+#include "viralloc.h"
+#include "vircommand.h"
+#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
#include "virobject.h"
+#include "virstring.h"
+#include "virtime.h"
+#include "viruuid.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
+#define ISCSI_DEFAULT_TARGET_PORT 3260
+#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000
+
VIR_LOG_INIT("storage.storage_backend_iscsi_direct");
+static struct iscsi_context *
+virISCSIDirectCreateContext(const char* initiator_iqn)
+{
+ struct iscsi_context *iscsi = NULL;
+
+ iscsi = iscsi_create_context(initiator_iqn);
+ if (!iscsi)
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to create iscsi context for %s"),
+ initiator_iqn);
+ return iscsi;
+}
+
+static char *
+virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source)
+{
+ char *portal = NULL;
+
+ if (source->nhost != 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Expected exactly 1 host for the storage pool"));
+ return NULL;
+ }
+ if (source->hosts[0].port == 0) {
+ ignore_value(virAsprintf(&portal, "%s:%d",
+ source->hosts[0].name,
+ ISCSI_DEFAULT_TARGET_PORT));
+ } else if (strchr(source->hosts[0].name, ':')) {
+ ignore_value(virAsprintf(&portal, "[%s]:%d",
+ source->hosts[0].name,
+ source->hosts[0].port));
+ } else {
+ ignore_value(virAsprintf(&portal, "%s:%d",
+ source->hosts[0].name,
+ source->hosts[0].port));
+ }
+ return portal;
+}
+
+static int
+virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi,
+ virStoragePoolSourcePtr source)
+{
+ unsigned char *secret_value = NULL;
+ size_t secret_size;
+ virStorageAuthDefPtr authdef = source->auth;
+ int ret = -1;
+ virConnectPtr conn = NULL;
+
+ if (!authdef || authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE)
+ return 0;
+
+ VIR_DEBUG("username='%s' authType=%d seclookupdef.type=%d",
+ authdef->username, authdef->authType, authdef->seclookupdef.type);
+
+ if (authdef->authType != VIR_STORAGE_AUTH_TYPE_CHAP) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("iscsi-direct pool only supports 'chap' auth type"));
+ return ret;
+ }
+
+ if (!(conn = virGetConnectSecret()))
+ return ret;
+
+ if (virSecretGetSecretString(conn, &authdef->seclookupdef,
+ VIR_SECRET_USAGE_TYPE_ISCSI,
+ &secret_value, &secret_size) < 0)
+ goto cleanup;
+
+ if (iscsi_set_initiator_username_pwd(iscsi,
+ authdef->username,
+ (const char *)secret_value) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to set credential: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_DISPOSE_N(secret_value, secret_size);
+ virObjectUnref(conn);
+ return ret;
+}
+
+static int
+virISCSIDirectSetContext(struct iscsi_context *iscsi,
+ const char *target_name)
+{
+ if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to init transport: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
+ if (iscsi_set_targetname(iscsi, target_name) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to set target name: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
+ if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to set session type: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
+ return 0;
+}
static int
-virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
- bool *isActive ATTRIBUTE_UNUSED)
+virISCSIDirectConnect(struct iscsi_context *iscsi,
+ const char *portal)
{
+ if (iscsi_connect_sync(iscsi, portal) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to connect: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
+ if (iscsi_login_sync(iscsi) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to login: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
return 0;
}
+static struct scsi_reportluns_list *
+virISCSIDirectReportLuns(struct iscsi_context *iscsi)
+{
+ struct scsi_task *task = NULL;
+ struct scsi_reportluns_list *list = NULL;
+ int full_size;
+
+ if (!(task = iscsi_reportluns_sync(iscsi, 0, 16))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to reportluns: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ full_size = scsi_datain_getfullsize(task);
+
+ if (full_size > task->datain.size) {
+ scsi_free_scsi_task(task);
+ if (!(task = iscsi_reportluns_sync(iscsi, 0, full_size))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to reportluns: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+ }
+
+ if (!(list = scsi_datain_unmarshall(task))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to unmarshall reportluns: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ cleanup:
+ scsi_free_scsi_task(task);
+ return list;
+}
+
static int
-virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
+virISCSIDirectTestUnitReady(struct iscsi_context *iscsi,
+ int lun)
{
+ struct scsi_task *task = NULL;
+ int ret = -1;
+ virTimeBackOffVar timebackoff;
+
+ if (virTimeBackOffStart(&timebackoff, 1,
+ VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0)
+ goto cleanup;
+
+ do {
+ if (!(task = iscsi_testunitready_sync(iscsi, lun))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed testunitready: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ if (task->status != SCSI_STATUS_CHECK_CONDITION ||
+ task->sense.key != SCSI_SENSE_UNIT_ATTENTION ||
+ task->sense.ascq != SCSI_SENSE_ASCQ_BUS_RESET)
+ break;
+
+ scsi_free_scsi_task(task);
+ } while (virTimeBackOffWait(&timebackoff));
+
+ if (task->status != SCSI_STATUS_GOOD) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed testunitready: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ scsi_free_scsi_task(task);
+ return ret;
+}
+
+static int
+virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ int lun,
+ char *portal)
+{
+ virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
+
+ if (virAsprintf(&vol->name, "%u", lun) < 0)
+ return -1;
+ if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal,
+ def->source.devices[0].path, lun) < 0)
+ return -1;
+ if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal,
+ def->source.devices[0].path, lun) < 0)
+ return -1;
return 0;
}
+static int
+virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi,
+ virStorageVolDefPtr vol, int lun)
+{
+ struct scsi_task *task = NULL;
+ struct scsi_inquiry_standard *inq = NULL;
+ long long size = 0;
+ int ret = -1;
+
+ if (!(task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) ||
+ task->status != SCSI_STATUS_GOOD) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to send inquiry command: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ if (!(inq = scsi_datain_unmarshall(task))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to unmarshall reply: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ if (inq->device_type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) {
+ struct scsi_readcapacity10 *rc10 = NULL;
+
+ scsi_free_scsi_task(task);
+ task = NULL;
+
+ if (!(task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) ||
+ task->status != SCSI_STATUS_GOOD) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get capacity of lun: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ if (!(rc10 = scsi_datain_unmarshall(task))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to unmarshall reply: %s"),
+ iscsi_get_error(iscsi));
+ goto cleanup;
+ }
+
+ size = rc10->block_size;
+ size *= rc10->lba;
+ vol->target.capacity = size;
+ vol->target.allocation = size;
+
+ }
+
+ ret = 0;
+ cleanup:
+ scsi_free_scsi_task(task);
+ return ret;
+}
+
+static int
+virISCSIDirectRefreshVol(virStoragePoolObjPtr pool,
+ struct iscsi_context *iscsi,
+ int lun,
+ char *portal)
+{
+ virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
+ virStorageVolDefPtr vol = NULL;
+ int ret = -1;
+
+ virStoragePoolObjClearVols(pool);
+ if (virISCSIDirectTestUnitReady(iscsi, lun) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC(vol) < 0)
+ goto cleanup;
+
+ vol->type = VIR_STORAGE_VOL_NETWORK;
+
+ if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0)
+ goto cleanup;
+
+ def->capacity += vol->target.capacity;
+ def->allocation += vol->target.allocation;
+
+ if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0)
+ goto cleanup;
+
+ if (virStoragePoolObjAddVol(pool, vol) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to create volume: %d"),
+ lun);
+ goto cleanup;
+ }
+ vol = NULL;
+
+ ret = 0;
+ cleanup:
+ virStorageVolDefFree(vol);
+ return ret;
+}
+
+static int
+virStorageBackendISCSIDirectRefreshVols(virStoragePoolObjPtr pool,
+ struct iscsi_context *iscsi,
+ char *portal)
+{
+ struct scsi_reportluns_list *list = NULL;
+ size_t i;
+
+ if (!(list = virISCSIDirectReportLuns(iscsi)))
+ return -1;
+ for (i = 0; i < list->num; i++) {
+ if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+virISCSIDirectDisconnect(struct iscsi_context *iscsi)
+{
+ if (iscsi_logout_sync(iscsi) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to logout: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
+ if (iscsi_disconnect(iscsi) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to disconnect: %s"),
+ iscsi_get_error(iscsi));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool,
+ bool *isActive)
+{
+ *isActive = virStoragePoolObjIsActive(pool);
+ return 0;
+}
+
+static int
+virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool)
+{
+ virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
+ struct iscsi_context *iscsi = NULL;
+ char *portal = NULL;
+ int ret = -1;
+
+ if (!(iscsi = virISCSIDirectCreateContext(def->source.initiator.iqn)))
+ goto cleanup;
+ if (!(portal = virStorageBackendISCSIDirectPortal(&def->source)))
+ goto cleanup;
+ if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0)
+ goto cleanup;
+ if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0)
+ goto cleanup;
+ if (virISCSIDirectConnect(iscsi, portal) < 0)
+ goto cleanup;
+ if (virStorageBackendISCSIDirectRefreshVols(pool, iscsi, portal) < 0)
+ goto disconect;
+
+ ret = 0;
+ disconect:
+ virISCSIDirectDisconnect(iscsi);
+ cleanup:
+ iscsi_destroy_context(iscsi);
+ VIR_FREE(portal);
+ return ret;
+}
+
virStorageBackend virStorageBackendISCSIDirect = {
.type = VIR_STORAGE_POOL_ISCSI_DIRECT,
--
2.17.1
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On Sat, 14 Jul 2018 00:06:15 +0200 clem@lse.epita.fr wrote: > From: Clementine Hayat <clem@lse.epita.fr> > > We need here libiscsi for the storgae pool backend. > For the iscsi-direct storage pool, only checkPool and refreshPool should > be necessary. > The pool is state-less and just need the informations within the volume > to work. > > Signed-off-by: Clementine Hayat <clem@lse.epita.fr> > --- > m4/virt-storage-iscsi-direct.m4 | 3 + > src/storage/Makefile.inc.am | 3 + > src/storage/storage_backend_iscsi_direct.c | 407 ++++++++++++++++++++- > 3 files changed, 410 insertions(+), 3 deletions(-) > > diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 > index cc2d490352..dab4414169 100644 > --- a/m4/virt-storage-iscsi-direct.m4 > +++ b/m4/virt-storage-iscsi-direct.m4 > @@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ > with_storage_iscsi_direct=$with_libiscsi > fi > if test "$with_storage_iscsi_direct" = "yes"; then > + if test "$with_libiscsi" = "no"; then > + AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver]) > + fi > AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], > [whether iSCSI backend for storage driver is enabled]) > fi > diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am > index d81864f5b9..bd5ea06f8b 100644 > --- a/src/storage/Makefile.inc.am > +++ b/src/storage/Makefile.inc.am > @@ -202,6 +202,8 @@ endif WITH_STORAGE_ISCSI > if WITH_STORAGE_ISCSI_DIRECT > libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) > libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ > + -I$(srcdir)/conf \ > + -I$(srcdir)/secret \ > $(LIBISCSI_CFLAGS) \ > $(AM_CFLAGS) \ > $(NULL) > @@ -210,6 +212,7 @@ storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la > libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) > libvirt_storage_backend_iscsi_direct_la_LIBADD = \ > libvirt.la \ > + $(LIBISCSI_LIBS) \ > ../gnulib/lib/libgnu.la \ > $(NULL) > endif WITH_STORAGE_ISCSI_DIRECT > diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c > index e3c1f75b42..f93c8e1e67 100644 > --- a/src/storage/storage_backend_iscsi_direct.c > +++ b/src/storage/storage_backend_iscsi_direct.c > @@ -1,34 +1,435 @@ > #include <config.h> > #include <fcntl.h> > +#include <iscsi/iscsi.h> > +#include <iscsi/scsi-lowlevel.h> > +#include <string.h> > #include <sys/stat.h> > #include <sys/wait.h> > #include <unistd.h> > > #include "datatypes.h" > #include "driver.h" > +#include "secret_util.h" > #include "storage_backend_iscsi_direct.h" > #include "storage_util.h" > +#include "viralloc.h" > +#include "vircommand.h" > +#include "virerror.h" > +#include "virfile.h" > #include "virlog.h" > #include "virobject.h" > +#include "virstring.h" > +#include "virtime.h" > +#include "viruuid.h" >From what I see there is a lot of unused headers here: * fcntl.h * string.h * sys/stat.h * sys/wait.h * unistd.h * driver.h * vircommand.h * virfile.h > > #define VIR_FROM_THIS VIR_FROM_STORAGE > > +#define ISCSI_DEFAULT_TARGET_PORT 3260 > +#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000 > + > VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); > > +static struct iscsi_context * > +virISCSIDirectCreateContext(const char* initiator_iqn) > +{ > + struct iscsi_context *iscsi = NULL; > + > + iscsi = iscsi_create_context(initiator_iqn); > + if (!iscsi) > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to create iscsi context for %s"), > + initiator_iqn); > + return iscsi; > +} > + > +static char * > +virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source) > +{ > + char *portal = NULL; > + > + if (source->nhost != 1) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("Expected exactly 1 host for the storage pool")); > + return NULL; > + } > + if (source->hosts[0].port == 0) { > + ignore_value(virAsprintf(&portal, "%s:%d", > + source->hosts[0].name, > + ISCSI_DEFAULT_TARGET_PORT)); > + } else if (strchr(source->hosts[0].name, ':')) { > + ignore_value(virAsprintf(&portal, "[%s]:%d", > + source->hosts[0].name, > + source->hosts[0].port)); > + } else { > + ignore_value(virAsprintf(&portal, "%s:%d", > + source->hosts[0].name, > + source->hosts[0].port)); > + } > + return portal; > +} > + > +static int > +virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi, > + virStoragePoolSourcePtr source) > +{ > + unsigned char *secret_value = NULL; > + size_t secret_size; > + virStorageAuthDefPtr authdef = source->auth; > + int ret = -1; > + virConnectPtr conn = NULL; > + > + if (!authdef || authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) > + return 0; > + > + VIR_DEBUG("username='%s' authType=%d seclookupdef.type=%d", > + authdef->username, authdef->authType, authdef->seclookupdef.type); > + > + if (authdef->authType != VIR_STORAGE_AUTH_TYPE_CHAP) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("iscsi-direct pool only supports 'chap' auth type")); > + return ret; > + } > + > + if (!(conn = virGetConnectSecret())) > + return ret; > + > + if (virSecretGetSecretString(conn, &authdef->seclookupdef, > + VIR_SECRET_USAGE_TYPE_ISCSI, > + &secret_value, &secret_size) < 0) > + goto cleanup; > + > + if (iscsi_set_initiator_username_pwd(iscsi, > + authdef->username, > + (const char *)secret_value) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to set credential: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + ret = 0; > + cleanup: > + VIR_DISPOSE_N(secret_value, secret_size); > + virObjectUnref(conn); > + return ret; > +} > + > +static int > +virISCSIDirectSetContext(struct iscsi_context *iscsi, > + const char *target_name) > +{ > + if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to init transport: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > + if (iscsi_set_targetname(iscsi, target_name) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to set target name: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to set session type: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > + return 0; > +} > > static int > -virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, > - bool *isActive ATTRIBUTE_UNUSED) > +virISCSIDirectConnect(struct iscsi_context *iscsi, > + const char *portal) > { > + if (iscsi_connect_sync(iscsi, portal) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to connect: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > + if (iscsi_login_sync(iscsi) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to login: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > return 0; > } > > +static struct scsi_reportluns_list * > +virISCSIDirectReportLuns(struct iscsi_context *iscsi) > +{ > + struct scsi_task *task = NULL; > + struct scsi_reportluns_list *list = NULL; > + int full_size; > + > + if (!(task = iscsi_reportluns_sync(iscsi, 0, 16))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to reportluns: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + full_size = scsi_datain_getfullsize(task); > + > + if (full_size > task->datain.size) { > + scsi_free_scsi_task(task); > + if (!(task = iscsi_reportluns_sync(iscsi, 0, full_size))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to reportluns: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + } > + > + if (!(list = scsi_datain_unmarshall(task))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to unmarshall reportluns: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + cleanup: > + scsi_free_scsi_task(task); > + return list; > +} > + > static int > -virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) > +virISCSIDirectTestUnitReady(struct iscsi_context *iscsi, > + int lun) > { > + struct scsi_task *task = NULL; > + int ret = -1; > + virTimeBackOffVar timebackoff; > + > + if (virTimeBackOffStart(&timebackoff, 1, > + VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0) > + goto cleanup; > + > + do { > + if (!(task = iscsi_testunitready_sync(iscsi, lun))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed testunitready: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + if (task->status != SCSI_STATUS_CHECK_CONDITION || > + task->sense.key != SCSI_SENSE_UNIT_ATTENTION || > + task->sense.ascq != SCSI_SENSE_ASCQ_BUS_RESET) > + break; > + > + scsi_free_scsi_task(task); > + } while (virTimeBackOffWait(&timebackoff)); > + > + if (task->status != SCSI_STATUS_GOOD) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed testunitready: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + ret = 0; > + cleanup: > + scsi_free_scsi_task(task); > + return ret; > +} > + > +static int > +virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool, > + virStorageVolDefPtr vol, > + int lun, > + char *portal) > +{ > + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); > + > + if (virAsprintf(&vol->name, "%u", lun) < 0) > + return -1; > + if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal, > + def->source.devices[0].path, lun) < 0) > + return -1; > + if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal, > + def->source.devices[0].path, lun) < 0) > + return -1; > return 0; > } > > +static int > +virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi, > + virStorageVolDefPtr vol, int lun) > +{ > + struct scsi_task *task = NULL; > + struct scsi_inquiry_standard *inq = NULL; > + long long size = 0; > + int ret = -1; > + > + if (!(task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) || > + task->status != SCSI_STATUS_GOOD) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to send inquiry command: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + if (!(inq = scsi_datain_unmarshall(task))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to unmarshall reply: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + if (inq->device_type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { > + struct scsi_readcapacity10 *rc10 = NULL; > + > + scsi_free_scsi_task(task); > + task = NULL; > + > + if (!(task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) || > + task->status != SCSI_STATUS_GOOD) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to get capacity of lun: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + if (!(rc10 = scsi_datain_unmarshall(task))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to unmarshall reply: %s"), > + iscsi_get_error(iscsi)); > + goto cleanup; > + } > + > + size = rc10->block_size; > + size *= rc10->lba; > + vol->target.capacity = size; > + vol->target.allocation = size; > + > + } > + > + ret = 0; > + cleanup: > + scsi_free_scsi_task(task); > + return ret; > +} > + > +static int > +virISCSIDirectRefreshVol(virStoragePoolObjPtr pool, > + struct iscsi_context *iscsi, > + int lun, > + char *portal) > +{ > + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); > + virStorageVolDefPtr vol = NULL; > + int ret = -1; > + > + virStoragePoolObjClearVols(pool); > + if (virISCSIDirectTestUnitReady(iscsi, lun) < 0) > + goto cleanup; > + > + if (VIR_ALLOC(vol) < 0) > + goto cleanup; > + > + vol->type = VIR_STORAGE_VOL_NETWORK; > + > + if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0) > + goto cleanup; > + > + def->capacity += vol->target.capacity; > + def->allocation += vol->target.allocation; > + > + if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0) > + goto cleanup; > + > + if (virStoragePoolObjAddVol(pool, vol) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to create volume: %d"), > + lun); > + goto cleanup; > + } > + vol = NULL; > + > + ret = 0; > + cleanup: > + virStorageVolDefFree(vol); > + return ret; > +} > + > +static int > +virStorageBackendISCSIDirectRefreshVols(virStoragePoolObjPtr pool, > + struct iscsi_context *iscsi, > + char *portal) > +{ > + struct scsi_reportluns_list *list = NULL; > + size_t i; > + > + if (!(list = virISCSIDirectReportLuns(iscsi))) > + return -1; > + for (i = 0; i < list->num; i++) { > + if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) < 0) > + return -1; > + } > + > + return 0; > +} > + > +static int > +virISCSIDirectDisconnect(struct iscsi_context *iscsi) > +{ > + if (iscsi_logout_sync(iscsi) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to logout: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > + if (iscsi_disconnect(iscsi) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to disconnect: %s"), > + iscsi_get_error(iscsi)); > + return -1; > + } > + return 0; > +} > + > +static int > +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool, > + bool *isActive) > +{ > + *isActive = virStoragePoolObjIsActive(pool); > + return 0; > +} > + > +static int > +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool) > +{ > + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); > + struct iscsi_context *iscsi = NULL; > + char *portal = NULL; > + int ret = -1; > + > + if (!(iscsi = virISCSIDirectCreateContext(def->source.initiator.iqn))) > + goto cleanup; > + if (!(portal = virStorageBackendISCSIDirectPortal(&def->source))) > + goto cleanup; > + if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0) > + goto cleanup; > + if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0) > + goto cleanup; > + if (virISCSIDirectConnect(iscsi, portal) < 0) > + goto cleanup; > + if (virStorageBackendISCSIDirectRefreshVols(pool, iscsi, portal) < 0) > + goto disconect; > + > + ret = 0; > + disconect: > + virISCSIDirectDisconnect(iscsi); > + cleanup: > + iscsi_destroy_context(iscsi); > + VIR_FREE(portal); > + return ret; Here, the cleanup code is not the complete opposite of the initialisation side. Just for clarity: cleanup: VIR_FREE(portal); iscsi_destroy_context(iscsi); return ret; > +} > + > virStorageBackend virStorageBackendISCSIDirect = { > .type = VIR_STORAGE_POOL_ISCSI_DIRECT, > -- Gabriel Laskar -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2025 Red Hat, Inc.