All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Denis V. Lunev" <den@openvz.org>
To: qemu-devel@nongnu.org
Cc: den@openvz.org, Denis Plotnikov <dplotnikov@virtuozzo.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: [Qemu-devel] [PATCH 1/1] qemu-nbd: add the option to use pre-created server socket
Date: Thu, 29 Sep 2016 14:02:15 +0300	[thread overview]
Message-ID: <1475146935-12118-1-git-send-email-den@openvz.org> (raw)

From: Denis Plotnikov <dplotnikov@virtuozzo.com>

Originally NBD server socket was created by qemu-nbd code. This leads to
the race when the management layer starts qemu-nbd server and allows a
client to connect to the server. In this case there is a possibility that
qemu-nbd does not open listening server socket yet. Creating listening
socket before starting of qemu-ndb and passing socket fd via command line
solves this issue completely.

Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
Reviewed-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Paolo Bonzini <pbonzini@redhat.com>
---
 qemu-nbd.c    | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 qemu-nbd.texi |  6 ++++
 2 files changed, 84 insertions(+), 10 deletions(-)

diff --git a/qemu-nbd.c b/qemu-nbd.c
index 99297a5..99bba38 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -48,6 +48,7 @@
 #define QEMU_NBD_OPT_OBJECT        260
 #define QEMU_NBD_OPT_TLSCREDS      261
 #define QEMU_NBD_OPT_IMAGE_OPTS    262
+#define QEMU_NBD_OPT_SRV_SOCKET_FD 263
 
 #define MBR_SIZE 512
 
@@ -78,6 +79,7 @@ static void usage(const char *name)
 "  -b, --bind=IFACE          interface to bind to (default `0.0.0.0')\n"
 "  -k, --socket=PATH         path to the unix socket\n"
 "                            (default '"SOCKET_PATH"')\n"
+"  --server-sock-fd=NUM      pre-opened listening server socket file descriptor\n"
 "  -e, --shared=NUM          device can be shared by NUM clients (default '1')\n"
 "  -t, --persistent          don't exit on the last connection\n"
 "  -v, --verbose             display extra debugging information\n"
@@ -382,7 +384,7 @@ static void nbd_update_server_watch(void)
 }
 
 
