This finally solves a long-standing problem that the plugin did not
follow the peculiar rules that VDDK imposes on multithreaded
programming (see "Multithreading Considerations" in the VDDK manual).

We add a background thread to the plugin which is responsible for
issuing the following VDDK calls:

  VixDiskLib_InitEx
  VixDiskLib_Exit
  VixDiskLib_ConnectEx
  VixDiskLib_Open
  VixDiskLib_Close
  VixDiskLib_Disconnect

(Other calls are still made directly by the plugin.)  This involves
some complicated synchronization but is otherwise uninteresting.

This allows us to relax the thread model from SERIALIZE_ALL_REQUESTS
to SERIALIZE_REQUESTS.  Note that VDDK does not allow parallel
requests to be made on one handle, so we cannot relax the model any
further.
---
 plugins/vddk/Makefile.am |   2 +
 plugins/vddk/octhread.c  | 399 +++++++++++++++++++++++++++++++++++++++
 plugins/vddk/vddk.c      | 190 ++++++-------------
 plugins/vddk/vddk.h      |  89 +++++++++
 tests/test-vddk-real.sh  |   2 +-
 5 files changed, 547 insertions(+), 135 deletions(-)

diff --git a/plugins/vddk/Makefile.am b/plugins/vddk/Makefile.am
index b806a7d..aff1288 100644
--- a/plugins/vddk/Makefile.am
+++ b/plugins/vddk/Makefile.am
@@ -42,6 +42,8 @@ plugin_LTLIBRARIES = nbdkit-vddk-plugin.la
 
 nbdkit_vddk_plugin_la_SOURCES = \
        vddk.c \
+       octhread.c \
+       vddk.h \
        vddk-structs.h \
        vddk-stubs.h \
        $(top_srcdir)/include/nbdkit-plugin.h \
