76daa3
From 1b7bbc5ff814406dfe9f64203462d92d8f71ef3a Mon Sep 17 00:00:00 2001
76daa3
From: Jeffrey Cody <jcody@redhat.com>
76daa3
Date: Mon, 8 May 2017 22:11:16 +0200
76daa3
Subject: [PATCH 6/7] block/vxhs: modularize VXHS via g_module
76daa3
76daa3
RH-Author: Jeffrey Cody <jcody@redhat.com>
76daa3
Message-id: <8a91a423440b7a5a14e868279c772e99b865bfc6.1494281291.git.jcody@redhat.com>
76daa3
Patchwork-id: 75046
76daa3
O-Subject: [RHEV-7.4 qemu-kvm-rhev 4/4] block/vxhs: modularize VXHS via g_module
76daa3
Bugzilla: 1265869
76daa3
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
76daa3
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
76daa3
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
76daa3
This converts the VXHS driver to be a runtime loaded module, with no
76daa3
external build dependencies on libvxhs / libqnio.   This (libvxhs) is a
76daa3
3rd party library, written by Veritas, to interface with the VXHS
76daa3
server.
76daa3
76daa3
Red Hat is not going to distribute libvxhs, nor will Red Hat use libvxhs
76daa3
in the build systems.  So that creates two criteria for the
76daa3
modularization, for business reasons:
76daa3
76daa3
1. No runtime dependencies on libvxhs (aside from opening the library on
76daa3
vxhs open)
76daa3
76daa3
2. No build dependencies on libvxhs packages.
76daa3
76daa3
There is support in QEMU for modular block drivers, however there are
76daa3
two issues with using the built-in support:
76daa3
76daa3
    A. It is all-or-none; if modules are enabled all protocols are built
76daa3
       as modules.  This wouldn't be that bad, as it would of course
76daa3
       enable more granular dependencies for qemu rpm packages. But...
76daa3
76daa3
    B. It is not designed with criteria #2 in mind; it reduces runtime
76daa3
       dependencies, not build dependencies.  The protocol libraries
76daa3
       that are still built linked against external libraries and using
76daa3
       external headers.
76daa3
76daa3
This patch uses g_module to load the libvxhs library, and incorporates
76daa3
the libvxhs.h header in the build tree.  If block driver protocols are
76daa3
also built as modules, libvxhs will still work and be built as a module
76daa3
too, except the shared library will still not have any dependency on
76daa3
libvxhs.
76daa3
76daa3
There are a few changes in this patch from upstream (aside from the
76daa3
module loading aspects):
76daa3
76daa3
1. It enables VXHS support to be built as a protocl module if
76daa3
--enable-modules is used during configure.
76daa3
76daa3
2. If the init call to iio_init() fails, populate errp with a
76daa3
meaningful error message.
76daa3
76daa3
3. Since we are loading the library dynamically, make check the min and
76daa3
max supported versions in the libvxhs library on load.
76daa3
76daa3
Patches for items #1 and #2 have been posted upstream.
76daa3
76daa3
It is expected that the libvxhs library is located at the following
76daa3
pathname: /usr/lib64/qemu/libvxhs.so.1
76daa3
76daa3
VXHS support is only built for x86_64 in RHEV.
76daa3
76daa3
Signed-off-by: Jeff Cody <jcody@redhat.com>
76daa3
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
---
76daa3
 block/vxhs.c                  | 122 +++++++++++++++++++++++++++++++----
76daa3
 configure                     |  33 +---------
76daa3
 include/block/vxhs_shim.h     | 143 ++++++++++++++++++++++++++++++++++++++++++
76daa3
 redhat/build_configure.sh     |   9 ++-
76daa3
 redhat/qemu-kvm.spec.template |   7 +++
76daa3
 5 files changed, 272 insertions(+), 42 deletions(-)
76daa3
 create mode 100644 include/block/vxhs_shim.h
