[Libguestfs] [PATCH nbdkit 2/4] server: Add nbdkit_shutdown() call.

Richard W.M. Jones rjones at redhat.com
Wed Mar 4 15:17:24 UTC 2020


Plugins and filters may call this to initiate an asynchronous shutdown
of the server.  This would only be used in the connected phase —
plugins should still call exit(3) directly for configuration failure.

It is equivalent to sending a kill signal to self, but it's cleaner to
have an API for this and better for potential future non-POSIX platforms.
---
 docs/nbdkit-plugin.pod       | 19 +++++++-
 include/nbdkit-common.h      |  1 +
 include/nbdkit-plugin.h      |  2 +-
 tests/Makefile.am            | 20 ++++++++
 server/nbdkit.syms           |  3 +-
 server/quit.c                |  8 +++-
 tests/test-shutdown.sh       | 71 ++++++++++++++++++++++++++++
 tests/test-shutdown-plugin.c | 89 ++++++++++++++++++++++++++++++++++++
 8 files changed, 209 insertions(+), 4 deletions(-)

diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index 77f1a098..494d77f8 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -1058,6 +1058,23 @@ before unloading the plugin.
 Note that it's not guaranteed this can always happen (eg. the server
 might be killed by C<SIGKILL> or segfault).
 
+=head2 Requesting asynchronous shutdown
+
+Plugins and filters can call L<exit(3)> in the configuration phase
+(before and including C<.get_ready>, but not in connected callbacks).
+
+Once nbdkit has started serving connections, plugins and filters
+should not call L<exit(3)>.  However they may instruct nbdkit to shut
+down by calling C<nbdkit_shutdown>:
+
+ void nbdkit_shutdown (void);
+
+This function requests an asynchronous shutdown and returns (I<note>
+that it does I<not> exit the process immediately).  It ensures that
+the plugin and all filters are unloaded cleanly which may take some
+time.  Further callbacks from nbdkit into the plugin or filter may
+occur after you have called this.
+
 =head1 PARSING COMMAND LINE PARAMETERS
 
 =head2 Parsing numbers
@@ -1443,4 +1460,4 @@ Pino Toscano
 
 =head1 COPYRIGHT
 
-Copyright (C) 2013-2018 Red Hat Inc.
+Copyright (C) 2013-2020 Red Hat Inc.
diff --git a/include/nbdkit-common.h b/include/nbdkit-common.h
index 50f3dd4f..9d1d89d0 100644
--- a/include/nbdkit-common.h
+++ b/include/nbdkit-common.h
@@ -111,6 +111,7 @@ extern char *nbdkit_realpath (const char *path);
 extern int nbdkit_nanosleep (unsigned sec, unsigned nsec);
 extern const char *nbdkit_export_name (void);
 extern int nbdkit_peer_name (struct sockaddr *addr, socklen_t *addrlen);
