Blame SOURCES/0082-p2v-wait-for-qemu-nbd-before-starting-conversion-RHB.patch

0d20ef
From 770be29b68b151964aff988de606963eaf04dbe3 Mon Sep 17 00:00:00 2001
0d20ef
From: John Eckersberg <jeckersb@redhat.com>
0d20ef
Date: Fri, 5 Dec 2014 16:58:13 -0500
0d20ef
Subject: [PATCH] p2v: wait for qemu-nbd before starting conversion
0d20ef
 (RHBZ#1167774)
0d20ef
0d20ef
Wait up to 10 seconds for qemu-nbd to start up and respond to clients.
0d20ef
Otherwise the conversion server may attempt to connect before qemu-nbd
0d20ef
is ready to serve it.
0d20ef
0d20ef
(cherry picked from commit 33098d23020bd3824a2954823a0dbaff751c814d)
0d20ef
---
0d20ef
 p2v/conversion.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0d20ef
 1 file changed, 76 insertions(+)
0d20ef
0d20ef
diff --git a/p2v/conversion.c b/p2v/conversion.c
0d20ef
index cb2deed..9f5a3ad 100644
0d20ef
--- a/p2v/conversion.c
0d20ef
+++ b/p2v/conversion.c
0d20ef
@@ -31,6 +31,8 @@
0d20ef
 #include <libintl.h>
0d20ef
 #include <sys/types.h>
0d20ef
 #include <sys/wait.h>
0d20ef
+#include <arpa/inet.h>
0d20ef
+#include <netinet/in.h>
0d20ef
 
0d20ef
 #include <glib.h>
0d20ef
 
0d20ef
@@ -39,6 +41,9 @@
0d20ef
 #include "miniexpect.h"
0d20ef
 #include "p2v.h"
0d20ef
 
0d20ef
+/* How long to wait for qemu-nbd to start (seconds). */
0d20ef
+#define WAIT_QEMU_NBD_TIMEOUT 10
0d20ef
+
0d20ef
 /* Data per NBD connection / physical disk. */
0d20ef
 struct data_conn {
0d20ef
   mexp_h *h;                /* miniexpect handle to ssh */
0d20ef
@@ -49,6 +54,7 @@ struct data_conn {
0d20ef
 
0d20ef
 static int send_quoted (mexp_h *, const char *s);
0d20ef
 static pid_t start_qemu_nbd (int nbd_local_port, const char *device);
0d20ef
+static int wait_qemu_nbd (int nbd_local_port, int timeout_seconds);
0d20ef
 static void cleanup_data_conns (struct data_conn *data_conns, size_t nr);
0d20ef
 static char *generate_libvirt_xml (struct config *, struct data_conn *);
0d20ef
 static const char *map_interface_to_network (struct config *, const char *interface);
0d20ef
@@ -156,6 +162,11 @@ start_conversion (struct config *config,
0d20ef
     if (data_conns[i].nbd_pid == 0)
0d20ef
       goto out;
0d20ef
 
0d20ef
+    /* Wait for qemu-nbd to listen */
0d20ef
+    if (wait_qemu_nbd (data_conns[i].nbd_local_port,
0d20ef
+                       WAIT_QEMU_NBD_TIMEOUT) == -1)
0d20ef
+      goto out;
0d20ef
+
0d20ef
 #if DEBUG_STDERR
0d20ef
     fprintf (stderr,
0d20ef
              "%s: data connection for %s: SSH remote port %d, local port %d\n",
0d20ef
@@ -371,6 +382,71 @@ start_qemu_nbd (int port, const char *device)
0d20ef
   return pid;
0d20ef
 }
0d20ef
 
0d20ef
+static int
0d20ef
+wait_qemu_nbd (int nbd_local_port, int timeout_seconds)
0d20ef
+{
0d20ef
+  int sockfd;
0d20ef
+  int result = -1;
0d20ef
+  struct sockaddr_in addr;
0d20ef
+  time_t start_t, now_t;
0d20ef
+  struct timeval timeout = { .tv_usec = 0 };
0d20ef
+  char magic[8]; /* NBDMAGIC */
0d20ef
+  size_t bytes_read = 0;
0d20ef
+  ssize_t recvd;
0d20ef
+
0d20ef
+  time (&start_t);
0d20ef
+
0d20ef
+  sockfd = socket (AF_INET, SOCK_STREAM, 0);
0d20ef
+  if (sockfd == -1) {
0d20ef
+    perror ("socket");
0d20ef
+    return -1;
0d20ef
+  }
0d20ef
+
0d20ef
+  memset (&addr, 0, sizeof addr);
0d20ef
+  addr.sin_family = AF_INET;
0d20ef
+  addr.sin_port = htons (nbd_local_port);
0d20ef
+  inet_pton (AF_INET, "localhost", &addr.sin_addr);
0d20ef
+
0d20ef
+  for (;;) {
0d20ef
+    time (&now_t);
0d20ef
+
0d20ef
+    if (now_t - start_t >= timeout_seconds) {
0d20ef
+      set_conversion_error ("waiting for qemu-nbd to start: connect: %m");
0d20ef
+      goto cleanup;
0d20ef
+    }
0d20ef
+
0d20ef
+    if (connect (sockfd, (struct sockaddr *) &addr, sizeof addr) == 0)
0d20ef
+      break;
0d20ef
+  }
0d20ef
+
0d20ef
+  time (&now_t);
0d20ef
+  timeout.tv_sec = (start_t + timeout_seconds) - now_t;
0d20ef
+  setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);
0d20ef
+
0d20ef
+  do {
0d20ef
+    recvd = recv (sockfd, magic, sizeof magic - bytes_read, 0);
0d20ef
+
0d20ef
+    if (recvd == -1) {
0d20ef
+      set_conversion_error ("waiting for qemu-nbd to start: recv: %m");
0d20ef
+      goto cleanup;
0d20ef
+    }
0d20ef
+
0d20ef
+    bytes_read += recvd;
0d20ef
+  } while (bytes_read < sizeof magic);
0d20ef
+
0d20ef
+  if (memcmp (magic, "NBDMAGIC", sizeof magic) != 0) {
0d20ef
+    set_conversion_error ("waiting for qemu-nbd to start: "
0d20ef
+                          "'NBDMAGIC' was not received from qemu-nbd");
0d20ef
+    goto cleanup;
0d20ef
+  }
0d20ef
+
0d20ef
+  result = 0;
0d20ef
+cleanup:
0d20ef
+  close (sockfd);
0d20ef
+
0d20ef
+  return result;
0d20ef
+}
0d20ef
+
0d20ef
 static void
0d20ef
 cleanup_data_conns (struct data_conn *data_conns, size_t nr)
0d20ef
 {
0d20ef
-- 
0d20ef
1.8.3.1
0d20ef