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