76daa3
76daa3
diff --git a/block/vxhs.c b/block/vxhs.c
76daa3
index 9ffe9d3..fbce83e 100644
76daa3
--- a/block/vxhs.c
76daa3
+++ b/block/vxhs.c
76daa3
@@ -9,7 +9,8 @@
76daa3
  */
76daa3
 
76daa3
 #include "qemu/osdep.h"
76daa3
-#include <qnio/qnio_api.h>
76daa3
+#include "block/vxhs_shim.h"
76daa3
+#include <gmodule.h>
76daa3
 #include <sys/param.h>
76daa3
 #include "block/block_int.h"
76daa3
 #include "qapi/qmp/qerror.h"
76daa3
@@ -58,6 +59,96 @@ typedef struct BDRVVXHSState {
76daa3
     char *tlscredsid; /* tlscredsid */
76daa3
 } BDRVVXHSState;
76daa3
 
76daa3
+#define LIBVXHS_FULL_PATHNAME "/usr/lib64/qemu/libvxhs.so.1"
76daa3
+static bool libvxhs_loaded;
76daa3
+static GModule *libvxhs_handle;
76daa3
+
76daa3
+static LibVXHSFuncs libvxhs;
76daa3
+
76daa3
+typedef struct LibVXHSSymbols {
76daa3
+    const char *name;
76daa3
+    gpointer *addr;
76daa3
+} LibVXHSSymbols;
76daa3
+
76daa3
+static LibVXHSSymbols libvxhs_symbols[] = {
76daa3
+    {"iio_init",        (gpointer *) &libvxhs.iio_init},
76daa3
+    {"iio_fini",        (gpointer *) &libvxhs.iio_fini},
76daa3
+    {"iio_min_version", (gpointer *) &libvxhs.iio_min_version},
76daa3
+    {"iio_max_version", (gpointer *) &libvxhs.iio_max_version},
76daa3
+    {"iio_open",        (gpointer *) &libvxhs.iio_open},
76daa3
+    {"iio_close",       (gpointer *) &libvxhs.iio_close},
76daa3
+    {"iio_writev",      (gpointer *) &libvxhs.iio_writev},
76daa3
+    {"iio_readv",       (gpointer *) &libvxhs.iio_readv},
76daa3
+    {"iio_ioctl",       (gpointer *) &libvxhs.iio_ioctl},
76daa3
+    {NULL}
76daa3
+};
76daa3
+
76daa3
+static void bdrv_vxhs_set_funcs(GModule *handle, Error **errp)
76daa3
+{
76daa3
+    int i = 0;
76daa3
+    while (libvxhs_symbols[i].name) {
76daa3
+        const char *name = libvxhs_symbols[i].name;
76daa3
+        if (!g_module_symbol(handle, name, libvxhs_symbols[i].addr)) {
76daa3
+            error_setg(errp, "%s could not be loaded from libvxhs: %s",
76daa3
+                       name, g_module_error());
76daa3
+            return;
76daa3
+        }
76daa3
+        ++i;
76daa3
+    }
76daa3
+}
76daa3
+
76daa3
+static void bdrv_vxhs_load_libs(Error **errp)
76daa3
+{
76daa3
+    Error *local_err = NULL;
76daa3
+    int32_t ver;
76daa3
+
76daa3
+    if (libvxhs_loaded) {
76daa3
+        return;
76daa3
+    }
76daa3
+
76daa3
+    if (!g_module_supported()) {
76daa3
+        error_setg(errp, "modules are not supported on this platform: %s",
76daa3
+                     g_module_error());
76daa3
+        return;
76daa3
+    }
76daa3
+
76daa3
+    libvxhs_handle = g_module_open(LIBVXHS_FULL_PATHNAME,
76daa3
+                                   G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
76daa3
+    if (!libvxhs_handle) {
76daa3
+        error_setg(errp, "error loading libvxhs: %s", g_module_error());
76daa3
+        return;
76daa3
+    }
76daa3
+
76daa3
+    g_module_make_resident(libvxhs_handle);
76daa3
+
76daa3
+    bdrv_vxhs_set_funcs(libvxhs_handle, &local_err);
76daa3
+    if (local_err) {
76daa3
+        error_propagate(errp, local_err);
76daa3
+        return;
76daa3
+    }
76daa3
+
76daa3
+    /* Now check to see if the libvxhs we are using here is supported
76daa3
+     * by the loaded version */
76daa3
+
76daa3
+    ver = (*libvxhs.iio_min_version)();
76daa3
+    if (ver > QNIO_VERSION) {
76daa3
+        error_setg(errp, "Trying to use libvxhs version %"PRId32" API, but "
76daa3
+                         "only %"PRId32" or newer is supported by %s",
76daa3
+                          QNIO_VERSION, ver, LIBVXHS_FULL_PATHNAME);
76daa3
+        return;
76daa3
+    }
76daa3
+
76daa3
+    ver = (*libvxhs.iio_max_version)();
76daa3
+    if (ver < QNIO_VERSION) {
76daa3
+        error_setg(errp, "Trying to use libvxhs version %"PRId32" API, but "
76daa3
+                         "only %"PRId32" or earlier is supported by %s",
76daa3
+                          QNIO_VERSION, ver, LIBVXHS_FULL_PATHNAME);
76daa3
+        return;
76daa3
+    }
76daa3
+
76daa3
+    libvxhs_loaded = true;
76daa3
+}
76daa3
+
76daa3
 static void vxhs_complete_aio_bh(void *opaque)
76daa3
 {
76daa3
     VXHSAIOCB *acb = opaque;
76daa3
@@ -219,7 +310,7 @@ static void vxhs_parse_filename(const char *filename, QDict *options,
76daa3
 static int vxhs_init_and_ref(void)
76daa3
 {
76daa3
     if (vxhs_ref++ == 0) {
76daa3
-        if (iio_init(QNIO_VERSION, vxhs_iio_callback)) {
76daa3
+        if ((*libvxhs.iio_init)(QNIO_VERSION, vxhs_iio_callback)) {
76daa3
             return -ENODEV;
76daa3
         }
76daa3
     }
76daa3
@@ -229,7 +320,7 @@ static int vxhs_init_and_ref(void)
76daa3
 static void vxhs_unref(void)
76daa3
 {
76daa3
     if (--vxhs_ref == 0) {
76daa3
-        iio_fini();
76daa3
+        (*libvxhs.iio_fini)();
76daa3
     }
76daa3
 }
76daa3
 
76daa3
@@ -299,8 +390,17 @@ static int vxhs_open(BlockDriverState *bs, QDict *options,
76daa3
     char *client_key = NULL;
76daa3
     char *client_cert = NULL;
76daa3
 
76daa3
+    bdrv_vxhs_load_libs(&local_err);
76daa3
+    if (local_err) {
76daa3
+        error_propagate(errp, local_err);
76daa3
+        /* on error, cannot cleanup because the iio_fini() function
76daa3
+         * is not loaded */
76daa3
+        return -EINVAL;
76daa3
+    }
76daa3
+
76daa3
     ret = vxhs_init_and_ref();
76daa3
     if (ret < 0) {
76daa3
+        error_setg(&local_err, "libvxhs iio_init() failed");
76daa3
         ret = -EINVAL;
76daa3
         goto out;
76daa3
     }
76daa3
@@ -385,8 +485,8 @@ static int vxhs_open(BlockDriverState *bs, QDict *options,
76daa3
     /*
76daa3
      * Open qnio channel to storage agent if not opened before
76daa3
      */
76daa3
-    dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0,
76daa3
-                           cacert, client_key, client_cert);
76daa3
+    dev_handlep = (*libvxhs.iio_open)(of_vsa_addr, s->vdisk_guid, 0,
76daa3
+                                      cacert, client_key, client_cert);
76daa3
     if (dev_handlep == NULL) {
76daa3
         trace_vxhs_open_iio_open(of_vsa_addr);
76daa3
         ret = -ENODEV;
76daa3
@@ -450,12 +550,12 @@ static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
76daa3
 
76daa3
     switch (iodir) {
76daa3
     case VDISK_AIO_WRITE:
76daa3
-            ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov,
76daa3
-                             offset, (uint64_t)size, iio_flags);
76daa3
+            ret = (*libvxhs.iio_writev)(dev_handle, acb, qiov->iov, qiov->niov,
76daa3
+                                        offset, (uint64_t)size, iio_flags);
76daa3
             break;
76daa3
     case VDISK_AIO_READ:
76daa3
-            ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov,
76daa3
-                            offset, (uint64_t)size, iio_flags);
76daa3
+            ret = (*libvxhs.iio_readv)(dev_handle, acb, qiov->iov, qiov->niov,
76daa3
+                                       offset, (uint64_t)size, iio_flags);
76daa3
             break;
76daa3
     default:
76daa3
             trace_vxhs_aio_rw_invalid(iodir);
76daa3
@@ -505,7 +605,7 @@ static void vxhs_close(BlockDriverState *bs)
76daa3
      * Close vDisk device
76daa3
      */
76daa3
     if (s->vdisk_hostinfo.dev_handle) {
76daa3
-        iio_close(s->vdisk_hostinfo.dev_handle);
76daa3
+        (*libvxhs.iio_close)(s->vdisk_hostinfo.dev_handle);
76daa3
         s->vdisk_hostinfo.dev_handle = NULL;
76daa3
     }
76daa3
 
76daa3
@@ -527,7 +627,7 @@ static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s)
76daa3
     int ret = 0;
76daa3
     void *dev_handle = s->vdisk_hostinfo.dev_handle;
76daa3
 
76daa3
-    ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0);
76daa3
+    ret = (*libvxhs.iio_ioctl)(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0);
76daa3
     if (ret < 0) {
76daa3
         trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno);
76daa3
         return -EIO;
76daa3
diff --git a/configure b/configure
76daa3
index 47b2475..2ca95f4 100755
76daa3
--- a/configure
76daa3
+++ b/configure
76daa3
@@ -3091,7 +3091,7 @@ else
76daa3
     glib_req_ver=2.22
76daa3
 fi
76daa3
 glib_modules=gthread-2.0
76daa3
-if test "$modules" = yes; then
76daa3
+if test "$modules" = yes -o "$vxhs" = yes; then
76daa3
     glib_modules="$glib_modules gmodule-2.0"
76daa3
 fi
76daa3
 
76daa3
@@ -4793,33 +4793,6 @@ if compile_prog "" "" ; then
76daa3
 fi
76daa3
 
76daa3
 ##########################################
76daa3
-# Veritas HyperScale block driver VxHS
76daa3
-# Check if libvxhs is installed
76daa3
-
76daa3
-if test "$vxhs" != "no" ; then
76daa3
-  cat > $TMPC <
76daa3
-#include <stdint.h>
76daa3
-#include <qnio/qnio_api.h>
76daa3
-
76daa3
-void *vxhs_callback;
76daa3
-
76daa3
-int main(void) {
76daa3
-    iio_init(QNIO_VERSION, vxhs_callback);
76daa3
-    return 0;
76daa3
-}
76daa3
-EOF
76daa3
-  vxhs_libs="-lvxhs -lssl"
76daa3
-  if compile_prog "" "$vxhs_libs" ; then
76daa3
-    vxhs=yes
76daa3
-  else
76daa3
-    if test "$vxhs" = "yes" ; then
76daa3
-      feature_not_found "vxhs block device" "Install libvxhs See github"
76daa3
-    fi
76daa3
-    vxhs=no
76daa3
-  fi
76daa3
-fi
76daa3
-
76daa3
-##########################################
76daa3
 # End of CC checks
76daa3
 # After here, no more $cc or $ld runs
76daa3
 
76daa3
@@ -5831,8 +5804,8 @@ if test "$pthread_setname_np" = "yes" ; then
76daa3
 fi
76daa3
 
76daa3
 if test "$vxhs" = "yes" ; then
76daa3
-  echo "CONFIG_VXHS=y" >> $config_host_mak
76daa3
-  echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak
76daa3
+  echo "CONFIG_VXHS=m" >> $config_host_mak
76daa3
+  echo "VXHS_LIBS= -lssl" >> $config_host_mak
76daa3
 fi
76daa3
 
76daa3
 if test "$tcg_interpreter" = "yes"; then
76daa3
diff --git a/include/block/vxhs_shim.h b/include/block/vxhs_shim.h
76daa3
new file mode 100644
76daa3
index 0000000..42519ae
76daa3
--- /dev/null
76daa3
+++ b/include/block/vxhs_shim.h
76daa3
@@ -0,0 +1,143 @@
76daa3
+/*
76daa3
+ * Network IO library for VxHS QEMU block driver (Veritas Technologies)
76daa3
+ *
76daa3
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
76daa3
+ * the COPYING file in the top-level directory.
76daa3
+ *
76daa3
+ * Contributions after 2014-08-15 are licensed under the terms of the
76daa3
+ * GNU GPL, version 2 or (at your option) any later version.
76daa3
+ */
76daa3
+
76daa3
+#ifndef QNIO_API_H
76daa3
+#define QNIO_API_H
76daa3
+
76daa3
+#include <sys/uio.h>
76daa3
+
76daa3
+/*
76daa3
+ * Bump up the version everytime this file is modified
76daa3
+ */
76daa3
+#define QNIO_VERSION    34
76daa3
+
76daa3
+/*
76daa3
+ * These are the opcodes referenced by callback routine.
76daa3
+ */
76daa3
+#define IRP_READ_REQUEST                    0x1FFF
76daa3
+#define IRP_WRITE_REQUEST                   0x2FFF
76daa3
+#define IRP_VDISK_CHECK_IO_FAILOVER_READY   2020
76daa3
+
76daa3
+/*
76daa3
+ * opcodes for iio_ioctl.
76daa3
+ */
76daa3
+#define IOR_VDISK_STAT                      1005
76daa3
+
76daa3
+/*
76daa3
+ * Error values for iio_cb_t callback function.
76daa3
+ */
76daa3
+#define QNIOERROR_HUP                       901 /* Retriable error */
76daa3
+#define QNIOERROR_NOCONN                    902 /* Non-retriable error */
76daa3
+
76daa3
+
76daa3
+/* Operation Flags */
76daa3
+#define IIO_FLAG_ASYNC        0x0001   /* Do an async send */
76daa3
+
76daa3
+/*
76daa3
+ * INPUT:
76daa3
+ *     ctx - opaque context
76daa3
+ *     opcode - Operation
76daa3
+ *     error - 0 for sucess, non-zero for failure.
76daa3
+ * RETURNS:
76daa3
+ *     void
76daa3
+ * DESCRIPTION:
76daa3
+ *     This callback is called, after Async request completes.
76daa3
+ *
76daa3
+ * CONTEXT:
76daa3
+ *     The callback should be wait-free.
76daa3
+ */
76daa3
+typedef void (*iio_cb_t) (void *ctx, uint32_t opcode, uint32_t error);
76daa3
+
76daa3
+typedef struct LibVXHSFuncs {
76daa3
+/*
76daa3
+ * RETURNS:
76daa3
+ *     0 for sucess, non-zero for failure.
76daa3
+ * DESCRIPTION:
76daa3
+ *     Intilize the library state. This should be called at the
76daa3
+ *     begining before issuing any library call.
76daa3
+ */
76daa3
+    int     (*iio_init)(int32_t version, iio_cb_t cb);
76daa3
+/*
76daa3
+ * RETURNS:
76daa3
+ *     void
76daa3
+ * DESCRIPTION:
76daa3
+ *     Relinquish library resources. This should be called on the
76daa3
+ *     close of last open device.
76daa3
+ */
76daa3
+    void    (*iio_fini)(void);
76daa3
+/*
76daa3
+ * DESCRIPTION:
76daa3
+ *     Returns minimum QNIO API version supported by library.
76daa3
+ */
76daa3
+    int32_t (*iio_min_version)(void);
76daa3
+/*
76daa3
+ * DESCRIPTION:
76daa3
+ *     Returns maximum QNIO API version supported by library.
76daa3
+ */
76daa3
+    int32_t (*iio_max_version)(void);
76daa3
+/*
76daa3
+ * INPUT:
76daa3
+ *    uri - const string of the format of://<hostname|ip>:port
76daa3
+ *    devid - Device ID.
76daa3
+ *    flags - currently unused, this must be set to 0
76daa3
+ *    cacert - CA certificates file in PEM format
76daa3
+ *    client_key - Client private key file in PEM format
76daa3
+ *    client_cert - Client certificate file in PEM format
76daa3
+ * RETURNS:
76daa3
+ *    opeque device handle on success, NULL on failure.
76daa3
+ * DESCRIPTION:
76daa3
+ *    This call returns device handle on success. Returns NULL on
76daa3
+ *    failure with errno set
76daa3
+ *    errno can be one of:
76daa3
+ *        ENODEV - remote device not found
76daa3
+ *        EBADF  - Unable to open communication channel.
76daa3
+ *        EBUSY  - The call cannot be completed right now
76daa3
+ */
76daa3
+    void   *(*iio_open)(const char *uri, const char *devid, uint32_t flags,
76daa3
+                        const char *cacert, const char *client_key,
76daa3
+                        const char *client_cert);
76daa3
+/*
76daa3
+ * Close the device.
76daa3
+ *    For every matching iio_open() there should be a matching iio_close()
76daa3
+ *    The last close free all data structures associated with the device.
76daa3
+ */
76daa3
+    int32_t (*iio_close)(void *dev_handle);
76daa3
+/*
76daa3
+ * INPUT:
76daa3
+ *    dev_handle - device descriptor on which read/write needs to be performed
76daa3
+ *    ctx - an opaque context that is not interpreted This is set for
76daa3
+ *          async calls only. It can be NULL.
76daa3
+ *    iov    - an array of iovecs (This is a scatter gather operation)
76daa3
+ *    iovcnt  - the number of iovecs
76daa3
+ *    offset - an offset to perform the write
76daa3
+ *    size   - I/O size
76daa3
+ *    flags  - can be one of
76daa3
+ *        IIO_FLAG_ASYNC - indicating this is a aio call.
76daa3
+ * RETURNS:
76daa3
+ *        -1 on error, sets errno
76daa3
+ *        EBADF  - the remote fd is bad
76daa3
+ *        EBUSY  - The call cannot be completed right now
76daa3
+ *        EPIPE  - the channel got disconnected, call back would be called in
76daa3
+ *                 addition to this.
76daa3
+ */
76daa3
+    int32_t (*iio_writev)(void *dev_handle, void *ctx, struct iovec *iov,
76daa3
+                          int iovcnt, uint64_t offset, uint64_t size,
76daa3
+                          uint32_t flags);
76daa3
+
76daa3
+    int32_t (*iio_readv)(void *dev_handle, void *ctx, struct iovec *iov,
76daa3
+                         int iovcnt, uint64_t offset, uint64_t size,
76daa3
+                         uint32_t flags);
76daa3
+
76daa3
+    int32_t (*iio_ioctl)(void *dev_handle, uint32_t opcode, void *opaque,
76daa3
+                         uint32_t flags);
76daa3
+
76daa3
+} LibVXHSFuncs;
76daa3
+
76daa3
+#endif
76daa3
-- 
76daa3
1.8.3.1
76daa3