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 | 374 +++++++++++++++++++++++++++++++++++++++
plugins/vddk/vddk.c | 164 ++++-------------
plugins/vddk/vddk.h | 89 ++++++++++
4 files changed, 504 insertions(+), 125 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..8f1985d
--- /dev/null
+++ b/plugins/vddk/octhread.c
@@ -0,0 +1,374 @@
+/* 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;
+
+/* 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 { BAD = 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. */
+ 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);
+ pthread_cond_wait (&return_cond, &return_cond_lock);
+}
+
+static VixError
+do_request (void)
+{
+ wake_up_octhread ();
+ wait_for_octhread ();
+
+ request.request_type = BAD;
+ return request.ret;
+}
+
+static void *octhread_run (void *);
+
+/*----------------------------------------------------------------------*/
+/* Plugins call these functions from the normal nbdkit thread context. */
+
+/* Start the octhread. Called by vddk_load. */
+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 ();
+ 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);
+ pthread_cond_wait (&request_cond, &request_cond_lock);
+ }
+
+ 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 BAD:
+ default:
+ abort ();
+ }
+
+ /* Set up return field and signal to plugin thread that we have
+ * finished.
+ */
+ request.ret = err;
+
+ {
+ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&return_cond_lock);
+ pthread_cond_signal (&return_cond);
+ }
+ } /* for (;;) */
+
+ return NULL;
+}
diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
index 53984ad..02e473e 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);
-}
+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
@@ -189,15 +132,16 @@ vddk_load (void)
#include "vddk-stubs.h"
#undef STUB
#undef OPTIONAL_STUB
+
+ start_octhread ();
}
static void
vddk_unload (void)
{
- if (init_called) {
- DEBUG_CALL ("VixDiskLib_Exit", "");
- VixDiskLib_Exit ();
- }
+ if (init_called)
+ octhread_do_VixDiskLib_Exit ();
+ stop_octhread ();
if (dl)
dlclose (dl);
free (config);
@@ -331,18 +275,10 @@ vddk_config_complete (void)
}
/* 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;
@@ -376,11 +312,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 +360,6 @@ vddk_open (int readonly)
{
struct vddk_handle *h;
VixError err;
- uint32_t flags;
h = malloc (sizeof *h);
if (h == NULL) {
@@ -462,33 +397,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 +417,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,11 +431,9 @@ vddk_close (void *handle)
{
struct vddk_handle *h = handle;
+ octhread_do_VixDiskLib_Close (h->handle);
+ octhread_do_VixDiskLib_Disconnect (h->connection);
free_connect_params (h->params);
- DEBUG_CALL ("VixDiskLib_Close", "handle");
- VixDiskLib_Close (h->handle);
- DEBUG_CALL ("VixDiskLib_Disconnect", "connection");
- VixDiskLib_Disconnect (h->connection);
free (h);
}
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 */
--
2.23.0