From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:52531) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TJ1zl-0008Dx-Ni for qemu-devel@nongnu.org; Tue, 02 Oct 2012 08:54:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TJ1zd-0003zv-CZ for qemu-devel@nongnu.org; Tue, 02 Oct 2012 08:54:41 -0400 Received: from mx1.redhat.com ([209.132.183.28]:10133) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TJ1zd-0003ya-2t for qemu-devel@nongnu.org; Tue, 02 Oct 2012 08:54:33 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q92CsWPA015191 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 2 Oct 2012 08:54:32 -0400 Date: Tue, 2 Oct 2012 09:37:51 -0300 From: Luiz Capitulino Message-ID: <20121002093751.1506f8aa@doriath.home> In-Reply-To: <1349103144-6827-9-git-send-email-pbonzini@redhat.com> References: <1349103144-6827-1-git-send-email-pbonzini@redhat.com> <1349103144-6827-9-git-send-email-pbonzini@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH v2 8/9] qmp: add NBD server commands List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Paolo Bonzini Cc: qemu-devel@nongnu.org On Mon, 1 Oct 2012 16:52:23 +0200 Paolo Bonzini wrote: > Adding an NBD server inside QEMU is trivial, since all the logic is > in nbd.c and can be shared easily between qemu-nbd and QEMU itself. > The main difference is that qemu-nbd serves a single unnamed export, > while QEMU serves named exports. > > Signed-off-by: Paolo Bonzini Acked-by: Luiz Capitulino > --- > Makefile.objs | 2 +- > blockdev-nbd.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > qapi-schema.json | 43 ++++++++++++++++++++ > qmp-commands.hx | 16 ++++++++ > 4 file modificati, 179 inserzioni(+). 1 rimozione(-) > create mode 100644 blockdev-nbd.c > > diff --git a/Makefile.objs b/Makefile.objs > index 124f783..40384ff 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -61,7 +61,7 @@ endif > # suppress *all* target specific code in case of system emulation, i.e. a > # single QEMU executable should support all CPUs and machines. > > -common-obj-y = $(block-obj-y) blockdev.o > +common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o > common-obj-y += net.o net/ > common-obj-y += qom/ > common-obj-y += readline.o console.o cursor.o > diff --git a/blockdev-nbd.c b/blockdev-nbd.c > new file mode 100644 > index 0000000..8031813 > --- /dev/null > +++ b/blockdev-nbd.c > @@ -0,0 +1,119 @@ > +/* > + * Serving QEMU block devices via NBD > + * > + * Copyright (c) 2012 Red Hat, Inc. > + * > + * Author: Paolo Bonzini > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * later. See the COPYING file in the top-level directory. > + */ > + > +#include "blockdev.h" > +#include "hw/block-common.h" > +#include "monitor.h" > +#include "qerror.h" > +#include "sysemu.h" > +#include "qmp-commands.h" > +#include "trace.h" > +#include "nbd.h" > +#include "qemu_socket.h" > + > +static int server_fd = -1; > + > +static void nbd_accept(void *opaque) > +{ > + struct sockaddr_in addr; > + socklen_t addr_len = sizeof(addr); > + > + int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); > + if (fd >= 0) { > + nbd_client_new(NULL, fd, nbd_client_put); > + } > +} > + > +void qmp_nbd_server_start(SocketAddress *addr, Error **errp) > +{ > + if (server_fd != -1) { > + error_setg(errp, "NBD server already running"); > + return; > + } > + > + server_fd = socket_listen(addr, errp); > + if (server_fd != -1) { > + qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL); > + } > +} > + > +/* Hook into the BlockDriverState notifiers to close the export when > + * the file is closed. > + */ > +typedef struct NBDCloseNotifier { > + Notifier n; > + NBDExport *exp; > + QTAILQ_ENTRY(NBDCloseNotifier) next; > +} NBDCloseNotifier; > + > +static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers = > + QTAILQ_HEAD_INITIALIZER(close_notifiers); > + > +static void nbd_close_notifier(Notifier *n, void *data) > +{ > + NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n); > + > + notifier_remove(&cn->n); > + QTAILQ_REMOVE(&close_notifiers, cn, next); > + > + nbd_export_close(cn->exp); > + nbd_export_put(cn->exp); > + g_free(cn); > +} > + > +static void nbd_server_put_ref(NBDExport *exp) > +{ > + BlockDriverState *bs = nbd_export_get_blockdev(exp); > + drive_put_ref(drive_get_by_blockdev(bs)); > +} > + > +void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, > + Error **errp) > +{ > + BlockDriverState *bs; > + NBDExport *exp; > + NBDCloseNotifier *n; > + > + if (nbd_export_find(device)) { > + error_setg(errp, "NBD server already exporting device '%s'", device); > + return; > + } > + > + bs = bdrv_find(device); > + if (!bs) { > + error_set(errp, QERR_DEVICE_NOT_FOUND, device); > + return; > + } > + > + exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, > + nbd_server_put_ref); > + > + nbd_export_set_name(exp, device); > + drive_get_ref(drive_get_by_blockdev(bs)); > + > + n = g_malloc0(sizeof(NBDCloseNotifier)); > + n->n.notify = nbd_close_notifier; > + n->exp = exp; > + bdrv_add_close_notifier(bs, &n->n); > + QTAILQ_INSERT_TAIL(&close_notifiers, n, next); > +} > + > +void qmp_nbd_server_stop(Error **errp) > +{ > + while (!QTAILQ_EMPTY(&close_notifiers)) { > + NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers); > + nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp)); > + } > + > + qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL); > + close(server_fd); > + server_fd = -1; > +} > diff --git a/qapi-schema.json b/qapi-schema.json > index b443a99..229421d 100644 > --- a/qapi-schema.json > +++ b/qapi-schema.json > @@ -2697,3 +2697,46 @@ > # Since: 0.14.0 > ## > { 'command': 'screendump', 'data': {'filename': 'str'} } > + > +## > +# @nbd-server-start: > +# > +# Start an NBD server listening on the given host and port. Block > +# devices can then be exported using @nbd-server-add. The NBD > +# server will present them as named exports; for example, another > +# QEMU instance could refer to them as "nbd:HOST:PORT:exportname=NAME". > +# > +# @addr: Address on which to listen. > +# > +# Returns: error if the server is already running. > +# > +# Since: 1.3.0 > +## > +{ 'command': 'nbd-server-start', > + 'data': { 'addr': 'SocketAddress' } } > + > +## > +# @nbd-server-add: > +# > +# Export a device to QEMU's embedded NBD server. > +# > +# @device: Block device to be exported > +# > +# @writable: Whether clients should be able to write to the device via the > +# NBD connection (default false). #optional > +# > +# Returns: error if the device is already marked for export. > +# > +# Since: 1.3.0 > +## > +{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool'} } > + > +## > +# @nbd-server-stop: > +# > +# Stop QEMU's embedded NBD server, and unregister all devices previously > +# added via @nbd-server-add. > +# > +# Since: 1.3.0 > +## > +{ 'command': 'nbd-server-stop' } > diff --git a/qmp-commands.hx b/qmp-commands.hx > index 36e08d9..c394af0 100644 > --- a/qmp-commands.hx > +++ b/qmp-commands.hx > @@ -2503,6 +2503,22 @@ EQMP > }, > > { > + .name = "nbd-server-start", > + .args_type = "addr:q", > + .mhandler.cmd_new = qmp_marshal_input_nbd_server_start, > + }, > + { > + .name = "nbd-server-add", > + .args_type = "device:B,writable:b?", > + .mhandler.cmd_new = qmp_marshal_input_nbd_server_add, > + }, > + { > + .name = "nbd-server-stop", > + .args_type = "", > + .mhandler.cmd_new = qmp_marshal_input_nbd_server_stop, > + }, > + > + { > .name = "change-vnc-password", > .args_type = "password:s", > .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,