[Libguestfs] [nbdkit PATCH 1/2] nbd: Add retry=N parameter

Eric Blake
Sat, 25 May 2019 22:32:23 -0000

A common command line use case for the nbd plugin is
 ( sock=`mktemp -u` &&
   nbdkit --exit-with-parent nbd socket=$sock &
   exec /path/to/server -k $sock)

As long as the first client to nbdkit doesn't try to connect until
after /path/to/server has created $sock, we are fine. But on a heavily
loaded system, it would be nice to give nbdkit some leeway to try
again to connect to the socket if a client connects quickly to nbdkit.

This becomes even more useful in the next patch when adding an option
for the nbd plugin to connect during .config_complete rather than
during .open, as the window of time for the external server to make
the socket available is no longer dependent on when nbdkit's first
client arrives.

Signed-off-by: Eric Blake <eblake@redhat.com>
---
 plugins/nbd/nbdkit-nbd-plugin.pod |  6 ++++++
 plugins/nbd/nbd.c                 | 24 ++++++++++++++++++++++--
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/plugins/nbd/nbdkit-nbd-plugin.pod
b/plugins/nbd/nbdkit-nbd-plugin.pod
index 913d1e5..4f9efa1 100644
--- a/plugins/nbd/nbdkit-nbd-plugin.pod
+++ b/plugins/nbd/nbdkit-nbd-plugin.pod
@@ -5,6 +5,7 @@ nbdkit-nbd-plugin - nbdkit nbd plugin
 =head1 SYNOPSIS

  nbdkit nbd { socket=SOCKNAME | hostname=HOST [port=PORT] } [export=NAME]
+    [retry=N]

 =head1 DESCRIPTION

@@ -50,6 +51,11 @@ If this parameter is given, and the server speaks new style
protocol,
 then connect to the named export instead of the default export (the
 empty string).

+=item B<retry=>N
+
+If the initial connection attempt to the server fails, retry up to
+B<N> times more after a second delay between tries (default 0).
+
 =back

 =head1 EXAMPLES
diff --git a/plugins/nbd/nbd.c b/plugins/nbd/nbd.c
index 1195eb8..6665cd9 100644
--- a/plugins/nbd/nbd.c
+++ b/plugins/nbd/nbd.c
@@ -70,6 +70,9 @@ static char *servname;
 /* Name of export on remote server, default '', ignored for oldstyle */
 static const char *export;

+/* Number of retries */
+static unsigned long retry;
+
 static void
 nbd_unload (void)
 {
@@ -79,11 +82,14 @@ nbd_unload (void)

 /* Called for each key=value passed on the command line.  This plugin
  * accepts socket=<sockname> or
hostname=<hostname>/port=<port>
- * (exactly one connection required) and export=<name> (optional).
+ * (exactly one connection required), and optional parameters
+ * export=<name>, retry=<n>.
  */
 static int
 nbd_config (const char *key, const char *value)
 {
+  char *end;
+
   if (strcmp (key, "socket") == 0) {
     /* See FILENAMES AND PATHS in nbdkit-plugin(3) */
     free (sockname);
@@ -97,6 +103,14 @@ nbd_config (const char *key, const char *value)
     port = value;
   else if (strcmp (key, "export") == 0)
     export = value;
+  else if (strcmp (key, "retry") == 0) {
+    errno = 0;
+    retry = strtoul (value, &end, 0);
+    if (value == end || errno) {
+      nbdkit_error ("could not parse retry as integer (%s)", value);
+      return -1;
+    }
+  }
   else {
     nbdkit_error ("unknown parameter '%s'", key);
     return -1;
@@ -960,12 +974,18 @@ nbd_open (int readonly)
     return NULL;
   }

+ retry:
   if (sockname)
     h->fd = nbd_connect_unix ();
   else
     h->fd = nbd_connect_tcp ();
-  if (h->fd == -1)
+  if (h->fd == -1) {
+    if (retry--) {
+      sleep (1);
+      goto retry;
+    }
     goto err;
+  }

   /* old and new handshake share same meaning of first 16 bytes */
   if (read_full (h->fd, &old, offsetof (struct old_handshake,
exportsize))) {
--
2.20.1