diff --git a/plugins/vddk/octhread.c b/plugins/vddk/octhread.c
new file mode 100644
index 0000000..9da3fb2
--- /dev/null
+++ b/plugins/vddk/octhread.c
@@ -0,0 +1,399 @@
+/* nbdkit
+ * Copyright (C) 2013-2019 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* This is the Open/Close Thread (octhread).
+ *
+ * Because of VDDK's complicated multi-threading requirements (see
+ * "Multithreading Considerations" in the VDDK manual) we have to
+ * issue various VDDK calls from a single thread.  In this file we
+ * create the extra thread which always runs while the VDDK plugin is
+ * loaded.
+ *
+ * The main VDDK plugin calls out to this thread synchronously
+ * whenever it needs to make one of the following calls:
+ *
+ *   VixDiskLib_InitEx
+ *   VixDiskLib_Exit
+ *   VixDiskLib_ConnectEx
+ *   VixDiskLib_Open
+ *   VixDiskLib_Close
+ *   VixDiskLib_Disconnect
+ *
+ * (Any other calls are made directly by the plugin.)
+ *
+ * To make one of the above calls, the plugin thread fills in struct
+ * request with the request type and signals on the request_cond.  The
+ * plugin thread then waits on the return_cond until that is signalled
+ * which indicates that the request was carried out (or there was an
+ * error).  The return value can be read out of the request struct.
+ * All this logic is wrapped in the octhread_do_* functions below.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#define NBDKIT_API_VERSION 2
+#include <nbdkit-plugin.h>
+
+#include "cleanup.h"
+
+#include "vddk.h"
+
+static pthread_t thread;
+
+/* Enable debugging of message passing: -D vddk.messagepassing=1 */
+int vddk_debug_messagepassing;
+
+/* Because the entire purpose of this is to serialize certain
+ * operations, the request struct can only be used by one calling
+ * thread.  The calling thread must hold request_lock during the
+ * entire request.
+ */
+static pthread_mutex_t request_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct {
+  /* Which function to call. */
+  enum { NONE = 0,
+         INITEX = 1, EXIT, CONNECTEX, OPEN, CLOSE, DISCONNECT,
+         STOP } request_type;
+
+  /* Parameters. */
+  VixDiskLibConnectParams *params;
+  VixDiskLibConnection *connection_ret;
+  VixDiskLibConnection connection;
+  VixDiskLibHandle *handle_ret;
+  VixDiskLibHandle handle;
+  int readonly;
+
+  /* Return code. */
+  bool request_done;
+  VixError ret;
+} request;
+
+/* Request and return conditions. */
+static pthread_cond_t request_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t request_cond_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t return_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t return_cond_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static inline void
+wake_up_octhread (void)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_cond_lock);
+  pthread_cond_signal (&request_cond);
+}
+
+static inline void
+wait_for_octhread (void)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&return_cond_lock);
+  while (! request.request_done)
+    pthread_cond_wait (&return_cond, &return_cond_lock);
+  request.request_done = false;
+}
+
+static VixError
+do_request (void)
+{
+  if (vddk_debug_messagepassing)
+    nbdkit_debug ("waking up octhread with request %d", request.request_type);
+  wake_up_octhread ();
+  if (vddk_debug_messagepassing)
+    nbdkit_debug ("waiting for octhread");
+  wait_for_octhread ();
+
+  return request.ret;
+}
+
+static void *octhread_run (void *);
+
+/*----------------------------------------------------------------------*/
+/* Plugins call these functions from the normal nbdkit thread context. */
+
+/* Start the octhread.  Called by vddk_ready_to_serve. */
+void
+start_octhread (void)
+{
+  int err;
+
+  err = pthread_create (&thread, NULL, octhread_run, NULL);
+  if (err != 0) {
+    errno = err;
+    nbdkit_error ("octhread: pthread_create: %m");
+    exit (EXIT_FAILURE);
+  }
+}
+
+/* Terminate the octhread.  Called from vddk_unload. */
+void
+stop_octhread (void)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = STOP;
+  do_request ();
+
+  /* We must wait for the thread to exit to avoid races during
+   * shutdown, eg. if this plugin was unloaded while the thread was
+   * still exiting.
+   */
+  pthread_join (thread, NULL);
+}
+
+/* Request VixDiskLib_InitEx and wait for it to finish. */
+VixError
+octhread_do_VixDiskLib_InitEx (void)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = INITEX;
+  return do_request ();
+}
+
+/* Request VixDiskLib_Exit and wait for it to finish. */
+VixError
+octhread_do_VixDiskLib_Exit (void)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = EXIT;
+  return do_request ();
+}
+
+/* Request VixDiskLib_ConnectEx and wait for it to finish. */
+VixError
+octhread_do_VixDiskLib_ConnectEx (const VixDiskLibConnectParams *params,
+                                  int readonly,
+                                  VixDiskLibConnection *connection)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = CONNECTEX;
+  request.params = (VixDiskLibConnectParams *) params;
+  request.readonly = readonly;
+  request.connection_ret = connection;
+  return do_request ();
+}
+
+/* Request VixDiskLib_Open and wait for it to finish. */
+VixError
+octhread_do_VixDiskLib_Open (const VixDiskLibConnection connection,
+                             int readonly,
+                             VixDiskLibHandle *handle)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = OPEN;
+  request.connection = connection;
+  request.readonly = readonly;
+  request.handle_ret = handle;
+  return do_request ();
+}
+
+/* Request VixDiskLib_Close and wait for it to finish. */
+VixError
+octhread_do_VixDiskLib_Close (VixDiskLibHandle handle)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = CLOSE;
+  request.handle = handle;
+  return do_request ();
+}
+
+/* Request VixDiskLib_Disconnect and wait for it to finish. */
+VixError
+octhread_do_VixDiskLib_Disconnect (VixDiskLibConnection connection)
+{
+  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_lock);
+
+  request.request_type = DISCONNECT;
+  request.connection = connection;
+  return do_request ();
+}
+
+/*----------------------------------------------------------------------*/
+/* The octhread itself. */
+
+static void
+trim (char *str)
+{
+  size_t len = strlen (str);
+
+  if (len > 0 && str[len-1] == '\n')
+    str[len-1] = '\0';
+}
+
+/* Turn log messages from the library into nbdkit_debug. */
+static void
+debug_function (const char *fs, va_list args)
+{
+  CLEANUP_FREE char *str = NULL;
+
+  if (vasprintf (&str, fs, args) == -1) {
+    nbdkit_debug ("lost debug message: %s", fs);
+    return;
+  }
+
+  trim (str);
+
+  nbdkit_debug ("%s", str);
+}
+
+/* Turn error messages from the library into nbdkit_error. */
+static void
+error_function (const char *fs, va_list args)
+{
+  CLEANUP_FREE char *str = NULL;
+
+  if (vasprintf (&str, fs, args) == -1) {
+    nbdkit_error ("lost error message: %s", fs);
+    return;
+  }
+
+  trim (str);
+
+  nbdkit_error ("%s", str);
+}
+
+static void *
+octhread_run (void *arg)
+{
+  int err;
+  uint32_t flags;
+  bool stop = false;
+
+  nbdkit_debug ("octhread started");
+
+  while (!stop) {
+    /* Wait for an incoming request. */
+    {
+      ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&request_cond_lock);
+      while (request.request_type == NONE)
+        pthread_cond_wait (&request_cond, &request_cond_lock);
+    }
+
+    if (vddk_debug_messagepassing)
+      nbdkit_debug ("octhread: request %d", request.request_type);
+
+    switch (request.request_type) {
+    case INITEX:
+      DEBUG_CALL ("VixDiskLib_InitEx",
+                  "%d, %d, &debug_fn, &error_fn, &error_fn, %s, %s",
+                  VDDK_MAJOR, VDDK_MINOR,
+                  libdir ? : VDDK_LIBDIR, config ? : "NULL");
+      err = VixDiskLib_InitEx (VDDK_MAJOR, VDDK_MINOR,
+                               &debug_function, /* log function */
+                               &error_function, /* warn function */
+                               &error_function, /* panic function */
+                               libdir ? : VDDK_LIBDIR, config);
+      break;
+
+    case EXIT:
+      DEBUG_CALL ("VixDiskLib_Exit", "");
+      VixDiskLib_Exit ();
+      err = VIX_OK;
+      break;
+
+    case CONNECTEX:
+      DEBUG_CALL ("VixDiskLib_ConnectEx",
+                  "params, %d, %s, %s, &connection",
+                  request.readonly,
+                  snapshot_moref ? : "NULL",
+                  transport_modes ? : "NULL");
+      err = VixDiskLib_ConnectEx (request.params,
+                                  request.readonly,
+                                  snapshot_moref,
+                                  transport_modes,
+                                  request.connection_ret);
+      break;
+
+    case OPEN:
+      flags = 0;
+      if (request.readonly)
+        flags |= VIXDISKLIB_FLAG_OPEN_READ_ONLY;
+      if (single_link)
+        flags |= VIXDISKLIB_FLAG_OPEN_SINGLE_LINK;
+      if (unbuffered)
+        flags |= VIXDISKLIB_FLAG_OPEN_UNBUFFERED;
+      DEBUG_CALL ("VixDiskLib_Open",
+                  "connection, %s, %d, &handle", filename, flags);
+      err = VixDiskLib_Open (request.connection, filename, flags,
+                             request.handle_ret);
+      break;
+
+    case CLOSE:
+      DEBUG_CALL ("VixDiskLib_Close", "handle");
+      err = VixDiskLib_Close (request.handle);
+      break;
+
+    case DISCONNECT:
+      DEBUG_CALL ("VixDiskLib_Disconnect", "connection");
+      err = VixDiskLib_Disconnect (request.connection);
+      break;
+
+    case STOP:
+      stop = true;
+      err = VIX_OK;
+      break;
+
+    case NONE:
+    default:
+      abort ();
+    }
+
+    request.request_type = NONE;
+
+    /* Set up return field and signal to plugin thread that we have
+     * finished.
+     */
+    if (vddk_debug_messagepassing)
+      nbdkit_debug ("octhread: return %d", err);
+    request.ret = err;
+    request.request_done = true;
+
+    {
+      ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&return_cond_lock);
+      pthread_cond_signal (&return_cond);
+    }
+  } /* for (;;) */
+
+  nbdkit_debug ("octhread exiting");
+
+  pthread_exit (NULL);
+}
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
index 5d3764d..375fbfa 100644
--- a/plugins/vddk/vddk.c
+++ b/plugins/vddk/vddk.c
@@ -42,7 +42,6 @@
 #include <dlfcn.h>
 
 #define NBDKIT_API_VERSION 2
