From patchwork Tue Oct 4 11:03:01 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev" X-Patchwork-Id: 9361593 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3DED760752 for ; Tue, 4 Oct 2016 11:03:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2CC75289C1 for ; Tue, 4 Oct 2016 11:03:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2047328A1F; Tue, 4 Oct 2016 11:03:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 048DD289C1 for ; Tue, 4 Oct 2016 11:03:41 +0000 (UTC) Received: from localhost ([::1]:41498 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1brNVc-000797-6f for patchwork-qemu-devel@patchwork.kernel.org; Tue, 04 Oct 2016 07:03:40 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37857) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1brNV9-000754-Rl for qemu-devel@nongnu.org; Tue, 04 Oct 2016 07:03:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1brNV3-0007oh-RT for qemu-devel@nongnu.org; Tue, 04 Oct 2016 07:03:10 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:36138 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1brNV3-0007mi-4t for qemu-devel@nongnu.org; Tue, 04 Oct 2016 07:03:05 -0400 Received: from iris.sw.ru ([10.30.2.139]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id u94B310A002320; Tue, 4 Oct 2016 14:03:01 +0300 (MSK) From: "Denis V. Lunev" To: qemu-devel@nongnu.org Date: Tue, 4 Oct 2016 14:03:01 +0300 Message-Id: <1475578981-24126-1-git-send-email-den@openvz.org> X-Mailer: git-send-email 2.7.4 X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH v2 1/1] qemu-nbd: add the option to use pre-created server socket X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: den@openvz.org, Denis Plotnikov , Paolo Bonzini Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Denis Plotnikov The NBD server socket was created by qemu-nbd code. This could lead to the race issue when the management layer started qemu-nbd server and allowed a client to connect to the server, the client tried to connect to the server but failed because qemu-nbd had not managed to open the listening server socket by the time the client has finished its trying to connect. Creating a listening socket before starting of qemu-ndb and passing the socket fd to be used as the server socket to qemu-nbd as an option solves this issue. It also helps to resolve the situation when qemu-nbd started by some management software should report the port number qemu-nbd bound to, to another piece of software. Right now, there is no good way to do that except to start the qemu-nbd to make sure that the certain port has been actually aquired. Otherwise, it is definitely racy to try to define the port first and then start the qemu-nbd, hoping that the port defined is still available. Passing of the pre-created file descriptor resolves this situation as well. As a plus, pre-creating of the server socket adds some degree of freedom in setting of the socket properties. It is so, because once qemu-nbd gets the socket fd, it starts using it as is, without any additional modifications. Signed-off-by: Denis Plotnikov Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini --- qemu-nbd.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- qemu-nbd.texi | 6 ++++ 2 files changed, 89 insertions(+), 12 deletions(-) Changes from v1: - commit message improvements - Eric's style nits applied diff --git a/qemu-nbd.c b/qemu-nbd.c index 99297a5..3b6319e 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -48,9 +48,13 @@ #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 +#define STR(s) _STR(s) +#define _STR(s) #s + static NBDExport *exp; static bool newproto; static int verbose; @@ -78,6 +82,8 @@ 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\n" +" 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,9 +388,8 @@ static void nbd_update_server_watch(void) } -static SocketAddress *nbd_build_socket_address(const char *sockpath, - const char *bindto, - const char *port) +static SocketAddress *nbd_build_sock_fd(const char *sockpath, + const char *bindto, const char *port) { SocketAddress *saddr; @@ -459,6 +464,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 = STR(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 +507,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 +543,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 +566,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 +757,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 +787,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 +901,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 +999,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