-static SocketAddress *nbd_build_socket_address(const char *sockpath,
+static SocketAddress *nbd_build_sock_fd(const char *sockpath,
                                                const char *bindto,
                                                const char *port)
 {
@@ -459,6 +461,41 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
     return creds;
 }
 
+static void setup_address_and_port(const char **address, const char **port)
+{
+    if (*address == NULL) {
+        *address = "0.0.0.0";
+    }
+
+    if (*port == NULL) {
+        *port = g_strdup_printf("%d", NBD_DEFAULT_PORT);;
+    }
+}
+
+/*
++ * Check socket parameters compatibility when sock_fd is given
++ */
+static const char *sock_fd_validate_opts(char *device, char *sockpath,
+                                         const char *address, const char *port)
+{
+    if (device != NULL) {
+        return "NBD device can't be set when socket fd is specified";
+    }
+
+    if (sockpath != NULL) {
+        return "Unix socket can't be set when socket fd is specified";
+    }
+
+    if (address != NULL) {
+        return "The interface can't be set when socket fd is specified";
+    }
+
+    if (port != NULL) {
+        return "TCP port number can't be set when socket fd is specified";
+    }
+
+    return NULL;
+}
 
 int main(int argc, char **argv)
 {
@@ -467,7 +504,7 @@ int main(int argc, char **argv)
     off_t dev_offset = 0;
     uint16_t nbdflags = 0;
     bool disconnect = false;
-    const char *bindto = "0.0.0.0";
+    const char *bindto = NULL;
     const char *port = NULL;
     char *sockpath = NULL;
     char *device = NULL;
@@ -503,6 +540,8 @@ int main(int argc, char **argv)
         { "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
         { "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
         { "trace", required_argument, NULL, 'T' },
+        { "server-sock-fd", required_argument, NULL,
+          QEMU_NBD_OPT_SRV_SOCKET_FD },
         { NULL, 0, NULL, 0 }
     };
     int ch;
@@ -524,6 +563,7 @@ int main(int argc, char **argv)
     bool imageOpts = false;
     bool writethrough = true;
     char *trace_file = NULL;
+    int sock_fd = -1;
 
     /* The client thread uses SIGTERM to interrupt the server.  A signal
      * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -714,6 +754,15 @@ int main(int argc, char **argv)
             g_free(trace_file);
             trace_file = trace_opt_parse(optarg);
             break;
+        case QEMU_NBD_OPT_SRV_SOCKET_FD:
+            sock_fd = qemu_parse_fd(optarg);
+
+            if (sock_fd < 0) {
+                error_report("Invalid socket fd value: "
+                             "it must be a non-negative integer");
+                exit(EXIT_FAILURE);
+            }
+            break;
         }
     }
 
@@ -735,6 +784,17 @@ int main(int argc, char **argv)
     trace_init_file(trace_file);
     qemu_set_log(LOG_TRACE);
 
+    if (sock_fd != -1) {
+        const char *err_msg = sock_fd_validate_opts(device, sockpath,
+                                                    bindto, port);
+        if (err_msg != NULL) {
+            error_report("%s", err_msg);
+            exit(EXIT_FAILURE);
+        }
+    } else {
+        setup_address_and_port(&bindto, &port);
+    }
+
     if (tlscredsid) {
         if (sockpath) {
             error_report("TLS is only supported with IPv4/IPv6");
@@ -838,7 +898,22 @@ int main(int argc, char **argv)
         snprintf(sockpath, 128, SOCKET_PATH, basename(device));
     }
 
-    saddr = nbd_build_socket_address(sockpath, bindto, port);
+    if (sock_fd == -1) {
+        server_ioc = qio_channel_socket_new();
+        saddr = nbd_build_sock_fd(sockpath, bindto, port);
+        if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
+            object_unref(OBJECT(server_ioc));
+            error_report_err(local_err);
+            return 1;
+        }
+    } else {
+        server_ioc = qio_channel_socket_new_fd(sock_fd, &local_err);
+        if (server_ioc == NULL) {
+            error_report("Failed to use the given server socket fd: %s",
+                         error_get_pretty(local_err));
+            exit(EXIT_FAILURE);
+        }
+    }
 
     if (qemu_init_main_loop(&local_err)) {
         error_report_err(local_err);
@@ -921,13 +996,6 @@ int main(int argc, char **argv)
         newproto = true;
     }
 
-    server_ioc = qio_channel_socket_new();
-    if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
-        object_unref(OBJECT(server_ioc));
-        error_report_err(local_err);
-        return 1;
-    }
-
     if (device) {
         int ret;
 
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 91ebf04..4c9ea00 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -34,6 +34,12 @@ The offset into the image
 The interface to bind to (default @samp{0.0.0.0})
 @item -k, --socket=@var{path}
 Use a unix socket with path @var{path}
+@item --server-sock-fd=@var{fd_num}
+A server socket fd to be used for client connections.
+The socket fd must be configured and switched to listening
+state before passing to the program. The program uses
+the given socket fd as is, without any additional
+modifications.
 @item --image-opts
 Treat @var{filename} as a set of image options, instead of a plain
 filename. If this flag is specified, the @var{-f} flag should
-- 
2.7.4

             reply	other threads:[~2016-09-29 11:02 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-29 11:02 Denis V. Lunev [this message]
2016-09-29 11:13 ` [Qemu-devel] [PATCH 1/1] qemu-nbd: add the option to use pre-created server socket Daniel P. Berrange
2016-09-29 12:18   ` Paolo Bonzini
2016-09-29 12:32     ` Daniel P. Berrange
2016-09-29 13:41   ` Stefan Hajnoczi
2016-09-29 15:05 ` Eric Blake
2016-09-29 15:52 ` Denis V. Lunev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1475146935-12118-1-git-send-email-den@openvz.org \
    --to=den@openvz.org \
    --cc=dplotnikov@virtuozzo.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.