-
 #include <nbdkit-plugin.h>
 
 #include "cleanup.h"
@@ -50,7 +49,7 @@
 #include "minmax.h"
 #include "rounding.h"
 
-#include "vddk-structs.h"
+#include "vddk.h"
 
 /* Enable extra disk info debugging with: -D vddk.diskinfo=1 */
 int vddk_debug_diskinfo;
@@ -58,90 +57,34 @@ int vddk_debug_diskinfo;
 /* Enable debugging of extents code with: -D vddk.extents=1 */
 int vddk_debug_extents;
 
-/* For each VDDK API define a static global variable.  These globals
- * are initialized when the plugin is loaded (by vddk_load).
+/* For each VDDK API define a global variable.  These globals are
+ * initialized when the plugin is loaded (by vddk_load).
  */
-#define STUB(fn,ret,args) static ret (*fn) args
-#define OPTIONAL_STUB(fn,ret,args) static ret (*fn) args
+#define STUB(fn,ret,args) ret (*fn) args
+#define OPTIONAL_STUB(fn,ret,args) ret (*fn) args
 #include "vddk-stubs.h"
 #undef STUB
 #undef OPTIONAL_STUB
 
-/* Parameters passed to InitEx. */
-#define VDDK_MAJOR 5
-#define VDDK_MINOR 1
-
 static void *dl = NULL;                    /* dlopen handle */