+extern void nbdkit_shutdown (void);
 
 struct nbdkit_extents;
 extern int nbdkit_add_extent (struct nbdkit_extents *,
diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h
index 7e06a4b1..7ff7bcee 100644
--- a/include/nbdkit-plugin.h
+++ b/include/nbdkit-plugin.h
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2013-2019 Red Hat Inc.
+ * Copyright (C) 2013-2020 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2dc35309..eb51757a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -265,6 +265,7 @@ TESTS += \
 	test-debug-flags.sh \
 	test-long-name.sh \
 	test-swap.sh \
+	test-shutdown.sh \
 	$(NULL)
 
 check_PROGRAMS += \
@@ -278,6 +279,25 @@ test_socket_activation_CPPFLAGS = \
 	$(NULL)
 test_socket_activation_CFLAGS = $(WARNINGS_CFLAGS)
 
+# check_LTLIBRARIES won't build a shared library (see automake manual).
+# So we have to do this and add a dependency.
+noinst_LTLIBRARIES += \
+	test-shutdown-plugin.la \
+	$(NULL)
+test-shutdown.sh: test-shutdown-plugin.la
+
+test_shutdown_plugin_la_SOURCES = \
+	test-shutdown-plugin.c \
+	$(top_srcdir)/include/nbdkit-plugin.h \
+	$(NULL)
+test_shutdown_plugin_la_CPPFLAGS = -I$(top_srcdir)/include
+test_shutdown_plugin_la_CFLAGS = $(WARNINGS_CFLAGS)
+# For use of the -rpath option, see:
+# https://lists.gnu.org/archive/html/libtool/2007-07/msg00067.html
+test_shutdown_plugin_la_LDFLAGS = \
+	-module -avoid-version -shared -rpath /nowhere \
+	$(NULL)
+
 endif HAVE_PLUGINS
 
 # Test the header files can be included on their own.
diff --git a/server/nbdkit.syms b/server/nbdkit.syms
index 96c22c07..111223f2 100644
--- a/server/nbdkit.syms
+++ b/server/nbdkit.syms
@@ -1,5 +1,5 @@
 # nbdkit
-# Copyright (C) 2018 Red Hat Inc.
+# Copyright (C) 2018-2020 Red Hat Inc.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
@@ -64,6 +64,7 @@
     nbdkit_read_password;
     nbdkit_realpath;
     nbdkit_set_error;
+    nbdkit_shutdown;
     nbdkit_vdebug;
     nbdkit_verror;
 
diff --git a/server/quit.c b/server/quit.c
index bff8ac7c..13fef437 100644
--- a/server/quit.c
+++ b/server/quit.c
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2019 Red Hat Inc.
+ * Copyright (C) 2019-2020 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -104,3 +104,9 @@ handle_quit (int sig)
 {
   set_quit ();
 }
+
+void
+nbdkit_shutdown (void)
+{
+  set_quit ();
+}
diff --git a/tests/test-shutdown.sh b/tests/test-shutdown.sh
new file mode 100755
index 00000000..fa09dce9
--- /dev/null
+++ b/tests/test-shutdown.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2019-2020 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.
+
+source ./functions.sh
+set -x
+
+requires qemu-img --version
+requires qemu-io --version
+
+plugin=.libs/test-shutdown-plugin.so
+requires test -f $plugin
+
+sock=`mktemp -u`
+files="shutdown.pid $sock"
+cleanup_fn rm -f $files
+
+# Start nbdkit with the shutdown plugin.
+start_nbdkit -P shutdown.pid -U $sock $plugin
+
+pid=`cat shutdown.pid`
+
+# Reads are fine, nbdkit should still be running afterwards.
+for i in 1 2 3; do
+    qemu-img info "nbd:unix:$sock"
+    sleep 2
+    kill -s 0 $pid
+done
+
+# Writing should cause nbdkit to exit, although it may take time.
+qemu-io -f raw -c 'w -P 0x55 0 1024' "nbd:unix:$sock"
+
+# Wait for nbdkit process to exit
+for i in {1..60}; do
+    if ! kill -s 0 $pid; then
+        break
+    fi
+    sleep 1
+done
+if kill -s 0 $pid; then
+    echo "$0: nbdkit $plugin did not exit as expected"
+    exit 1
+fi
diff --git a/tests/test-shutdown-plugin.c b/tests/test-shutdown-plugin.c
new file mode 100644
index 00000000..4ec98538
--- /dev/null
+++ b/tests/test-shutdown-plugin.c
@@ -0,0 +1,89 @@
+/* nbdkit
+ * Copyright (C) 2013-2020 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.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nbdkit-plugin.h>
+
+static void
+shutdown_unload (void)
+{
+  nbdkit_debug ("clean shutdown");
+}
+
+static void *
+shutdown_open (int readonly)
+{
+  return NBDKIT_HANDLE_NOT_NEEDED;
+}
+
+static int64_t
+shutdown_get_size (void *handle)
+{
+  return INT64_C (1024*1024);
+}
+
+#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
+
+static int
+shutdown_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
+{
+  memset (buf, 0, count);
+  return 0;
+}
+
+/* Writing 0x55 to any location causes a shutdown. */
+static int
+shutdown_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
+{
+  if (memchr (buf, 0x55, count) != NULL) {
+    nbdkit_debug ("shutdown triggered!");
+    nbdkit_shutdown ();
+  }
+  return 0;
+}
+
+static struct nbdkit_plugin plugin = {
+  .name              = "shutdown",
+  .version           = PACKAGE_VERSION,
+  .unload            = shutdown_unload,
+  .open              = shutdown_open,
+  .get_size          = shutdown_get_size,
+  .pread             = shutdown_pread,
+  .pwrite            = shutdown_pwrite,
+};
+
+NBDKIT_REGISTER_PLUGIN(plugin)
-- 
2.25.0




More information about the Libguestfs mailing list