-static int init_called = 0;                /* was InitEx called */
-
-static char *config = NULL;                /* config */
-static const char *cookie = NULL;          /* cookie */
-static const char *filename = NULL;        /* file */
-static char *libdir = NULL;                /* libdir */
-static uint16_t nfc_host_port = 0;         /* nfchostport */
-static char *password = NULL;              /* password */
-static uint16_t port = 0;                  /* port */
-static const char *server_name = NULL;     /* server */
-static bool single_link = false;           /* single-link */
-static const char *snapshot_moref = NULL;  /* snapshot */
-static const char *thumb_print = NULL;     /* thumbprint */
-static const char *transport_modes = NULL; /* transports */
-static bool unbuffered = false;            /* unbuffered */
-static const char *username = NULL;        /* user */
-static const char *vmx_spec = NULL;        /* vm */
-static bool is_remote = false;
-
-#define VDDK_ERROR(err, fs, ...)                                \
-  do {                                                          \
-    char *vddk_err_msg;                                         \
-    vddk_err_msg = VixDiskLib_GetErrorText ((err), NULL);       \
-    nbdkit_error (fs ": %s", ##__VA_ARGS__, vddk_err_msg);      \
-    VixDiskLib_FreeErrorText (vddk_err_msg);                    \
-  } while (0)
-
-#define DEBUG_CALL(fn, fs, ...)                                 \
-  nbdkit_debug ("VDDK call: %s (" fs ")", fn, ##__VA_ARGS__)
-
-static void
-trim (char *str)
-{
-  size_t len = strlen (str);
-
-  if (len > 0 && str[len-1] == '\n')
-    str[len-1] = '\0';
-}
-
-/* Turn log messages from the library into nbdkit_debug. */
-static void
-debug_function (const char *fs, va_list args)
-{
-  CLEANUP_FREE char *str = NULL;
-
-  if (vasprintf (&str, fs, args) == -1) {
-    nbdkit_debug ("lost debug message: %s", fs);
-    return;
-  }
-
-  trim (str);
-
-  nbdkit_debug ("%s", str);
-}
-
-/* Turn error messages from the library into nbdkit_error. */
-static void
-error_function (const char *fs, va_list args)
-{
-  CLEANUP_FREE char *str = NULL;
-
-  if (vasprintf (&str, fs, args) == -1) {
-    nbdkit_error ("lost error message: %s", fs);
-    return;
-  }
-
-  trim (str);
-
-  nbdkit_error ("%s", str);
-}
+static bool octhread_running = false;      /* octhread is running */
+
+char *config = NULL;                       /* config */
+const char *cookie = NULL;                 /* cookie */
+const char *filename = NULL;               /* file */
+char *libdir = NULL;                       /* libdir */
+uint16_t nfc_host_port = 0;                /* nfchostport */
+char *password = NULL;                     /* password */
+uint16_t port = 0;                         /* port */
+const char *server_name = NULL;            /* server */
+bool single_link = false;                  /* single-link */
+const char *snapshot_moref = NULL;         /* snapshot */
+const char *thumb_print = NULL;            /* thumbprint */
+const char *transport_modes = NULL;        /* transports */
+bool unbuffered = false;                   /* unbuffered */
+const char *username = NULL;               /* user */
+const char *vmx_spec = NULL;               /* vm */
+bool is_remote = false;                    /* is a remote connection? */
 
 /* Load and unload the plugin. */
 static void
@@ -194,9 +137,9 @@ vddk_load (void)
 static void
 vddk_unload (void)
 {
-  if (init_called) {
-    DEBUG_CALL ("VixDiskLib_Exit", "");
-    VixDiskLib_Exit ();
+  if (octhread_running) {
+    octhread_do_VixDiskLib_Exit ();
+    stop_octhread ();
   }
   if (dl)
     dlclose (dl);
@@ -292,8 +235,6 @@ vddk_config (const char *key, const char *value)
 static int
 vddk_config_complete (void)
 {
-  VixError err;
-
   if (filename == NULL) {
     nbdkit_error ("you must supply the file=<FILENAME> parameter "
                   "after the plugin name on the command line");
@@ -330,29 +271,31 @@ vddk_config_complete (void)
 #undef missing
   }
 
+  return 0;
+}
+
+#define vddk_config_help \
+  "file=<FILENAME>     (required) The filename (eg. VMDK file) to serve.\n" \
+  "Many optional parameters are supported, see nbdkit-vddk-plugin(3)."
+
+static int
+vddk_ready_to_serve (void)
+{
+  VixError err;
+
+  start_octhread ();
+
   /* Initialize VDDK library. */
-  DEBUG_CALL ("VixDiskLib_InitEx",
-              "%d, %d, &debug_fn, &error_fn, &error_fn, %s, %s",
-              VDDK_MAJOR, VDDK_MINOR,
-              libdir ? : VDDK_LIBDIR, config ? : "NULL");
-  err = VixDiskLib_InitEx (VDDK_MAJOR, VDDK_MINOR,
-                           &debug_function, /* log function */
-                           &error_function, /* warn function */
-                           &error_function, /* panic function */
-                           libdir ? : VDDK_LIBDIR, config);
+  err = octhread_do_VixDiskLib_InitEx ();
   if (err != VIX_OK) {
     VDDK_ERROR (err, "VixDiskLib_InitEx");
-    exit (EXIT_FAILURE);
+    return -1;
   }
-  init_called = 1;
 
+  octhread_running = true;
   return 0;
 }
 
-#define vddk_config_help \
-  "file=<FILENAME>     (required) The filename (eg. VMDK file) to serve.\n" \
-  "Many optional parameters are supported, see nbdkit-vddk-plugin(3)."
-
 static void
 vddk_dump_plugin (void)
 {
@@ -376,11 +319,11 @@ vddk_dump_plugin (void)
 #endif
 }
 
-/* XXX To really do threading correctly in accordance with the VDDK
- * documentation, we must do all open/close calls from a single
- * thread.  This is a huge pain.
+/* See "Multithreading Considerations" in the VDDK manual.  VDDK does
+ * not allow parallel requests on the same handle, so we cannot use
+ * the parallel thread model.
  */
-#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
+#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
 
 /* The per-connection handle. */
 struct vddk_handle {
@@ -424,7 +367,6 @@ vddk_open (int readonly)
 {
   struct vddk_handle *h;
   VixError err;
-  uint32_t flags;
 
   h = malloc (sizeof *h);
   if (h == NULL) {
@@ -462,33 +404,15 @@ vddk_open (int readonly)
    * Advanced Transport modes, but I could not make it work with
    * either ESXi or vCenter servers.
    */
-
-  DEBUG_CALL ("VixDiskLib_ConnectEx",
-              "h->params, %d, %s, %s, &connection",
-              readonly,
-              snapshot_moref ? : "NULL",
-              transport_modes ? : "NULL");
-  err = VixDiskLib_ConnectEx (h->params,
-                              readonly,
-                              snapshot_moref,
-                              transport_modes,
-                              &h->connection);
+  err = octhread_do_VixDiskLib_ConnectEx (h->params, readonly,
+                                          &h->connection);
   if (err != VIX_OK) {
     VDDK_ERROR (err, "VixDiskLib_ConnectEx");
     goto err1;
   }
 
-  flags = 0;
-  if (readonly)
-    flags |= VIXDISKLIB_FLAG_OPEN_READ_ONLY;
-  if (single_link)
-    flags |= VIXDISKLIB_FLAG_OPEN_SINGLE_LINK;
-  if (unbuffered)
-    flags |= VIXDISKLIB_FLAG_OPEN_UNBUFFERED;
-
-  DEBUG_CALL ("VixDiskLib_Open",
-              "connection, %s, %d, &handle", filename, flags);
-  err = VixDiskLib_Open (h->connection, filename, flags, &h->handle);
+  err = octhread_do_VixDiskLib_Open (h->connection, readonly,
+                                     &h->handle);
   if (err != VIX_OK) {
     VDDK_ERROR (err, "VixDiskLib_Open: %s", filename);
     goto err2;
@@ -500,8 +424,7 @@ vddk_open (int readonly)
   return h;
 
  err2:
-  DEBUG_CALL ("VixDiskLib_Disconnect", "connection");
-  VixDiskLib_Disconnect (h->connection);
+  octhread_do_VixDiskLib_Disconnect (h->connection);
  err1:
   free_connect_params (h->params);
  err0:
@@ -515,10 +438,8 @@ vddk_close (void *handle)
 {
   struct vddk_handle *h = handle;
 
-  DEBUG_CALL ("VixDiskLib_Close", "handle");
-  VixDiskLib_Close (h->handle);
-  DEBUG_CALL ("VixDiskLib_Disconnect", "connection");
-  VixDiskLib_Disconnect (h->connection);
+  octhread_do_VixDiskLib_Close (h->handle);
+  octhread_do_VixDiskLib_Disconnect (h->connection);
   free_connect_params (h->params);
   free (h);
 }
@@ -833,10 +754,11 @@ static struct nbdkit_plugin plugin = {
   .version           = PACKAGE_VERSION,
   .load              = vddk_load,
   .unload            = vddk_unload,
+  .dump_plugin       = vddk_dump_plugin,
   .config            = vddk_config,
   .config_complete   = vddk_config_complete,
   .config_help       = vddk_config_help,
-  .dump_plugin       = vddk_dump_plugin,
+  .ready_to_serve    = vddk_ready_to_serve,
   .open              = vddk_open,
   .close             = vddk_close,
   .get_size          = vddk_get_size,
diff --git a/plugins/vddk/vddk.h b/plugins/vddk/vddk.h
new file mode 100644
index 0000000..7d012eb
--- /dev/null
+++ b/plugins/vddk/vddk.h
@@ -0,0 +1,89 @@
+/* nbdkit
+ * Copyright (C) 2013-2019 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef NBDKIT_VDDK_H
+#define NBDKIT_VDDK_H
+
+#include "vddk-structs.h"
+
+/* For each VDDK API define an extern global variable.  These globals
+ * are initialized when the plugin is loaded (by vddk_load).
+ */
+#define STUB(fn,ret,args) extern ret (*fn) args
+#define OPTIONAL_STUB(fn,ret,args) extern ret (*fn) args
+#include "vddk-stubs.h"
+#undef STUB
+#undef OPTIONAL_STUB
+
+extern char *config;
+extern const char *cookie;
+extern const char *filename;
+extern char *libdir;
+extern uint16_t nfc_host_port;
+extern char *password;
+extern uint16_t port;
+extern const char *server_name;
+extern bool single_link;
+extern const char *snapshot_moref;
+extern const char *thumb_print;
+extern const char *transport_modes;
+extern bool unbuffered;
+extern const char *username;
+extern const char *vmx_spec;
+extern bool is_remote;
+
+#define VDDK_ERROR(err, fs, ...)                                \
+  do {                                                          \
+    char *vddk_err_msg;                                         \
+    vddk_err_msg = VixDiskLib_GetErrorText ((err), NULL);       \
+    nbdkit_error (fs ": %s", ##__VA_ARGS__, vddk_err_msg);      \
+    VixDiskLib_FreeErrorText (vddk_err_msg);                    \
+  } while (0)
+
+#define DEBUG_CALL(fn, fs, ...)                                 \
+  nbdkit_debug ("VDDK call: %s (" fs ")", fn, ##__VA_ARGS__)
+
+/* Parameters passed to InitEx. */
+#define VDDK_MAJOR 5
+#define VDDK_MINOR 1
+
+/* Functions in octhread.c */
+extern void start_octhread (void);
+extern void stop_octhread (void);
+extern VixError octhread_do_VixDiskLib_InitEx (void);
+extern VixError octhread_do_VixDiskLib_Exit (void);
+extern VixError octhread_do_VixDiskLib_ConnectEx (const 
VixDiskLibConnectParams *params, int readonly, VixDiskLibConnection 
*connection);
+extern VixError octhread_do_VixDiskLib_Open (const VixDiskLibConnection 
connection, int readonly, VixDiskLibHandle *handle);
+extern VixError octhread_do_VixDiskLib_Close (VixDiskLibHandle handle);
+extern VixError octhread_do_VixDiskLib_Disconnect (VixDiskLibConnection 
connection);
+
+#endif /* NBDKIT_VDDK_H */
diff --git a/tests/test-vddk-real.sh b/tests/test-vddk-real.sh
index 60f634c..6b31808 100755
--- a/tests/test-vddk-real.sh
+++ b/tests/test-vddk-real.sh
@@ -57,7 +57,7 @@ qemu-img create -f vmdk test-vddk-real.vmdk 100M
 export old_ld_library_path="$LD_LIBRARY_PATH"
 export LD_LIBRARY_PATH="$vddkdir/$lib:$LD_LIBRARY_PATH"
 
-nbdkit -f -v -U - \
+nbdkit -f -v -U - -D vddk.messagepassing=1 \
        --filter=readahead \
        vddk libdir="$vddkdir" file=test-vddk-real.vmdk \
        --run '
-- 
2.23.0

_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs

Reply via email to