* [Qemu-devel] [PATCH 01/21] vscclient: do not add a socket watch if there is not data to send
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 02/21] spice-char: remove unused field Marc-André Lureau
` (20 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Fixes the following error:
** (process:780): CRITICAL **: do_socket_send: assertion
`socket_to_send->len != 0' failed
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
libcacard/vscclient.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index a3cb776..c413a4f 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -58,7 +58,7 @@ static QemuMutex socket_to_send_lock;
static guint socket_tag;
static void
-update_socket_watch(gboolean out);
+update_socket_watch(void);
static gboolean
do_socket_send(GIOChannel *source,
@@ -80,7 +80,7 @@ do_socket_send(GIOChannel *source,
g_byte_array_remove_range(socket_to_send, 0, bw);
if (socket_to_send->len == 0) {
- update_socket_watch(FALSE);
+ update_socket_watch();
return FALSE;
}
return TRUE;
@@ -89,7 +89,7 @@ do_socket_send(GIOChannel *source,
static gboolean
socket_prepare_sending(gpointer user_data)
{
- update_socket_watch(TRUE);
+ update_socket_watch();
return FALSE;
}
@@ -440,8 +440,10 @@ do_socket(GIOChannel *source,
}
static void
-update_socket_watch(gboolean out)
+update_socket_watch(void)
{
+ gboolean out = socket_to_send->len > 0;
+
if (socket_tag != 0) {
g_source_remove(socket_tag);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 02/21] spice-char: remove unused field
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 01/21] vscclient: do not add a socket watch if there is not data to send Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 03/21] qmp_change_blockdev() remove unused has_format Marc-André Lureau
` (19 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel,
Marc-André Lureau
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
spice-qemu-char.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 6d147a7..e074d9e 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -11,7 +11,6 @@
typedef struct SpiceCharDriver {
CharDriverState* chr;
SpiceCharDeviceInstance sin;
- char *subtype;
bool active;
bool blocked;
const uint8_t *datapos;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 03/21] qmp_change_blockdev() remove unused has_format
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 01/21] vscclient: do not add a socket watch if there is not data to send Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 02/21] spice-char: remove unused field Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 04/21] include: add missing config-host.h include Marc-André Lureau
` (18 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel,
Marc-André Lureau
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
blockdev.c | 2 +-
include/sysemu/blockdev.h | 2 +-
qmp.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 86e6bff..b8db544 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1524,7 +1524,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
}
void qmp_change_blockdev(const char *device, const char *filename,
- bool has_format, const char *format, Error **errp)
+ const char *format, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv = NULL;
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 1082091..134712b 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -64,7 +64,7 @@ DriveInfo *drive_init(QemuOpts *arg, BlockInterfaceType block_default_type);
DriveInfo *add_init_drive(const char *opts);
void qmp_change_blockdev(const char *device, const char *filename,
- bool has_format, const char *format, Error **errp);
+ const char *format, Error **errp);
void do_commit(Monitor *mon, const QDict *qdict);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
#endif
diff --git a/qmp.c b/qmp.c
index 4c149b3..1d7a04d 100644
--- a/qmp.c
+++ b/qmp.c
@@ -400,7 +400,7 @@ void qmp_change(const char *device, const char *target,
if (strcmp(device, "vnc") == 0) {
qmp_change_vnc(target, has_arg, arg, err);
} else {
- qmp_change_blockdev(device, target, has_arg, arg, err);
+ qmp_change_blockdev(device, target, arg, err);
}
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 04/21] include: add missing config-host.h include
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (2 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 03/21] qmp_change_blockdev() remove unused has_format Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 05/21] char: add qemu_chr_fe_event() Marc-André Lureau
` (17 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/qemu-spice.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index 86c75c7..a93b4b2 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -18,6 +18,8 @@
#ifndef QEMU_SPICE_H
#define QEMU_SPICE_H
+#include "config-host.h"
+
#ifdef CONFIG_SPICE
#include <spice.h>
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 05/21] char: add qemu_chr_fe_event()
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (3 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 04/21] include: add missing config-host.h include Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:36 ` Alon Levy
2013-11-18 12:25 ` [Qemu-devel] [PATCH 06/21] Split nbd block client code Marc-André Lureau
` (16 subsequent siblings)
21 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/sysemu/char.h | 10 ++++++++++
qemu-char.c | 7 +++++++
spice-qemu-char.c | 10 ++++++++++
3 files changed, 27 insertions(+)
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index ad101d9..d23c8f1 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -69,6 +69,7 @@ struct CharDriverState {
void (*chr_accept_input)(struct CharDriverState *chr);
void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
+ void (*chr_fe_event)(struct CharDriverState *chr, int event);
void *opaque;
char *label;
char *filename;
@@ -138,6 +139,15 @@ void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo);
void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open);
/**
+ * @qemu_chr_fe_event:
+ *
+ * Send an event from the back end to the front end.
+ *
+ * @event the event to send
+ */
+void qemu_chr_fe_event(CharDriverState *s, int event);
+
+/**
* @qemu_chr_fe_printf:
*
* Write to a character backend using a printf style interface.
diff --git a/qemu-char.c b/qemu-char.c
index e00f84c..418dc69 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3353,6 +3353,13 @@ void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open)
}
}
+void qemu_chr_fe_event(struct CharDriverState *chr, int event)
+{
+ if (chr->chr_fe_event) {
+ chr->chr_fe_event(chr, event);
+ }
+}
+
int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
GIOFunc func, void *user_data)
{
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index e074d9e..16439c5 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -222,6 +222,15 @@ static void spice_chr_set_fe_open(struct CharDriverState *chr, int fe_open)
}
}
+static void spice_chr_fe_event(struct CharDriverState *chr, int event)
+{
+#if SPICE_SERVER_VERSION >= 0x000c02
+ SpiceCharDriver *s = chr->opaque;
+
+ spice_server_port_event(&s->sin, event);
+#endif
+}
+
static void print_allowed_subtypes(void)
{
const char** psubtype;
@@ -255,6 +264,7 @@ static CharDriverState *chr_open(const char *subtype)
chr->chr_close = spice_chr_close;
chr->chr_set_fe_open = spice_chr_set_fe_open;
chr->explicit_be_open = true;
+ chr->chr_fe_event = spice_chr_fe_event;
QLIST_INSERT_HEAD(&spice_chars, s, next);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 05/21] char: add qemu_chr_fe_event()
2013-11-18 12:25 ` [Qemu-devel] [PATCH 05/21] char: add qemu_chr_fe_event() Marc-André Lureau
@ 2013-11-18 12:36 ` Alon Levy
0 siblings, 0 replies; 28+ messages in thread
From: Alon Levy @ 2013-11-18 12:36 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
On 11/18/2013 02:25 PM, Marc-André Lureau wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
The patch description is incomplete, or the patch should be split - this
patch also implements qemu_chr_fe_event for spiceport.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/sysemu/char.h | 10 ++++++++++
> qemu-char.c | 7 +++++++
> spice-qemu-char.c | 10 ++++++++++
> 3 files changed, 27 insertions(+)
>
> diff --git a/include/sysemu/char.h b/include/sysemu/char.h
> index ad101d9..d23c8f1 100644
> --- a/include/sysemu/char.h
> +++ b/include/sysemu/char.h
> @@ -69,6 +69,7 @@ struct CharDriverState {
> void (*chr_accept_input)(struct CharDriverState *chr);
> void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
> void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
> + void (*chr_fe_event)(struct CharDriverState *chr, int event);
> void *opaque;
> char *label;
> char *filename;
> @@ -138,6 +139,15 @@ void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo);
> void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open);
>
> /**
> + * @qemu_chr_fe_event:
> + *
> + * Send an event from the back end to the front end.
> + *
> + * @event the event to send
> + */
> +void qemu_chr_fe_event(CharDriverState *s, int event);
> +
> +/**
> * @qemu_chr_fe_printf:
> *
> * Write to a character backend using a printf style interface.
> diff --git a/qemu-char.c b/qemu-char.c
> index e00f84c..418dc69 100644
> --- a/qemu-char.c
> +++ b/qemu-char.c
> @@ -3353,6 +3353,13 @@ void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open)
> }
> }
>
> +void qemu_chr_fe_event(struct CharDriverState *chr, int event)
> +{
> + if (chr->chr_fe_event) {
> + chr->chr_fe_event(chr, event);
> + }
> +}
> +
> int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
> GIOFunc func, void *user_data)
> {
> diff --git a/spice-qemu-char.c b/spice-qemu-char.c
> index e074d9e..16439c5 100644
> --- a/spice-qemu-char.c
> +++ b/spice-qemu-char.c
> @@ -222,6 +222,15 @@ static void spice_chr_set_fe_open(struct CharDriverState *chr, int fe_open)
> }
> }
>
> +static void spice_chr_fe_event(struct CharDriverState *chr, int event)
> +{
> +#if SPICE_SERVER_VERSION >= 0x000c02
> + SpiceCharDriver *s = chr->opaque;
> +
> + spice_server_port_event(&s->sin, event);
> +#endif
> +}
> +
> static void print_allowed_subtypes(void)
> {
> const char** psubtype;
> @@ -255,6 +264,7 @@ static CharDriverState *chr_open(const char *subtype)
> chr->chr_close = spice_chr_close;
> chr->chr_set_fe_open = spice_chr_set_fe_open;
> chr->explicit_be_open = true;
> + chr->chr_fe_event = spice_chr_fe_event;
>
> QLIST_INSERT_HEAD(&spice_chars, s, next);
>
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 06/21] Split nbd block client code
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (4 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 05/21] char: add qemu_chr_fe_event() Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 07/21] nbd: don't change socket block during negotiate Marc-André Lureau
` (15 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block/Makefile.objs | 2 +-
block/nbd-client.c | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++
block/nbd-client.h | 51 +++++++
block/nbd.c | 373 ++++------------------------------------------------
4 files changed, 452 insertions(+), 346 deletions(-)
create mode 100644 block/nbd-client.c
create mode 100644 block/nbd-client.h
diff --git a/block/Makefile.objs b/block/Makefile.objs
index f43ecbc..4e8c91e 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -10,7 +10,7 @@ block-obj-$(CONFIG_POSIX) += raw-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
ifeq ($(CONFIG_POSIX),y)
-block-obj-y += nbd.o sheepdog.o
+block-obj-y += nbd.o nbd-client.o sheepdog.o
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
diff --git a/block/nbd-client.c b/block/nbd-client.c
new file mode 100644
index 0000000..1abfc6a
--- /dev/null
+++ b/block/nbd-client.c
@@ -0,0 +1,372 @@
+/*
+ * QEMU Block driver for NBD
+ *
+ * Copyright (C) 2008 Bull S.A.S.
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * Some parts:
+ * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "nbd-client.h"
+#include "qemu/sockets.h"
+
+#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
+#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
+
+static void nbd_reply_ready(void *opaque)
+{
+ NbdClientSession *s = opaque;
+ uint64_t i;
+ int ret;
+
+ if (s->reply.handle == 0) {
+ /* No reply already in flight. Fetch a header. It is possible
+ * that another thread has done the same thing in parallel, so
+ * the socket is not readable anymore.
+ */
+ ret = nbd_receive_reply(s->sock, &s->reply);
+ if (ret == -EAGAIN) {
+ return;
+ }
+ if (ret < 0) {
+ s->reply.handle = 0;
+ goto fail;
+ }
+ }
+
+ /* There's no need for a mutex on the receive side, because the
+ * handler acts as a synchronization point and ensures that only
+ * one coroutine is called until the reply finishes. */
+ i = HANDLE_TO_INDEX(s, s->reply.handle);
+ if (i >= MAX_NBD_REQUESTS) {
+ goto fail;
+ }
+
+ if (s->recv_coroutine[i]) {
+ qemu_coroutine_enter(s->recv_coroutine[i], NULL);
+ return;
+ }
+
+fail:
+ for (i = 0; i < MAX_NBD_REQUESTS; i++) {
+ if (s->recv_coroutine[i]) {
+ qemu_coroutine_enter(s->recv_coroutine[i], NULL);
+ }
+ }
+}
+
+static void nbd_restart_write(void *opaque)
+{
+ NbdClientSession *s = opaque;
+
+ qemu_coroutine_enter(s->send_coroutine, NULL);
+}
+
+static int nbd_co_send_request(NbdClientSession *s,
+ struct nbd_request *request,
+ QEMUIOVector *qiov, int offset)
+{
+ int rc, ret;
+
+ qemu_co_mutex_lock(&s->send_mutex);
+ s->send_coroutine = qemu_coroutine_self();
+ qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write, s);
+ if (qiov) {
+ if (!s->is_unix) {
+ socket_set_cork(s->sock, 1);
+ }
+ rc = nbd_send_request(s->sock, request);
+ if (rc >= 0) {
+ ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
+ offset, request->len);
+ if (ret != request->len) {
+ rc = -EIO;
+ }
+ }
+ if (!s->is_unix) {
+ socket_set_cork(s->sock, 0);
+ }
+ } else {
+ rc = nbd_send_request(s->sock, request);
+ }
+ qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, s);
+ s->send_coroutine = NULL;
+ qemu_co_mutex_unlock(&s->send_mutex);
+ return rc;
+}
+
+static void nbd_co_receive_reply(NbdClientSession *s,
+ struct nbd_request *request, struct nbd_reply *reply,
+ QEMUIOVector *qiov, int offset)
+{
+ int ret;
+
+ /* Wait until we're woken up by the read handler. TODO: perhaps
+ * peek at the next reply and avoid yielding if it's ours? */
+ qemu_coroutine_yield();
+ *reply = s->reply;
+ if (reply->handle != request->handle) {
+ reply->error = EIO;
+ } else {
+ if (qiov && reply->error == 0) {
+ ret = qemu_co_recvv(s->sock, qiov->iov, qiov->niov,
+ offset, request->len);
+ if (ret != request->len) {
+ reply->error = EIO;
+ }
+ }
+
+ /* Tell the read handler to read another header. */
+ s->reply.handle = 0;
+ }
+}
+
+static void nbd_coroutine_start(NbdClientSession *s,
+ struct nbd_request *request)
+{
+ int i;
+
+ /* Poor man semaphore. The free_sema is locked when no other request
+ * can be accepted, and unlocked after receiving one reply. */
+ if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
+ qemu_co_mutex_lock(&s->free_sema);
+ assert(s->in_flight < MAX_NBD_REQUESTS);
+ }
+ s->in_flight++;
+
+ for (i = 0; i < MAX_NBD_REQUESTS; i++) {
+ if (s->recv_coroutine[i] == NULL) {
+ s->recv_coroutine[i] = qemu_coroutine_self();
+ break;
+ }
+ }
+
+ assert(i < MAX_NBD_REQUESTS);
+ request->handle = INDEX_TO_HANDLE(s, i);
+}
+
+static void nbd_coroutine_end(NbdClientSession *s,
+ struct nbd_request *request)
+{
+ int i = HANDLE_TO_INDEX(s, request->handle);
+ s->recv_coroutine[i] = NULL;
+ if (s->in_flight-- == MAX_NBD_REQUESTS) {
+ qemu_co_mutex_unlock(&s->free_sema);
+ }
+}
+
+static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov,
+ int offset)
+{
+ struct nbd_request request;
+ struct nbd_reply reply;
+ ssize_t ret;
+
+ request.type = NBD_CMD_READ;
+ request.from = sector_num * 512;
+ request.len = nb_sectors * 512;
+
+ nbd_coroutine_start(client, &request);
+ ret = nbd_co_send_request(client, &request, NULL, 0);
+ if (ret < 0) {
+ reply.error = -ret;
+ } else {
+ nbd_co_receive_reply(client, &request, &reply, qiov, offset);
+ }
+ nbd_coroutine_end(client, &request);
+ return -reply.error;
+
+}
+
+static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov,
+ int offset)
+{
+ struct nbd_request request;
+ struct nbd_reply reply;
+ ssize_t ret;
+
+ request.type = NBD_CMD_WRITE;
+ if (!bdrv_enable_write_cache(client->bs) &&
+ (client->nbdflags & NBD_FLAG_SEND_FUA)) {
+ request.type |= NBD_CMD_FLAG_FUA;
+ }
+
+ request.from = sector_num * 512;
+ request.len = nb_sectors * 512;
+
+ nbd_coroutine_start(client, &request);
+ ret = nbd_co_send_request(client, &request, qiov, offset);
+ if (ret < 0) {
+ reply.error = -ret;
+ } else {
+ nbd_co_receive_reply(client, &request, &reply, NULL, 0);
+ }
+ nbd_coroutine_end(client, &request);
+ return -reply.error;
+}
+
+/* qemu-nbd has a limit of slightly less than 1M per request. Try to
+ * remain aligned to 4K. */
+#define NBD_MAX_SECTORS 2040
+
+int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov)
+{
+ int offset = 0;
+ int ret;
+ while (nb_sectors > NBD_MAX_SECTORS) {
+ ret = nbd_co_readv_1(client, sector_num,
+ NBD_MAX_SECTORS, qiov, offset);
+ if (ret < 0) {
+ return ret;
+ }
+ offset += NBD_MAX_SECTORS * 512;
+ sector_num += NBD_MAX_SECTORS;
+ nb_sectors -= NBD_MAX_SECTORS;
+ }
+ return nbd_co_readv_1(client, sector_num, nb_sectors, qiov, offset);
+}
+
+int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov)
+{
+ int offset = 0;
+ int ret;
+ while (nb_sectors > NBD_MAX_SECTORS) {
+ ret = nbd_co_writev_1(client, sector_num,
+ NBD_MAX_SECTORS, qiov, offset);
+ if (ret < 0) {
+ return ret;
+ }
+ offset += NBD_MAX_SECTORS * 512;
+ sector_num += NBD_MAX_SECTORS;
+ nb_sectors -= NBD_MAX_SECTORS;
+ }
+ return nbd_co_writev_1(client, sector_num, nb_sectors, qiov, offset);
+}
+
+int nbd_client_session_co_flush(NbdClientSession *client)
+{
+ struct nbd_request request;
+ struct nbd_reply reply;
+ ssize_t ret;
+
+ if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) {
+ return 0;
+ }
+
+ request.type = NBD_CMD_FLUSH;
+ if (client->nbdflags & NBD_FLAG_SEND_FUA) {
+ request.type |= NBD_CMD_FLAG_FUA;
+ }
+
+ request.from = 0;
+ request.len = 0;
+
+ nbd_coroutine_start(client, &request);
+ ret = nbd_co_send_request(client, &request, NULL, 0);
+ if (ret < 0) {
+ reply.error = -ret;
+ } else {
+ nbd_co_receive_reply(client, &request, &reply, NULL, 0);
+ }
+ nbd_coroutine_end(client, &request);
+ return -reply.error;
+}
+
+int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors)
+{
+ struct nbd_request request;
+ struct nbd_reply reply;
+ ssize_t ret;
+
+ if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) {
+ return 0;
+ }
+ request.type = NBD_CMD_TRIM;
+ request.from = sector_num * 512;
+ request.len = nb_sectors * 512;
+
+ nbd_coroutine_start(client, &request);
+ ret = nbd_co_send_request(client, &request, NULL, 0);
+ if (ret < 0) {
+ reply.error = -ret;
+ } else {
+ nbd_co_receive_reply(client, &request, &reply, NULL, 0);
+ }
+ nbd_coroutine_end(client, &request);
+ return -reply.error;
+
+}
+
+static void nbd_teardown_connection(NbdClientSession *client)
+{
+ struct nbd_request request;
+
+ request.type = NBD_CMD_DISC;
+ request.from = 0;
+ request.len = 0;
+ nbd_send_request(client->sock, &request);
+
+ qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
+ closesocket(client->sock);
+ client->sock = -1;
+}
+
+void nbd_client_session_close(NbdClientSession *client)
+{
+ nbd_teardown_connection(client);
+ g_free(client->export_name);
+ client->export_name = NULL;
+}
+
+int nbd_client_session_init(NbdClientSession *client,
+ BlockDriverState *bs, int sock)
+{
+ int ret;
+
+ /* NBD handshake */
+ ret = nbd_receive_negotiate(sock, client->export_name,
+ &client->nbdflags, &client->size,
+ &client->blocksize);
+ if (ret < 0) {
+ logout("Failed to negotiate with the NBD server\n");
+ closesocket(sock);
+ return ret;
+ }
+
+ qemu_co_mutex_init(&client->send_mutex);
+ qemu_co_mutex_init(&client->free_sema);
+ client->bs = bs;
+ client->sock = sock;
+
+ /* Now that we're connected, set the socket to be non-blocking and
+ * kick the reply mechanism. */
+ qemu_set_nonblock(sock);
+ qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, client);
+
+ logout("Established connection with NBD server\n");
+ return 0;
+}
diff --git a/block/nbd-client.h b/block/nbd-client.h
new file mode 100644
index 0000000..c271236
--- /dev/null
+++ b/block/nbd-client.h
@@ -0,0 +1,51 @@
+#ifndef NBD_CLIENT_H
+#define NBD_CLIENT_H
+
+#include "qemu-common.h"
+#include "block/nbd.h"
+#include "block/block_int.h"
+
+/* #define DEBUG_NBD */
+
+#if defined(DEBUG_NBD)
+#define logout(fmt, ...) \
+ fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+#define MAX_NBD_REQUESTS 16
+
+typedef struct NbdClientSession {
+ int sock;
+ uint32_t nbdflags;
+ off_t size;
+ size_t blocksize;
+
+ CoMutex send_mutex;
+ CoMutex free_sema;
+ Coroutine *send_coroutine;
+ int in_flight;
+
+ Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
+ struct nbd_reply reply;
+
+ char *export_name; /* An NBD server may export several devices */
+ bool is_unix;
+
+ BlockDriverState *bs;
+} NbdClientSession;
+
+int nbd_client_session_init(NbdClientSession *client,
+ BlockDriverState *bs, int sock);
+void nbd_client_session_close(NbdClientSession *client);
+
+int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors);
+int nbd_client_session_co_flush(NbdClientSession *client);
+int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov);
+int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov);
+
+#endif /* NBD_CLIENT_H */
diff --git a/block/nbd.c b/block/nbd.c
index c8deeee..be75ba0 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -26,8 +26,7 @@
* THE SOFTWARE.
*/
-#include "qemu-common.h"
-#include "block/nbd.h"
+#include "block/nbd-client.h"
#include "qemu/uri.h"
#include "block/block_int.h"
#include "qemu/module.h"
@@ -40,37 +39,9 @@
#define EN_OPTSTR ":exportname="
-/* #define DEBUG_NBD */
-
-#if defined(DEBUG_NBD)
-#define logout(fmt, ...) \
- fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
-#else
-#define logout(fmt, ...) ((void)0)
-#endif
-
-#define MAX_NBD_REQUESTS 16
-#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
-#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
-
typedef struct BDRVNBDState {
- int sock;
- uint32_t nbdflags;
- off_t size;
- size_t blocksize;
-
- CoMutex send_mutex;
- CoMutex free_sema;
- Coroutine *send_coroutine;
- int in_flight;
-
- Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
- struct nbd_reply reply;
-
- bool is_unix;
+ NbdClientSession client;
QemuOpts *socket_opts;
-
- char *export_name; /* An NBD server may export several devices */
} BDRVNBDState;
static int nbd_parse_uri(const char *filename, QDict *options)
@@ -227,9 +198,9 @@ static int nbd_config(BDRVNBDState *s, QDict *options)
"be used at the same time.");
return -EINVAL;
}
- s->is_unix = true;
+ s->client.is_unix = true;
} else if (qdict_haskey(options, "host")) {
- s->is_unix = false;
+ s->client.is_unix = false;
} else {
return -EINVAL;
}
@@ -247,162 +218,20 @@ static int nbd_config(BDRVNBDState *s, QDict *options)
qemu_opt_set_number(s->socket_opts, "port", NBD_DEFAULT_PORT);
}
- s->export_name = g_strdup(qdict_get_try_str(options, "export"));
- if (s->export_name) {
+ s->client.export_name = g_strdup(qdict_get_try_str(options, "export"));
+ if (s->client.export_name) {
qdict_del(options, "export");
}
return 0;
}
-
-static void nbd_coroutine_start(BDRVNBDState *s, struct nbd_request *request)
-{
- int i;
-
- /* Poor man semaphore. The free_sema is locked when no other request
- * can be accepted, and unlocked after receiving one reply. */
- if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
- qemu_co_mutex_lock(&s->free_sema);
- assert(s->in_flight < MAX_NBD_REQUESTS);
- }
- s->in_flight++;
-
- for (i = 0; i < MAX_NBD_REQUESTS; i++) {
- if (s->recv_coroutine[i] == NULL) {
- s->recv_coroutine[i] = qemu_coroutine_self();
- break;
- }
- }
-
- assert(i < MAX_NBD_REQUESTS);
- request->handle = INDEX_TO_HANDLE(s, i);
-}
-
-static void nbd_reply_ready(void *opaque)
-{
- BDRVNBDState *s = opaque;
- uint64_t i;
- int ret;
-
- if (s->reply.handle == 0) {
- /* No reply already in flight. Fetch a header. It is possible
- * that another thread has done the same thing in parallel, so
- * the socket is not readable anymore.
- */
- ret = nbd_receive_reply(s->sock, &s->reply);
- if (ret == -EAGAIN) {
- return;
- }
- if (ret < 0) {
- s->reply.handle = 0;
- goto fail;
- }
- }
-
- /* There's no need for a mutex on the receive side, because the
- * handler acts as a synchronization point and ensures that only
- * one coroutine is called until the reply finishes. */
- i = HANDLE_TO_INDEX(s, s->reply.handle);
- if (i >= MAX_NBD_REQUESTS) {
- goto fail;
- }
-
- if (s->recv_coroutine[i]) {
- qemu_coroutine_enter(s->recv_coroutine[i], NULL);
- return;
- }
-
-fail:
- for (i = 0; i < MAX_NBD_REQUESTS; i++) {
- if (s->recv_coroutine[i]) {
- qemu_coroutine_enter(s->recv_coroutine[i], NULL);
- }
- }
-}
-
-static void nbd_restart_write(void *opaque)
-{
- BDRVNBDState *s = opaque;
- qemu_coroutine_enter(s->send_coroutine, NULL);
-}
-
-static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
- QEMUIOVector *qiov, int offset)
-{
- int rc, ret;
-
- qemu_co_mutex_lock(&s->send_mutex);
- s->send_coroutine = qemu_coroutine_self();
- qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write, s);
- if (qiov) {
- if (!s->is_unix) {
- socket_set_cork(s->sock, 1);
- }
- rc = nbd_send_request(s->sock, request);
- if (rc >= 0) {
- ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
- offset, request->len);
- if (ret != request->len) {
- rc = -EIO;
- }
- }
- if (!s->is_unix) {
- socket_set_cork(s->sock, 0);
- }
- } else {
- rc = nbd_send_request(s->sock, request);
- }
- qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, s);
- s->send_coroutine = NULL;
- qemu_co_mutex_unlock(&s->send_mutex);
- return rc;
-}
-
-static void nbd_co_receive_reply(BDRVNBDState *s, struct nbd_request *request,
- struct nbd_reply *reply,
- QEMUIOVector *qiov, int offset)
-{
- int ret;
-
- /* Wait until we're woken up by the read handler. TODO: perhaps
- * peek at the next reply and avoid yielding if it's ours? */
- qemu_coroutine_yield();
- *reply = s->reply;
- if (reply->handle != request->handle) {
- reply->error = EIO;
- } else {
- if (qiov && reply->error == 0) {
- ret = qemu_co_recvv(s->sock, qiov->iov, qiov->niov,
- offset, request->len);
- if (ret != request->len) {
- reply->error = EIO;
- }
- }
-
- /* Tell the read handler to read another header. */
- s->reply.handle = 0;
- }
-}
-
-static void nbd_coroutine_end(BDRVNBDState *s, struct nbd_request *request)
-{
- int i = HANDLE_TO_INDEX(s, request->handle);
- s->recv_coroutine[i] = NULL;
- if (s->in_flight-- == MAX_NBD_REQUESTS) {
- qemu_co_mutex_unlock(&s->free_sema);
- }
-}
-
static int nbd_establish_connection(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
int sock;
- int ret;
- off_t size;
- size_t blocksize;
- if (s->is_unix) {
+ if (s->client.is_unix) {
sock = unix_socket_outgoing(qemu_opt_get(s->socket_opts, "path"));
} else {
sock = tcp_socket_outgoing_opts(s->socket_opts);
@@ -417,50 +246,14 @@ static int nbd_establish_connection(BlockDriverState *bs)
return -errno;
}
- /* NBD handshake */
- ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
- &blocksize);
- if (ret < 0) {
- logout("Failed to negotiate with the NBD server\n");
- closesocket(sock);
- return ret;
- }
-
- /* Now that we're connected, set the socket to be non-blocking and
- * kick the reply mechanism. */
- qemu_set_nonblock(sock);
- qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, s);
-
- s->sock = sock;
- s->size = size;
- s->blocksize = blocksize;
-
- logout("Established connection with NBD server\n");
- return 0;
-}
-
-static void nbd_teardown_connection(BlockDriverState *bs)
-{
- BDRVNBDState *s = bs->opaque;
- struct nbd_request request;
-
- request.type = NBD_CMD_DISC;
- request.from = 0;
- request.len = 0;
- nbd_send_request(s->sock, &request);
-
- qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL);
- closesocket(s->sock);
+ return sock;
}
static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVNBDState *s = bs->opaque;
- int result;
-
- qemu_co_mutex_init(&s->send_mutex);
- qemu_co_mutex_init(&s->free_sema);
+ int result, sock;
/* Pop the config into our state object. Exit if invalid. */
result = nbd_config(s, options);
@@ -471,172 +264,62 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
/* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour.
*/
- result = nbd_establish_connection(bs);
-
- return result;
-}
-
-static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, QEMUIOVector *qiov,
- int offset)
-{
- BDRVNBDState *s = bs->opaque;
- struct nbd_request request;
- struct nbd_reply reply;
- ssize_t ret;
-
- request.type = NBD_CMD_READ;
- request.from = sector_num * 512;
- request.len = nb_sectors * 512;
-
- nbd_coroutine_start(s, &request);
- ret = nbd_co_send_request(s, &request, NULL, 0);
- if (ret < 0) {
- reply.error = -ret;
- } else {
- nbd_co_receive_reply(s, &request, &reply, qiov, offset);
- }
- nbd_coroutine_end(s, &request);
- return -reply.error;
-
-}
-
-static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, QEMUIOVector *qiov,
- int offset)
-{
- BDRVNBDState *s = bs->opaque;
- struct nbd_request request;
- struct nbd_reply reply;
- ssize_t ret;
-
- request.type = NBD_CMD_WRITE;
- if (!bdrv_enable_write_cache(bs) && (s->nbdflags & NBD_FLAG_SEND_FUA)) {
- request.type |= NBD_CMD_FLAG_FUA;
+ sock = nbd_establish_connection(bs);
+ if (sock < 0) {
+ return sock;
}
- request.from = sector_num * 512;
- request.len = nb_sectors * 512;
-
- nbd_coroutine_start(s, &request);
- ret = nbd_co_send_request(s, &request, qiov, offset);
- if (ret < 0) {
- reply.error = -ret;
- } else {
- nbd_co_receive_reply(s, &request, &reply, NULL, 0);
- }
- nbd_coroutine_end(s, &request);
- return -reply.error;
+ /* NBD handshake */
+ return nbd_client_session_init(&s->client, bs, sock);
}
-/* qemu-nbd has a limit of slightly less than 1M per request. Try to
- * remain aligned to 4K. */
-#define NBD_MAX_SECTORS 2040
-
static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
- int offset = 0;
- int ret;
- while (nb_sectors > NBD_MAX_SECTORS) {
- ret = nbd_co_readv_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
- if (ret < 0) {
- return ret;
- }
- offset += NBD_MAX_SECTORS * 512;
- sector_num += NBD_MAX_SECTORS;
- nb_sectors -= NBD_MAX_SECTORS;
- }
- return nbd_co_readv_1(bs, sector_num, nb_sectors, qiov, offset);
+ BDRVNBDState *s = bs->opaque;
+
+ return nbd_client_session_co_readv(&s->client, sector_num,
+ nb_sectors, qiov);
}
static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
- int offset = 0;
- int ret;
- while (nb_sectors > NBD_MAX_SECTORS) {
- ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
- if (ret < 0) {
- return ret;
- }
- offset += NBD_MAX_SECTORS * 512;
- sector_num += NBD_MAX_SECTORS;
- nb_sectors -= NBD_MAX_SECTORS;
- }
- return nbd_co_writev_1(bs, sector_num, nb_sectors, qiov, offset);
+ BDRVNBDState *s = bs->opaque;
+
+ return nbd_client_session_co_writev(&s->client, sector_num,
+ nb_sectors, qiov);
}
static int nbd_co_flush(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
- struct nbd_request request;
- struct nbd_reply reply;
- ssize_t ret;
-
- if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) {
- return 0;
- }
- request.type = NBD_CMD_FLUSH;
- if (s->nbdflags & NBD_FLAG_SEND_FUA) {
- request.type |= NBD_CMD_FLAG_FUA;
- }
-
- request.from = 0;
- request.len = 0;
-
- nbd_coroutine_start(s, &request);
- ret = nbd_co_send_request(s, &request, NULL, 0);
- if (ret < 0) {
- reply.error = -ret;
- } else {
- nbd_co_receive_reply(s, &request, &reply, NULL, 0);
- }
- nbd_coroutine_end(s, &request);
- return -reply.error;
+ return nbd_client_session_co_flush(&s->client);
}
static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors)
{
BDRVNBDState *s = bs->opaque;
- struct nbd_request request;
- struct nbd_reply reply;
- ssize_t ret;
- if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) {
- return 0;
- }
- request.type = NBD_CMD_TRIM;
- request.from = sector_num * 512;
- request.len = nb_sectors * 512;
-
- nbd_coroutine_start(s, &request);
- ret = nbd_co_send_request(s, &request, NULL, 0);
- if (ret < 0) {
- reply.error = -ret;
- } else {
- nbd_co_receive_reply(s, &request, &reply, NULL, 0);
- }
- nbd_coroutine_end(s, &request);
- return -reply.error;
+ return nbd_client_session_co_discard(&s->client, sector_num,
+ nb_sectors);
}
static void nbd_close(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
- g_free(s->export_name);
- qemu_opts_del(s->socket_opts);
- nbd_teardown_connection(bs);
+ qemu_opts_del(s->socket_opts);
+ nbd_client_session_close(&s->client);
}
static int64_t nbd_getlength(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
- return s->size;
+ return s->client.size;
}
static BlockDriver bdrv_nbd = {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 07/21] nbd: don't change socket block during negotiate
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (5 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 06/21] Split nbd block client code Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 08/21] nbd: pass export name as init argument Marc-André Lureau
` (14 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
The caller might handle non-blocking using coroutine. Leave the choice
to the caller to use a blocking or non-blocking negotiate.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
nbd.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/nbd.c b/nbd.c
index f847940..3af9d17 100644
--- a/nbd.c
+++ b/nbd.c
@@ -443,7 +443,6 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
TRACE("Receiving negotiation.");
- qemu_set_block(csock);
rc = -EINVAL;
if (read_sync(csock, buf, 8) != 8) {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 08/21] nbd: pass export name as init argument
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (6 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 07/21] nbd: don't change socket block during negotiate Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 09/21] nbd: make session_close() idempotent Marc-André Lureau
` (13 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
There is no need to keep the export name around, and it seems a better
fit as an argument in the init() call.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block/nbd-client.c | 10 ++++------
block/nbd-client.h | 5 ++---
block/nbd.c | 13 ++++++++-----
3 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 1abfc6a..e29227b 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -338,17 +338,15 @@ static void nbd_teardown_connection(NbdClientSession *client)
void nbd_client_session_close(NbdClientSession *client)
{
nbd_teardown_connection(client);
- g_free(client->export_name);
- client->export_name = NULL;
}
-int nbd_client_session_init(NbdClientSession *client,
- BlockDriverState *bs, int sock)
+int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
+ int sock, const char *export)
{
int ret;
- /* NBD handshake */
- ret = nbd_receive_negotiate(sock, client->export_name,
+ logout("session init %s\n", export);
+ ret = nbd_receive_negotiate(sock, export,
&client->nbdflags, &client->size,
&client->blocksize);
if (ret < 0) {
diff --git a/block/nbd-client.h b/block/nbd-client.h
index c271236..f2a6337 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -30,14 +30,13 @@ typedef struct NbdClientSession {
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
struct nbd_reply reply;
- char *export_name; /* An NBD server may export several devices */
bool is_unix;
BlockDriverState *bs;
} NbdClientSession;
-int nbd_client_session_init(NbdClientSession *client,
- BlockDriverState *bs, int sock);
+int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
+ int sock, const char *export_name);
void nbd_client_session_close(NbdClientSession *client);
int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
diff --git a/block/nbd.c b/block/nbd.c
index be75ba0..4455a13 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -188,7 +188,7 @@ out:
g_free(file);
}
-static int nbd_config(BDRVNBDState *s, QDict *options)
+static int nbd_config(BDRVNBDState *s, QDict *options, char **export)
{
Error *local_err = NULL;
@@ -218,8 +218,8 @@ static int nbd_config(BDRVNBDState *s, QDict *options)
qemu_opt_set_number(s->socket_opts, "port", NBD_DEFAULT_PORT);
}
- s->client.export_name = g_strdup(qdict_get_try_str(options, "export"));
- if (s->client.export_name) {
+ *export = g_strdup(qdict_get_try_str(options, "export"));
+ if (*export) {
qdict_del(options, "export");
}
@@ -253,10 +253,11 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVNBDState *s = bs->opaque;
+ char *export = NULL;
int result, sock;
/* Pop the config into our state object. Exit if invalid. */
- result = nbd_config(s, options);
+ result = nbd_config(s, options, &export);
if (result != 0) {
return result;
}
@@ -270,7 +271,9 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
}
/* NBD handshake */
- return nbd_client_session_init(&s->client, bs, sock);
+ result = nbd_client_session_init(&s->client, bs, sock, export);
+ g_free(export);
+ return result;
}
static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 09/21] nbd: make session_close() idempotent
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (7 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 08/21] nbd: pass export name as init argument Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 10/21] nbd: finish any pending coroutine Marc-André Lureau
` (12 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block/nbd-client.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index e29227b..c0ad2c2 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -337,7 +337,12 @@ static void nbd_teardown_connection(NbdClientSession *client)
void nbd_client_session_close(NbdClientSession *client)
{
+ if (!client->bs) {
+ return;
+ }
+
nbd_teardown_connection(client);
+ client->bs = NULL;
}
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 10/21] nbd: finish any pending coroutine
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (8 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 09/21] nbd: make session_close() idempotent Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 11/21] nbd: avoid uninitialized warnings Marc-André Lureau
` (11 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel
Make sure all pending coroutines are finished when closing the session.
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
block/nbd-client.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index c0ad2c2..ad6fb01 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -32,6 +32,18 @@
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
+static void nbd_recv_coroutines_enter_all(NbdClientSession *s)
+{
+ int i;
+
+ for (i = 0; i < MAX_NBD_REQUESTS; i++) {
+ if (s->recv_coroutine[i]) {
+ fprintf(stderr, "*nbd reply enter: %p %d\n", s, s->reply.error);
+ qemu_coroutine_enter(s->recv_coroutine[i], NULL);
+ }
+ }
+}
+
static void nbd_reply_ready(void *opaque)
{
NbdClientSession *s = opaque;
@@ -67,11 +79,7 @@ static void nbd_reply_ready(void *opaque)
}
fail:
- for (i = 0; i < MAX_NBD_REQUESTS; i++) {
- if (s->recv_coroutine[i]) {
- qemu_coroutine_enter(s->recv_coroutine[i], NULL);
- }
- }
+ nbd_recv_coroutines_enter_all(s);
}
static void nbd_restart_write(void *opaque)
@@ -332,6 +340,10 @@ static void nbd_teardown_connection(NbdClientSession *client)
qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
closesocket(client->sock);
+ /* finish any pending coroutines */
+ client->reply.handle = 0;
+ client->reply.error = EIO;
+ nbd_recv_coroutines_enter_all(client);
client->sock = -1;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 11/21] nbd: avoid uninitialized warnings
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (9 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 10/21] nbd: finish any pending coroutine Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 12/21] block: save the associated child name in BlockDriverState Marc-André Lureau
` (10 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel
==15815== Thread 1:
==15815== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15815== at 0x65AD5CB: send (send.c:31)
==15815== by 0x37F84B: nbd_wr_sync (nbd.c:145)
==15815== by 0x37F94B: write_sync (nbd.c:186)
==15815== by 0x380FA9: nbd_send_request (nbd.c:681)
==15815== by 0x1C4A2D: nbd_teardown_connection (nbd-client.c:337)
==15815== by 0x1C4AD8: nbd_client_session_close (nbd-client.c:354)
==15815== by 0x1ED2D8: close_socketpair (spicebd.c:132)
==15815== by 0x1EE265: spice_close (spicebd.c:457)
==15815== by 0x1ACBF6: bdrv_close (block.c:1519)
==15815== by 0x1AD804: bdrv_delete (block.c:1772)
==15815== by 0x1B4136: bdrv_unref (block.c:4476)
==15815== by 0x1ACCE0: bdrv_close (block.c:1541)
==15815== Address 0x7feffef98 is on thread 1's stack
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
block/nbd-client.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index ad6fb01..82806f1 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -186,11 +186,10 @@ static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov,
int offset)
{
- struct nbd_request request;
+ struct nbd_request request = { .type = NBD_CMD_READ };
struct nbd_reply reply;
ssize_t ret;
- request.type = NBD_CMD_READ;
request.from = sector_num * 512;
request.len = nb_sectors * 512;
@@ -210,11 +209,10 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov,
int offset)
{
- struct nbd_request request;
+ struct nbd_request request = { .type = NBD_CMD_WRITE };
struct nbd_reply reply;
ssize_t ret;
- request.type = NBD_CMD_WRITE;
if (!bdrv_enable_write_cache(client->bs) &&
(client->nbdflags & NBD_FLAG_SEND_FUA)) {
request.type |= NBD_CMD_FLAG_FUA;
@@ -276,7 +274,7 @@ int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
int nbd_client_session_co_flush(NbdClientSession *client)
{
- struct nbd_request request;
+ struct nbd_request request = { .type = NBD_CMD_FLUSH };
struct nbd_reply reply;
ssize_t ret;
@@ -284,7 +282,6 @@ int nbd_client_session_co_flush(NbdClientSession *client)
return 0;
}
- request.type = NBD_CMD_FLUSH;
if (client->nbdflags & NBD_FLAG_SEND_FUA) {
request.type |= NBD_CMD_FLAG_FUA;
}
@@ -306,14 +303,13 @@ int nbd_client_session_co_flush(NbdClientSession *client)
int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
int nb_sectors)
{
- struct nbd_request request;
+ struct nbd_request request = { .type = NBD_CMD_TRIM };
struct nbd_reply reply;
ssize_t ret;
if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) {
return 0;
}
- request.type = NBD_CMD_TRIM;
request.from = sector_num * 512;
request.len = nb_sectors * 512;
@@ -331,11 +327,12 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
static void nbd_teardown_connection(NbdClientSession *client)
{
- struct nbd_request request;
+ struct nbd_request request = {
+ .type = NBD_CMD_DISC,
+ .from = 0,
+ .len = 0
+ };
- request.type = NBD_CMD_DISC;
- request.from = 0;
- request.len = 0;
nbd_send_request(client->sock, &request);
qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 12/21] block: save the associated child name in BlockDriverState
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (10 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 11/21] nbd: avoid uninitialized warnings Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 13/21] blockdev: add qmp_change_blockdev_int() Marc-André Lureau
` (9 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
This allows the Spice block driver to eject the associated device.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block.c | 58 ++++++++++++++++++++++++++++++++---------------
include/block/block_int.h | 1 +
2 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/block.c b/block.c
index 6d5c804..0558525 100644
--- a/block.c
+++ b/block.c
@@ -318,7 +318,8 @@ void bdrv_register(BlockDriver *bdrv)
}
/* create a new block device (by default it is empty) */
-BlockDriverState *bdrv_new(const char *device_name)
+static BlockDriverState *bdrv_new_int(const char *device_name,
+ BlockDriverState *child)
{
BlockDriverState *bs;
@@ -334,9 +335,24 @@ BlockDriverState *bdrv_new(const char *device_name)
qemu_co_queue_init(&bs->throttled_reqs[1]);
bs->refcnt = 1;
+ if (child) {
+ if (strlen(child->child_device_name)) {
+ pstrcpy(bs->child_device_name, sizeof(bs->child_device_name),
+ child->child_device_name);
+ } else {
+ pstrcpy(bs->child_device_name, sizeof(bs->child_device_name),
+ child->device_name);
+ }
+ }
+
return bs;
}
+BlockDriverState *bdrv_new(const char *device_name)
+{
+ return bdrv_new_int(device_name, NULL);
+}
+
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify)
{
notifier_list_add(&bs->close_notifiers, notify);
@@ -847,16 +863,8 @@ free_and_fail:
return ret;
}
-/*
- * Opens a file using a protocol (file, host_device, nbd, ...)
- *
- * options is a QDict of options to pass to the block drivers, or NULL for an
- * empty set of options. The reference to the QDict belongs to the block layer
- * after the call (even on failure), so if the caller intends to reuse the
- * dictionary, it needs to use QINCREF() before calling bdrv_file_open.
- */
-int bdrv_file_open(BlockDriverState **pbs, const char *filename,
- QDict *options, int flags, Error **errp)
+static int bdrv_file_open_int(BlockDriverState **pbs, const char *filename,
+ QDict *options, int flags, BlockDriverState *child, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv;
@@ -870,7 +878,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
options = qdict_new();
}
- bs = bdrv_new("");
+ bs = bdrv_new_int("", child);
bs->options = options;
options = qdict_clone_shallow(options);
@@ -957,6 +965,20 @@ fail:
}
/*
+ * Opens a file using a protocol (file, host_device, nbd, ...)
+ *
+ * options is a QDict of options to pass to the block drivers, or NULL for an
+ * empty set of options. The reference to the QDict belongs to the block layer
+ * after the call (even on failure), so if the caller intends to reuse the
+ * dictionary, it needs to use QINCREF() before calling bdrv_file_open.
+ */
+int bdrv_file_open(BlockDriverState **pbs, const char *filename,
+ QDict *options, int flags, Error **errp)
+{
+ return bdrv_file_open_int(pbs, filename, options, flags, NULL, errp);
+}
+
+/*
* Opens the backing file for a BlockDriverState if not yet open
*
* options is a QDict of options to pass to the block drivers, or NULL for an
@@ -992,8 +1014,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
sizeof(backing_filename));
}
- bs->backing_hd = bdrv_new("");
-
+ bs->backing_hd = bdrv_new_int("", bs);
if (bs->backing_format[0] != '\0') {
back_drv = bdrv_find_format(bs->backing_format);
}
@@ -1063,7 +1084,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
instead of opening 'filename' directly */
/* if there is a backing file, use it */
- bs1 = bdrv_new("");
+ bs1 = bdrv_new_int("", bs);
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
if (ret < 0) {
bdrv_unref(bs1);
@@ -1124,8 +1145,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
qdict_extract_subqdict(options, &file_options, "file.");
- ret = bdrv_file_open(&file, filename, file_options,
- bdrv_open_flags(bs, flags | BDRV_O_UNMAP), &local_err);
+ ret = bdrv_file_open_int(&file, filename, file_options,
+ bdrv_open_flags(bs, flags | BDRV_O_UNMAP),
+ bs, &local_err);
if (ret < 0) {
goto fail;
}
@@ -1883,7 +1905,7 @@ int bdrv_commit(BlockDriverState *bs)
if (!drv)
return -ENOMEDIUM;
-
+
if (!bs->backing_hd) {
return -ENOTSUP;
}
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 1666066..e0f31dc 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -301,6 +301,7 @@ struct BlockDriverState {
bool iostatus_enabled;
BlockDeviceIoStatus iostatus;
char device_name[32];
+ char child_device_name[32];
HBitmap *dirty_bitmap;
int refcnt;
int in_use; /* users other than guest access, eg. block migration */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 13/21] blockdev: add qmp_change_blockdev_int()
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (11 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 12/21] block: save the associated child name in BlockDriverState Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 14/21] block: extract make_snapshot() from bdrv_open() Marc-André Lureau
` (8 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel,
Marc-André Lureau
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Allow to pass additional arguments, such as options and opaque
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
blockdev.c | 24 +++++++++++++++++++-----
include/sysemu/blockdev.h | 3 +++
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index b8db544..f2c3c4e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1498,12 +1498,13 @@ void qmp_block_passwd(const char *device, const char *password, Error **errp)
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
int bdrv_flags, BlockDriver *drv,
- const char *password, Error **errp)
+ const char *password, QDict *options,
+ Error **errp)
{
Error *local_err = NULL;
int ret;
- ret = bdrv_open(bs, filename, NULL, bdrv_flags, drv, &local_err);
+ ret = bdrv_open(bs, filename, options, bdrv_flags, drv, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return;
@@ -1523,8 +1524,9 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
}
}
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp)
+void qmp_change_blockdev_int(const char *device, const char *filename,
+ const char *format, QDict *options, void *opaque,
+ Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv = NULL;
@@ -1554,7 +1556,19 @@ void qmp_change_blockdev(const char *device, const char *filename,
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
- qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
+ if (bs->opaque) {
+ error_set(errp, QERR_INVALID_PARAMETER, device);
+ return;
+ }
+ bs->opaque = opaque;
+
+ qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, options, errp);
+}
+
+void qmp_change_blockdev(const char *device, const char *filename,
+ const char *format, Error **errp)
+{
+ qmp_change_blockdev_int(device, filename, format, NULL, NULL, errp);
}
/* throttling disk I/O limits */
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 134712b..5ce4997 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -65,6 +65,9 @@ DriveInfo *add_init_drive(const char *opts);
void qmp_change_blockdev(const char *device, const char *filename,
const char *format, Error **errp);
+void qmp_change_blockdev_int(const char *device, const char *filename,
+ const char *format, QDict *options, void *opaque,
+ Error **errp);
void do_commit(Monitor *mon, const QDict *qdict);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 14/21] block: extract make_snapshot() from bdrv_open()
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (12 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 13/21] blockdev: add qmp_change_blockdev_int() Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 15/21] block: add "snapshot.size" option to avoid extra bdrv_open() Marc-André Lureau
` (7 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block.c | 121 +++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 70 insertions(+), 51 deletions(-)
diff --git a/block.c b/block.c
index 0558525..09aada5 100644
--- a/block.c
+++ b/block.c
@@ -1038,6 +1038,73 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
return 0;
}
+static int make_snapshot(BlockDriverState *bs, int64_t total_size,
+ const char **pfilename, BlockDriver **pdrv,
+ Error **errp)
+{
+ const char *filename = *pfilename;
+ BlockDriver *drv = *pdrv;
+ int ret;
+ BlockDriver *bdrv_qcow2;
+ QEMUOptionParameter *create_options;
+ char backing_filename[PATH_MAX];
+ /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
+ char tmp_filename[PATH_MAX + 1];
+ Error *local_err = NULL;
+
+ assert(filename != NULL);
+ total_size &= BDRV_SECTOR_MASK;
+
+ /* if snapshot, we create a temporary backing file and open it
+ instead of opening 'filename' directly */
+
+ ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
+ if (ret < 0) {
+ goto fail;
+ }
+
+ /* Real path is meaningless for protocols */
+ if (path_has_protocol(filename)) {
+ snprintf(backing_filename, sizeof(backing_filename),
+ "%s", filename);
+ } else if (!realpath(filename, backing_filename)) {
+ ret = -errno;
+ error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
+ goto fail;
+ }
+
+ bdrv_qcow2 = bdrv_find_format("qcow2");
+ create_options = parse_option_parameters("", bdrv_qcow2->create_options,
+ NULL);
+
+ set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
+ set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE,
+ backing_filename);
+ if (drv) {
+ set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT,
+ drv->format_name);
+ }
+
+ ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
+ free_option_parameters(create_options);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not create temporary overlay "
+ "'%s': %s", tmp_filename,
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ goto fail;
+ }
+
+ *pfilename = tmp_filename;
+ *pdrv = bdrv_qcow2;
+ bs->is_temporary = 1;
+ return 0;
+
+fail:
+ return ret;
+}
+
/*
* Opens a disk image (raw, qcow2, vmdk, ...)
*
@@ -1050,8 +1117,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
int flags, BlockDriver *drv, Error **errp)
{
int ret;
- /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
- char tmp_filename[PATH_MAX + 1];
BlockDriverState *file = NULL;
QDict *file_options = NULL;
const char *drvname;
@@ -1069,73 +1134,27 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
int64_t total_size;
- BlockDriver *bdrv_qcow2;
- QEMUOptionParameter *create_options;
- char backing_filename[PATH_MAX];
if (qdict_size(options) != 0) {
error_setg(errp, "Can't use snapshot=on with driver-specific options");
ret = -EINVAL;
goto fail;
}
- assert(filename != NULL);
-
- /* if snapshot, we create a temporary backing file and open it
- instead of opening 'filename' directly */
- /* if there is a backing file, use it */
- bs1 = bdrv_new_int("", bs);
+ bs1 = bdrv_new_int("", NULL);
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
if (ret < 0) {
bdrv_unref(bs1);
goto fail;
}
- total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
+ total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
bdrv_unref(bs1);
- ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
- if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not get temporary filename");
- goto fail;
- }
-
- /* Real path is meaningless for protocols */
- if (path_has_protocol(filename)) {
- snprintf(backing_filename, sizeof(backing_filename),
- "%s", filename);
- } else if (!realpath(filename, backing_filename)) {
- ret = -errno;
- error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
- goto fail;
- }
-
- bdrv_qcow2 = bdrv_find_format("qcow2");
- create_options = parse_option_parameters("", bdrv_qcow2->create_options,
- NULL);
-
- set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
- set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE,
- backing_filename);
- if (drv) {
- set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT,
- drv->format_name);
- }
-
- ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
- free_option_parameters(create_options);
+ ret = make_snapshot(bs, total_size, &filename, &drv, errp);
if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not create temporary overlay "
- "'%s': %s", tmp_filename,
- error_get_pretty(local_err));
- error_free(local_err);
- local_err = NULL;
goto fail;
}
-
- filename = tmp_filename;
- drv = bdrv_qcow2;
- bs->is_temporary = 1;
}
/* Open image file without format layer */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 15/21] block: add "snapshot.size" option to avoid extra bdrv_open()
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (13 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 14/21] block: extract make_snapshot() from bdrv_open() Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 16/21] block: learn to open a driver with a given opaque Marc-André Lureau
` (6 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/block.c b/block.c
index 09aada5..9e7632e 100644
--- a/block.c
+++ b/block.c
@@ -1135,27 +1135,32 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
BlockDriverState *bs1;
int64_t total_size;
+ total_size = qdict_get_try_int(options, "snapshot.size", -1);
+ qdict_del(options, "snapshot.size");
+
if (qdict_size(options) != 0) {
error_setg(errp, "Can't use snapshot=on with driver-specific options");
ret = -EINVAL;
goto fail;
}
- bs1 = bdrv_new_int("", NULL);
- ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
- if (ret < 0) {
+ if (total_size == -1) {
+ bs1 = bdrv_new_int("", NULL);
+ ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
+ if (ret < 0) {
+ bdrv_unref(bs1);
+ goto fail;
+ }
+ total_size = bdrv_getlength(bs1);
bdrv_unref(bs1);
- goto fail;
}
- total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
- bdrv_unref(bs1);
-
ret = make_snapshot(bs, total_size, &filename, &drv, errp);
if (ret < 0) {
goto fail;
}
}
+ qdict_del(options, "snapshot.size");
/* Open image file without format layer */
if (flags & BDRV_O_RDWR) {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 16/21] block: learn to open a driver with a given opaque
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (14 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 15/21] block: add "snapshot.size" option to avoid extra bdrv_open() Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 17/21] block: allow to call bdrv_open() with an opaque Marc-André Lureau
` (5 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
If the block driver is given an opaque data, there is no need to
allocate a new one. This allows to pass an existing driver state to the
new driver.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block.c | 48 +++++++++++++++++++++++++++++-------------------
1 file changed, 29 insertions(+), 19 deletions(-)
diff --git a/block.c b/block.c
index 9e7632e..f154979 100644
--- a/block.c
+++ b/block.c
@@ -319,7 +319,7 @@ void bdrv_register(BlockDriver *bdrv)
/* create a new block device (by default it is empty) */
static BlockDriverState *bdrv_new_int(const char *device_name,
- BlockDriverState *child)
+ BlockDriverState *child, void *opaque)
{
BlockDriverState *bs;
@@ -344,13 +344,14 @@ static BlockDriverState *bdrv_new_int(const char *device_name,
child->device_name);
}
}
+ bs->opaque = opaque;
return bs;
}
BlockDriverState *bdrv_new(const char *device_name)
{
- return bdrv_new_int(device_name, NULL);
+ return bdrv_new_int(device_name, NULL, NULL);
}
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify)
@@ -810,7 +811,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
}
bs->drv = drv;
- bs->opaque = g_malloc0(drv->instance_size);
+ if (bs->opaque == NULL) {
+ bs->opaque = g_malloc0(drv->instance_size);
+ }
bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
@@ -864,7 +867,8 @@ free_and_fail:
}
static int bdrv_file_open_int(BlockDriverState **pbs, const char *filename,
- QDict *options, int flags, BlockDriverState *child, Error **errp)
+ QDict *options, int flags, BlockDriverState *child, void *opaque,
+ Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv;
@@ -878,7 +882,7 @@ static int bdrv_file_open_int(BlockDriverState **pbs, const char *filename,
options = qdict_new();
}
- bs = bdrv_new_int("", child);
+ bs = bdrv_new_int("", child, opaque);
bs->options = options;
options = qdict_clone_shallow(options);
@@ -975,18 +979,11 @@ fail:
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
QDict *options, int flags, Error **errp)
{
- return bdrv_file_open_int(pbs, filename, options, flags, NULL, errp);
+ return bdrv_file_open_int(pbs, filename, options, flags, NULL, NULL, errp);
}
-/*
- * Opens the backing file for a BlockDriverState if not yet open
- *
- * options is a QDict of options to pass to the block drivers, or NULL for an
- * empty set of options. The reference to the QDict is transferred to this
- * function (even on failure), so if the caller intends to reuse the dictionary,
- * it needs to use QINCREF() before calling bdrv_file_open.
- */
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+static int bdrv_open_backing_file_int(BlockDriverState *bs,
+ QDict *options, void *opaque, Error **errp)
{
char backing_filename[PATH_MAX];
int back_flags, ret;
@@ -1014,7 +1011,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
sizeof(backing_filename));
}
- bs->backing_hd = bdrv_new_int("", bs);
+ bs->backing_hd = bdrv_new_int("", bs, opaque);
if (bs->backing_format[0] != '\0') {
back_drv = bdrv_find_format(bs->backing_format);
}
@@ -1038,6 +1035,19 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
return 0;
}
+/*
+ * Opens the backing file for a BlockDriverState if not yet open
+ *
+ * options is a QDict of options to pass to the block drivers, or NULL for an
+ * empty set of options. The reference to the QDict is transferred to this
+ * function (even on failure), so if the caller intends to reuse the dictionary,
+ * it needs to use QINCREF() before calling bdrv_file_open.
+ */
+int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+{
+ return bdrv_open_backing_file_int(bs, options, NULL, errp);
+}
+
static int make_snapshot(BlockDriverState *bs, int64_t total_size,
const char **pfilename, BlockDriver **pdrv,
Error **errp)
@@ -1145,7 +1155,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
}
if (total_size == -1) {
- bs1 = bdrv_new_int("", NULL);
+ bs1 = bdrv_new_int("", NULL, NULL);
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
if (ret < 0) {
bdrv_unref(bs1);
@@ -1171,7 +1181,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
ret = bdrv_file_open_int(&file, filename, file_options,
bdrv_open_flags(bs, flags | BDRV_O_UNMAP),
- bs, &local_err);
+ bs, NULL, &local_err);
if (ret < 0) {
goto fail;
}
@@ -1207,7 +1217,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
QDict *backing_options;
qdict_extract_subqdict(options, &backing_options, "backing.");
- ret = bdrv_open_backing_file(bs, backing_options, &local_err);
+ ret = bdrv_open_backing_file_int(bs, backing_options, NULL, &local_err);
if (ret < 0) {
goto close_and_fail;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 17/21] block: allow to call bdrv_open() with an opaque
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (15 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 16/21] block: learn to open a driver with a given opaque Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 18/21] block: do not notify change during migration Marc-André Lureau
` (4 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
If the block driver already has a bs->opaque when calling bdrv_open(),
pass it down to the file driver.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Conflicts:
block.c
---
block.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/block.c b/block.c
index f154979..ce2427b 100644
--- a/block.c
+++ b/block.c
@@ -1131,6 +1131,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
QDict *file_options = NULL;
const char *drvname;
Error *local_err = NULL;
+ void *backing_opaque = NULL;
/* NULL means an empty set of options */
if (options == NULL) {
@@ -1154,6 +1155,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
goto fail;
}
+ backing_opaque = bs->opaque;
+ bs->opaque = NULL;
if (total_size == -1) {
bs1 = bdrv_new_int("", NULL, NULL);
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
@@ -1181,7 +1184,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
ret = bdrv_file_open_int(&file, filename, file_options,
bdrv_open_flags(bs, flags | BDRV_O_UNMAP),
- bs, NULL, &local_err);
+ bs, bs->opaque, &local_err);
+ bs->opaque = NULL;
if (ret < 0) {
goto fail;
}
@@ -1217,7 +1221,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
QDict *backing_options;
qdict_extract_subqdict(options, &backing_options, "backing.");
- ret = bdrv_open_backing_file_int(bs, backing_options, NULL, &local_err);
+ ret = bdrv_open_backing_file_int(bs, backing_options,
+ backing_opaque, &local_err);
if (ret < 0) {
goto close_and_fail;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 18/21] block: do not notify change during migration
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (16 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 17/21] block: allow to call bdrv_open() with an opaque Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:25 ` [Qemu-devel] [PATCH 19/21] sysemu: add vm_start_hold/release Marc-André Lureau
` (3 subsequent siblings)
21 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel,
Marc-André Lureau
From: Marc-André Lureau <marcandre.lureau@redhat.com>
When starting qemu, a block driver isn't associated with a device, so
no notification is emitted when the media is loaded.
The Spice block driver loads the media during migration. But at
that time, the device is already associated, however, we want to
avoid notification to the guest. Checking the runstate seems the
simplest way.
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
block.c | 4 +++-
hw/block/fdc.c | 8 +++++---
hw/ide/core.c | 12 +++++++-----
hw/scsi/scsi-disk.c | 11 +++++++----
hw/sd/sd.c | 6 +++++-
include/block/block.h | 2 +-
stubs/vm-stop.c | 5 +++++
7 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/block.c b/block.c
index ce2427b..fdbc7f9 100644
--- a/block.c
+++ b/block.c
@@ -1864,9 +1864,11 @@ static void bdrv_emit_qmp_eject_event(BlockDriverState *bs, bool ejected)
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
{
+ bool notify = !runstate_check(RUN_STATE_INMIGRATE);
+
if (bs->dev_ops && bs->dev_ops->change_media_cb) {
bool tray_was_closed = !bdrv_dev_is_tray_open(bs);
- bs->dev_ops->change_media_cb(bs->dev_opaque, load);
+ bs->dev_ops->change_media_cb(bs->dev_opaque, load, notify);
if (tray_was_closed) {
/* tray open */
bdrv_emit_qmp_eject_event(bs, true);
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index c5a6c21..bb8cffb 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -1984,11 +1984,13 @@ static void fdctrl_result_timer(void *opaque)
}
}
-static void fdctrl_change_cb(void *opaque, bool load)
+static void fdctrl_change_cb(void *opaque, bool load, bool notify)
{
FDrive *drive = opaque;
- drive->media_changed = 1;
+ if (notify) {
+ drive->media_changed = 1;
+ }
fd_revalidate(drive);
}
@@ -2018,7 +2020,7 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
}
fd_init(drive);
- fdctrl_change_cb(drive, 0);
+ fdctrl_change_cb(drive, 0, false);
if (drive->bs) {
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
}
diff --git a/hw/ide/core.c b/hw/ide/core.c
index e1f4c33..18b2f85 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -882,7 +882,7 @@ static void ide_cfata_metadata_write(IDEState *s)
}
/* called when the inserted state of the media has changed */
-static void ide_cd_change_cb(void *opaque, bool load)
+static void ide_cd_change_cb(void *opaque, bool load, bool notify)
{
IDEState *s = opaque;
uint64_t nb_sectors;
@@ -898,10 +898,12 @@ static void ide_cd_change_cb(void *opaque, bool load)
* Then we set UNIT_ATTENTION, by which the guest will
* detect a new CD in the drive. See ide_atapi_cmd() for details.
*/
- s->cdrom_changed = 1;
- s->events.new_media = true;
- s->events.eject_request = false;
- ide_set_irq(s->bus);
+ if (notify) {
+ s->cdrom_changed = 1;
+ s->events.new_media = true;
+ s->events.eject_request = false;
+ ide_set_irq(s->bus);
+ }
}
static void ide_cd_eject_request_cb(void *opaque, bool force)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 74e6a14..87f2299 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2010,7 +2010,7 @@ static void scsi_disk_resize_cb(void *opaque)
}
}
-static void scsi_cd_change_media_cb(void *opaque, bool load)
+static void scsi_cd_change_media_cb(void *opaque, bool load, bool notify)
{
SCSIDiskState *s = opaque;
@@ -2024,11 +2024,14 @@ static void scsi_cd_change_media_cb(void *opaque, bool load)
* media_changed governs the state machine used for unit attention
* report. media_event is used by GET EVENT STATUS NOTIFICATION.
*/
- s->media_changed = load;
s->tray_open = !load;
- scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
- s->media_event = true;
s->eject_request = false;
+
+ if (notify) {
+ s->media_changed = load;
+ scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
+ s->media_event = true;
+ }
}
static void scsi_cd_eject_request_cb(void *opaque, bool force)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 4502ad1..09f37be 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -439,10 +439,14 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
sd->expecting_acmd = false;
}
-static void sd_cardchange(void *opaque, bool load)
+static void sd_cardchange(void *opaque, bool load, bool notify)
{
SDState *sd = opaque;
+ if (!notify) {
+ return;
+ }
+
qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
if (bdrv_is_inserted(sd->bdrv)) {
sd_reset(sd, sd->bdrv);
diff --git a/include/block/block.h b/include/block/block.h
index 3560deb..a5ccbb5 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -36,7 +36,7 @@ typedef struct BlockDevOps {
* changes. Sure would be useful if it did.
* Device models with removable media must implement this callback.
*/
- void (*change_media_cb)(void *opaque, bool load);
+ void (*change_media_cb)(void *opaque, bool load, bool notify);
/*
* Runs when an eject request is issued from the monitor, the tray
* is closed, and the medium is locked.
diff --git a/stubs/vm-stop.c b/stubs/vm-stop.c
index f82c897..9c66002 100644
--- a/stubs/vm-stop.c
+++ b/stubs/vm-stop.c
@@ -5,3 +5,8 @@ int vm_stop(RunState state)
{
abort();
}
+
+bool runstate_check(RunState state)
+{
+ return FALSE;
+}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 19/21] sysemu: add vm_start_hold/release
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (17 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 18/21] block: do not notify change during migration Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-29 10:30 ` Paolo Bonzini
2013-11-18 12:25 ` [Qemu-devel] [PATCH 20/21] spice-core: allow an interface to be in AIO context Marc-André Lureau
` (2 subsequent siblings)
21 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel
This is a simple solution (or hack?) to allow the Spice block driver to
hold the VM from starting before the migration state is completed.
During migration, the destination qemu needs to initialize the NBD
session. This requires waiting for the Spice client and communication
before the VM is started, but using a running main loop.
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
include/sysemu/sysemu.h | 2 ++
vl.c | 17 +++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index cd5791e..a76a6e7 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -38,6 +38,8 @@ void vm_state_notify(int running, RunState state);
#define VMRESET_REPORT true
void vm_start(void);
+void vm_start_hold(void);
+void vm_start_release(void);
int vm_stop(RunState state);
int vm_stop_force_state(RunState state);
diff --git a/vl.c b/vl.c
index 4ad15b8..8905ba5 100644
--- a/vl.c
+++ b/vl.c
@@ -1690,8 +1690,25 @@ void vm_state_notify(int running, RunState state)
}
}
+static int start_hold;
+
+void vm_start_hold(void)
+{
+ start_hold++;
+}
+
+void vm_start_release(void)
+{
+ start_hold--;
+ vm_start();
+}
+
void vm_start(void)
{
+ if (start_hold != 0) {
+ return;
+ }
+
if (!runstate_is_running()) {
cpu_enable_ticks();
runstate_set(RUN_STATE_RUNNING);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 19/21] sysemu: add vm_start_hold/release
2013-11-18 12:25 ` [Qemu-devel] [PATCH 19/21] sysemu: add vm_start_hold/release Marc-André Lureau
@ 2013-11-29 10:30 ` Paolo Bonzini
0 siblings, 0 replies; 28+ messages in thread
From: Paolo Bonzini @ 2013-11-29 10:30 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: kwolf, jcody, qemu-devel, spice-devel
Il 18/11/2013 13:25, Marc-André Lureau ha scritto:
> +static int start_hold;
> +
> +void vm_start_hold(void)
> +{
> + start_hold++;
> +}
> +
> +void vm_start_release(void)
> +{
> + start_hold--;
> + vm_start();
> +}
> +
> void vm_start(void)
> {
> + if (start_hold != 0) {
> + return;
> + }
> +
This is interesting. I like it, but I think this sequence:
vm_start_hold()
vm_start_release()
should not call vm_start(), while this:
vm_start_hold()
vm_start()
vm_start_release()
should call it.
Also, vm_start_hold() should assert that the VM is not running.
Paolo
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 20/21] spice-core: allow an interface to be in AIO context
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (18 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 19/21] sysemu: add vm_start_hold/release Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-18 12:53 ` [Qemu-devel] [Spice-devel] " Alon Levy
2013-11-18 12:25 ` [Qemu-devel] [PATCH 21/21] block: add spice block device backend Marc-André Lureau
2013-11-22 13:28 ` [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
21 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, jcody, Marc-André Lureau, kraxel, spice-devel
The Spice block driver must be able complete operations within a AIO
context only.
Spice is currently only running within the main loop, and doesn't allow
the block driver to complete operations, such as flush during migration.
This patch allows a Spice interface to be associated with a different
context. Currently, the interface user_data is simply used to
differentiate main loop from AIO, but could later be used to associate
an interface with a particular thread.
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
---
include/ui/qemu-spice.h | 2 +-
qemu-char.c | 2 +-
spice-qemu-char.c | 9 +++----
ui/spice-core.c | 62 +++++++++++++++++++++++++++++++++++++++++++------
4 files changed, 62 insertions(+), 13 deletions(-)
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index a93b4b2..d5ba702 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -48,7 +48,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
void do_info_spice_print(Monitor *mon, const QObject *data);
void do_info_spice(Monitor *mon, QObject **ret_data);
-CharDriverState *qemu_chr_open_spice_vmc(const char *type);
+CharDriverState *qemu_chr_open_spice_vmc(const char *type, bool aio);
#if SPICE_SERVER_VERSION >= 0x000c02
CharDriverState *qemu_chr_open_spice_port(const char *name);
void qemu_spice_register_ports(void);
diff --git a/qemu-char.c b/qemu-char.c
index 418dc69..bfac7bf 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3747,7 +3747,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
#endif
#ifdef CONFIG_SPICE
case CHARDEV_BACKEND_KIND_SPICEVMC:
- chr = qemu_chr_open_spice_vmc(backend->spicevmc->type);
+ chr = qemu_chr_open_spice_vmc(backend->spicevmc->type, false);
break;
case CHARDEV_BACKEND_KIND_SPICEPORT:
chr = qemu_chr_open_spice_port(backend->spiceport->fqdn);
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 16439c5..421f7de 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -248,7 +248,7 @@ static void print_allowed_subtypes(void)
fprintf(stderr, "\n");
}
-static CharDriverState *chr_open(const char *subtype)
+static CharDriverState *chr_open(const char *subtype, bool aio)
{
CharDriverState *chr;
SpiceCharDriver *s;
@@ -257,6 +257,7 @@ static CharDriverState *chr_open(const char *subtype)
s = g_malloc0(sizeof(SpiceCharDriver));
s->chr = chr;
s->active = false;
+ s->sin.base.user_data = (void*)aio;
s->sin.subtype = g_strdup(subtype);
chr->opaque = s;
chr->chr_write = spice_chr_write;
@@ -271,7 +272,7 @@ static CharDriverState *chr_open(const char *subtype)
return chr;
}
-CharDriverState *qemu_chr_open_spice_vmc(const char *type)
+CharDriverState *qemu_chr_open_spice_vmc(const char *type, bool aio)
{
const char **psubtype = spice_server_char_device_recognized_subtypes();
@@ -291,7 +292,7 @@ CharDriverState *qemu_chr_open_spice_vmc(const char *type)
return NULL;
}
- return chr_open(type);
+ return chr_open(type, aio);
}
#if SPICE_SERVER_VERSION >= 0x000c02
@@ -305,7 +306,7 @@ CharDriverState *qemu_chr_open_spice_port(const char *name)
return NULL;
}
- chr = chr_open("port");
+ chr = chr_open("port", false);
s = chr->opaque;
s->sin.portname = g_strdup(name);
diff --git a/ui/spice-core.c b/ui/spice-core.c
index e4d533d..0f69630 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -53,34 +53,64 @@ static QemuThread me;
struct SpiceTimer {
QEMUTimer *timer;
+ QEMUBH *bh;
QTAILQ_ENTRY(SpiceTimer) next;
};
static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
+#if SPICE_INTERFACE_CORE_MAJOR >= 2
+static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque, SpiceBaseInstance *sin)
+#else
static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
+#endif
{
SpiceTimer *timer;
timer = g_malloc0(sizeof(*timer));
- timer->timer = timer_new_ms(QEMU_CLOCK_REALTIME, func, opaque);
+
+#if SPICE_INTERFACE_CORE_MAJOR >= 2
+ bool aio = sin ? !!sin->user_data : false;
+ if (aio) {
+ fprintf(stderr, "AIO doesn't have timers yet, using BH\n");
+ timer->bh = qemu_bh_new(func, opaque);
+ } else
+#endif
+ {
+ timer->timer = timer_new_ms(QEMU_CLOCK_REALTIME, func, opaque);
+ }
+
QTAILQ_INSERT_TAIL(&timers, timer, next);
+
return timer;
}
static void timer_start(SpiceTimer *timer, uint32_t ms)
{
- timer_mod(timer->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ms);
+ if (timer->bh) {
+ qemu_bh_schedule_idle(timer->bh); /* at least every 10ms, see async.c */
+ } else {
+ timer_mod(timer->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ms);
+ }
}
static void timer_cancel(SpiceTimer *timer)
{
- timer_del(timer->timer);
+ if (timer->bh) {
+ qemu_bh_cancel(timer->bh);
+ } else {
+ timer_del(timer->timer);
+ }
}
static void timer_remove(SpiceTimer *timer)
{
- timer_del(timer->timer);
- timer_free(timer->timer);
+ if (timer->bh) {
+ qemu_bh_delete(timer->bh);
+ } else {
+ timer_del(timer->timer);
+ timer_free(timer->timer);
+ }
+
QTAILQ_REMOVE(&timers, timer, next);
g_free(timer);
}
@@ -89,6 +119,7 @@ struct SpiceWatch {
int fd;
int event_mask;
SpiceWatchFunc func;
+ bool aio;
void *opaque;
QTAILQ_ENTRY(SpiceWatch) next;
};
@@ -118,10 +149,19 @@ static void watch_update_mask(SpiceWatch *watch, int event_mask)
if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
on_write = watch_write;
}
- qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+
+ if (watch->aio) {
+ qemu_aio_set_fd_handler(watch->fd, on_read, on_write, watch);
+ } else {
+ qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+ }
}
+#if SPICE_INTERFACE_CORE_MAJOR >= 2
+static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque, SpiceBaseInstance *sin)
+#else
static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+#endif
{
SpiceWatch *watch;
@@ -129,6 +169,10 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
watch->fd = fd;
watch->func = func;
watch->opaque = opaque;
+#if SPICE_INTERFACE_CORE_MAJOR >= 2
+ watch->aio = sin ? !!sin->user_data : false;
+#endif
+
QTAILQ_INSERT_TAIL(&watches, watch, next);
watch_update_mask(watch, event_mask);
@@ -137,7 +181,11 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
static void watch_remove(SpiceWatch *watch)
{
- qemu_set_fd_handler(watch->fd, NULL, NULL, NULL);
+ if (watch->aio) {
+ qemu_aio_set_fd_handler(watch->fd, NULL, NULL, NULL);
+ } else {
+ qemu_set_fd_handler(watch->fd, NULL, NULL, NULL);
+ }
QTAILQ_REMOVE(&watches, watch, next);
g_free(watch);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [Spice-devel] [PATCH 20/21] spice-core: allow an interface to be in AIO context
2013-11-18 12:25 ` [Qemu-devel] [PATCH 20/21] spice-core: allow an interface to be in AIO context Marc-André Lureau
@ 2013-11-18 12:53 ` Alon Levy
0 siblings, 0 replies; 28+ messages in thread
From: Alon Levy @ 2013-11-18 12:53 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel; +Cc: kwolf, jcody, spice-devel
On 11/18/2013 02:25 PM, Marc-André Lureau wrote:
> The Spice block driver must be able complete operations within a AIO
> context only.
>
> Spice is currently only running within the main loop, and doesn't allow
> the block driver to complete operations, such as flush during migration.
>
> This patch allows a Spice interface to be associated with a different
> context. Currently, the interface user_data is simply used to
> differentiate main loop from AIO, but could later be used to associate
> an interface with a particular thread.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
> ---
> include/ui/qemu-spice.h | 2 +-
> qemu-char.c | 2 +-
> spice-qemu-char.c | 9 +++----
> ui/spice-core.c | 62 +++++++++++++++++++++++++++++++++++++++++++------
> 4 files changed, 62 insertions(+), 13 deletions(-)
>
> diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
> index a93b4b2..d5ba702 100644
> --- a/include/ui/qemu-spice.h
> +++ b/include/ui/qemu-spice.h
> @@ -48,7 +48,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
> void do_info_spice_print(Monitor *mon, const QObject *data);
> void do_info_spice(Monitor *mon, QObject **ret_data);
>
> -CharDriverState *qemu_chr_open_spice_vmc(const char *type);
> +CharDriverState *qemu_chr_open_spice_vmc(const char *type, bool aio);
> #if SPICE_SERVER_VERSION >= 0x000c02
> CharDriverState *qemu_chr_open_spice_port(const char *name);
> void qemu_spice_register_ports(void);
> diff --git a/qemu-char.c b/qemu-char.c
> index 418dc69..bfac7bf 100644
> --- a/qemu-char.c
> +++ b/qemu-char.c
> @@ -3747,7 +3747,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
> #endif
> #ifdef CONFIG_SPICE
> case CHARDEV_BACKEND_KIND_SPICEVMC:
> - chr = qemu_chr_open_spice_vmc(backend->spicevmc->type);
> + chr = qemu_chr_open_spice_vmc(backend->spicevmc->type, false);
> break;
> case CHARDEV_BACKEND_KIND_SPICEPORT:
> chr = qemu_chr_open_spice_port(backend->spiceport->fqdn);
> diff --git a/spice-qemu-char.c b/spice-qemu-char.c
> index 16439c5..421f7de 100644
> --- a/spice-qemu-char.c
> +++ b/spice-qemu-char.c
> @@ -248,7 +248,7 @@ static void print_allowed_subtypes(void)
> fprintf(stderr, "\n");
> }
>
> -static CharDriverState *chr_open(const char *subtype)
> +static CharDriverState *chr_open(const char *subtype, bool aio)
> {
> CharDriverState *chr;
> SpiceCharDriver *s;
> @@ -257,6 +257,7 @@ static CharDriverState *chr_open(const char *subtype)
> s = g_malloc0(sizeof(SpiceCharDriver));
> s->chr = chr;
> s->active = false;
> + s->sin.base.user_data = (void*)aio;
> s->sin.subtype = g_strdup(subtype);
> chr->opaque = s;
> chr->chr_write = spice_chr_write;
> @@ -271,7 +272,7 @@ static CharDriverState *chr_open(const char *subtype)
> return chr;
> }
>
> -CharDriverState *qemu_chr_open_spice_vmc(const char *type)
> +CharDriverState *qemu_chr_open_spice_vmc(const char *type, bool aio)
> {
> const char **psubtype = spice_server_char_device_recognized_subtypes();
>
> @@ -291,7 +292,7 @@ CharDriverState *qemu_chr_open_spice_vmc(const char *type)
> return NULL;
> }
>
> - return chr_open(type);
> + return chr_open(type, aio);
> }
>
> #if SPICE_SERVER_VERSION >= 0x000c02
> @@ -305,7 +306,7 @@ CharDriverState *qemu_chr_open_spice_port(const char *name)
> return NULL;
> }
>
> - chr = chr_open("port");
> + chr = chr_open("port", false);
> s = chr->opaque;
> s->sin.portname = g_strdup(name);
>
> diff --git a/ui/spice-core.c b/ui/spice-core.c
> index e4d533d..0f69630 100644
> --- a/ui/spice-core.c
> +++ b/ui/spice-core.c
> @@ -53,34 +53,64 @@ static QemuThread me;
>
> struct SpiceTimer {
> QEMUTimer *timer;
> + QEMUBH *bh;
> QTAILQ_ENTRY(SpiceTimer) next;
> };
> static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
>
> +#if SPICE_INTERFACE_CORE_MAJOR >= 2
> +static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque, SpiceBaseInstance *sin)
> +#else
> static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
> +#endif
> {
> SpiceTimer *timer;
>
> timer = g_malloc0(sizeof(*timer));
> - timer->timer = timer_new_ms(QEMU_CLOCK_REALTIME, func, opaque);
> +
> +#if SPICE_INTERFACE_CORE_MAJOR >= 2
> + bool aio = sin ? !!sin->user_data : false;
Shouldn't there be a cast there:
(bool)sin->user_data
?
> + if (aio) {
> + fprintf(stderr, "AIO doesn't have timers yet, using BH\n");
> + timer->bh = qemu_bh_new(func, opaque);
> + } else
> +#endif
> + {
> + timer->timer = timer_new_ms(QEMU_CLOCK_REALTIME, func, opaque);
> + }
> +
> QTAILQ_INSERT_TAIL(&timers, timer, next);
> +
> return timer;
> }
>
> static void timer_start(SpiceTimer *timer, uint32_t ms)
> {
> - timer_mod(timer->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ms);
> + if (timer->bh) {
> + qemu_bh_schedule_idle(timer->bh); /* at least every 10ms, see async.c */
> + } else {
> + timer_mod(timer->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + ms);
> + }
> }
>
> static void timer_cancel(SpiceTimer *timer)
> {
> - timer_del(timer->timer);
> + if (timer->bh) {
> + qemu_bh_cancel(timer->bh);
> + } else {
> + timer_del(timer->timer);
> + }
> }
>
> static void timer_remove(SpiceTimer *timer)
> {
> - timer_del(timer->timer);
> - timer_free(timer->timer);
> + if (timer->bh) {
> + qemu_bh_delete(timer->bh);
> + } else {
> + timer_del(timer->timer);
> + timer_free(timer->timer);
> + }
> +
> QTAILQ_REMOVE(&timers, timer, next);
> g_free(timer);
> }
> @@ -89,6 +119,7 @@ struct SpiceWatch {
> int fd;
> int event_mask;
> SpiceWatchFunc func;
> + bool aio;
> void *opaque;
> QTAILQ_ENTRY(SpiceWatch) next;
> };
> @@ -118,10 +149,19 @@ static void watch_update_mask(SpiceWatch *watch, int event_mask)
> if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
> on_write = watch_write;
> }
> - qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
> +
> + if (watch->aio) {
> + qemu_aio_set_fd_handler(watch->fd, on_read, on_write, watch);
> + } else {
> + qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
> + }
> }
>
> +#if SPICE_INTERFACE_CORE_MAJOR >= 2
> +static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque, SpiceBaseInstance *sin)
> +#else
> static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
> +#endif
> {
> SpiceWatch *watch;
>
> @@ -129,6 +169,10 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
> watch->fd = fd;
> watch->func = func;
> watch->opaque = opaque;
> +#if SPICE_INTERFACE_CORE_MAJOR >= 2
> + watch->aio = sin ? !!sin->user_data : false;
> +#endif
> +
> QTAILQ_INSERT_TAIL(&watches, watch, next);
>
> watch_update_mask(watch, event_mask);
> @@ -137,7 +181,11 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
>
> static void watch_remove(SpiceWatch *watch)
> {
> - qemu_set_fd_handler(watch->fd, NULL, NULL, NULL);
> + if (watch->aio) {
> + qemu_aio_set_fd_handler(watch->fd, NULL, NULL, NULL);
> + } else {
> + qemu_set_fd_handler(watch->fd, NULL, NULL, NULL);
> + }
> QTAILQ_REMOVE(&watches, watch, next);
> g_free(watch);
> }
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 21/21] block: add spice block device backend
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (19 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 20/21] spice-core: allow an interface to be in AIO context Marc-André Lureau
@ 2013-11-18 12:25 ` Marc-André Lureau
2013-11-20 11:00 ` Marc-André Lureau
2013-11-22 13:28 ` [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
21 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-18 12:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Marc-André Lureau, jcody, kraxel, spice-devel
From: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
block/Makefile.objs | 1 +
block/spicebd.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 537 insertions(+)
create mode 100644 block/spicebd.c
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 4e8c91e..f49b7c3 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -16,6 +16,7 @@ block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
block-obj-$(CONFIG_LIBSSH2) += ssh.o
+common-obj-$(CONFIG_SPICE) += spicebd.o
endif
common-obj-y += stream.o
diff --git a/block/spicebd.c b/block/spicebd.c
new file mode 100644
index 0000000..6b23b61
--- /dev/null
+++ b/block/spicebd.c
@@ -0,0 +1,536 @@
+/*
+ * Spice block backend for QEMU.
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ * Author: Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <spice/protocol.h>
+
+#include "nbd-client.h"
+#include "ui/qemu-spice.h"
+#include "block/block_int.h"
+#include "qemu/sockets.h"
+#include "qemu/uri.h"
+#include "qapi/qmp/qint.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/char.h"
+#include "qmp-commands.h"
+#include "sysemu/blockdev.h"
+#include "migration/migration.h"
+
+#ifndef DEBUG_SPICE
+#define DEBUG_SPICE 0
+#endif
+
+#define SOCKET_CHR 0
+#define SOCKET_NBD 1
+
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_SPICE) { \
+ fprintf(stderr, "spicebd: %-15s " fmt "\n", \
+ __func__, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+typedef struct Buffer {
+ uint8_t data[4096];
+ uint8_t *p;
+ char left;
+} Buffer;
+
+typedef struct BDRVSpiceState {
+ BlockDriverState *bs;
+ QEMUBH *bh;
+ NbdClientSession client;
+
+ /* our spicechr-fd pipe */
+ int sv[2];
+ Buffer readb;
+ Buffer writeb;
+
+ int aio_count;
+ CharDriverState *chr;
+ guint chr_watch;
+
+ Coroutine *coroutine;
+ bool need_read;
+ bool need_write;
+ bool opened;
+ bool inmigrate;
+} BDRVSpiceState;
+
+static void nbd_read_handler(void *opaque);
+static void update_chr_handlers(BDRVSpiceState *s);
+
+static int parse_uri(const char *filename, QDict *options, Error **errp)
+{
+ URI *uri = NULL;
+
+ uri = uri_parse(filename);
+ if (!uri) {
+ return -EINVAL;
+ }
+
+ if (strcmp(uri->scheme, "spicebd") != 0) {
+ error_setg(errp, "URI scheme must be 'spicebd'");
+ goto err;
+ }
+
+ uri_free(uri);
+ return 0;
+
+ err:
+ if (uri) {
+ uri_free(uri);
+ }
+ return -EINVAL;
+}
+
+static void spice_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ parse_uri(filename, options, errp);
+}
+
+static void co_restart(void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+
+ qemu_coroutine_enter(s->coroutine, NULL);
+}
+
+static void close_socketpair(BDRVSpiceState *s)
+{
+ if (!s->opened) {
+ return;
+ }
+
+ DPRINTF("");
+ nbd_client_session_close(&s->client);
+
+ if (s->sv[SOCKET_NBD] >= 0) {
+ qemu_aio_set_fd_handler(s->sv[SOCKET_NBD], NULL, NULL, NULL);
+ closesocket(s->sv[SOCKET_NBD]);
+ s->sv[SOCKET_NBD] = -1;
+ }
+
+ if (s->sv[SOCKET_CHR] >= 0) {
+ qemu_aio_set_fd_handler(s->sv[SOCKET_CHR], NULL, NULL, NULL);
+ closesocket(s->sv[SOCKET_CHR]);
+ s->sv[SOCKET_CHR] = -1;
+ }
+
+ if (s->inmigrate) {
+ vm_start_release();
+ s->inmigrate = false;
+ }
+
+ s->opened = FALSE;
+ if (s->coroutine && s->coroutine != qemu_coroutine_self()) {
+ co_restart(s);
+ }
+}
+
+static int chardev_can_read(void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+ int retval = 0;
+
+ GPollFD pfd = {
+ .fd = s->sv[SOCKET_CHR],
+ .events = G_IO_OUT
+ };
+ g_poll(&pfd, 1, 0);
+ if (pfd.revents & G_IO_OUT) {
+ retval = s->writeb.left == 0 ? sizeof(s->writeb.data) : 0;
+ }
+
+ return retval;
+}
+
+static void chardev_read(void *opaque, const uint8_t *buf, int size)
+{
+ BDRVSpiceState *s = opaque;
+ int written;
+
+ DPRINTF("reply from client %d", size);
+ written = write(s->sv[SOCKET_CHR], buf, size);
+ if (written == -1) {
+ if (errno != EAGAIN) {
+ close_socketpair(s);
+ return;
+ } else {
+ written = 0;
+ }
+ }
+
+ if (s->writeb.left == 0) {
+ size -= written;
+ assert(size <= sizeof(s->writeb.data));
+ memcpy(s->writeb.data, buf, size);
+ s->writeb.p = s->writeb.data;
+ s->writeb.left = size;
+ } else {
+ s->writeb.left -= written;
+ s->writeb.p += written;
+ }
+
+ s->need_write = s->writeb.left > 0;
+ update_chr_handlers(s);
+}
+
+static void change_blockdev_cb(void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+ BlockDriverState *bs = s->bs;
+ Error *err = NULL;
+ int bdrv_flags;
+ QDict *options = NULL;
+ char device_name[32];
+
+ qemu_bh_delete(s->bh);
+ s->bh = NULL;
+
+ memcpy(device_name, bs->child_device_name, sizeof(device_name));
+ DPRINTF("set bs %p to NULL", bs);
+ bs->opaque = NULL;
+
+ bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
+ if (bdrv_is_snapshot(bs)) {
+ bdrv_flags |= BDRV_O_SNAPSHOT;
+ options = qdict_new();
+ qdict_put(options, "snapshot.size", qint_from_int(s->client.size));
+ }
+
+ qmp_eject(device_name, true, true, &err);
+ if (error_is_set(&err)) {
+ fprintf(stderr, "spicebd: %s\n", error_get_pretty(err));
+ error_free(err);
+ QDECREF(options);
+ free(s);
+ }
+
+ qmp_change_blockdev_int(device_name, "spicebd:", NULL,
+ options, s, &err);
+ if (error_is_set(&err)) {
+ fprintf(stderr, "spicebd: %s\n", error_get_pretty(err));
+ error_free(err);
+ }
+
+ if (s->inmigrate) {
+ vm_start_release();
+ s->inmigrate = false;
+ }
+}
+
+static void coroutine_fn co_init(void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+ BlockDriverState *bs = s->bs;
+
+ DPRINTF("temporary coroutine for session initialization %p, "
+ "device: %s", s, bs->child_device_name);
+
+ qemu_set_nonblock(s->sv[SOCKET_NBD]);
+ /* After session_init, the fd_handler is managed by nbd-client */
+ qemu_aio_set_fd_handler(s->sv[SOCKET_NBD], co_restart, NULL, s);
+ if (nbd_client_session_init(&s->client, bs,
+ s->sv[SOCKET_NBD], NULL) < 0) {
+ close_socketpair(s);
+ } else {
+ assert(s->bh == NULL);
+ /* NOTE: need to defer out of current AIO call, to avoid non-blocking
+ drain_all when ejecting? */
+ s->bh = qemu_bh_new(change_blockdev_cb, s);
+ qemu_bh_schedule(s->bh);
+ }
+
+ s->coroutine = NULL;
+ DPRINTF("end of temporary coroutine");
+}
+
+static void spice_init(BDRVSpiceState *s)
+{
+ if (s->opened) {
+ return;
+ }
+
+ s->opened = TRUE;
+
+ /* TODO: teach nbd to use a iostream api instead of a socket */
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, s->sv) == -1) {
+ fprintf(stderr, "failed to create socketpair\n");
+ return;
+ }
+
+ s->need_read = TRUE;
+ update_chr_handlers(s);
+
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ vm_start_hold();
+ s->inmigrate = true;
+ }
+
+ /* tell server we are ready */
+ qemu_chr_fe_event(s->chr, SPICE_PORT_EVENT_OPENED);
+ s->coroutine = qemu_coroutine_create(co_init);
+ qemu_coroutine_enter(s->coroutine, s);
+}
+
+static void chardev_event(void *opaque, int event)
+{
+ BDRVSpiceState *s = opaque;
+
+ switch (event) {
+ case CHR_EVENT_CLOSED:
+ DPRINTF("chardev close");
+ close_socketpair(s);
+ break;
+ case CHR_EVENT_BREAK:
+ DPRINTF("chardev break");
+ if (s->coroutine) {
+ DPRINTF("already waiting for incoming session");
+ qemu_chr_fe_event(s->chr, SPICE_PORT_EVENT_OPENED);
+ return;
+ }
+ close_socketpair(s);
+ /* fall-through */
+ case CHR_EVENT_OPENED:
+ DPRINTF("chardev opened");
+ spice_init(s);
+ break;
+ default:
+ DPRINTF("unhandled chardev event %d", event);
+ }
+}
+
+static gboolean write_to_chr(GIOChannel *chan, GIOCondition cond,
+ void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+ int r;
+
+ r = qemu_chr_fe_write(s->chr, s->readb.p, s->readb.left);
+ DPRINTF("write_to_chr %d/%d", r, s->readb.left);
+ if (r <= 0) {
+ close_socketpair(s);
+ return FALSE;
+ }
+
+ s->readb.p += r;
+ s->readb.left -= r;
+
+ if (s->readb.left > 0) {
+ if (!s->chr_watch) {
+ s->chr_watch = qemu_chr_fe_add_watch(s->chr, G_IO_OUT,
+ write_to_chr, s);
+ }
+ return TRUE;
+ } else {
+ s->need_read = TRUE;
+ update_chr_handlers(s);
+ }
+
+ return FALSE;
+}
+
+static void nbd_read_handler(void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+
+ DPRINTF("read from nbd");
+
+ if (s->readb.left > 0) {
+ abort();
+ }
+
+ do {
+ s->readb.left = recv(s->sv[SOCKET_CHR], s->readb.data,
+ sizeof(s->readb.data), MSG_DONTWAIT);
+ } while (s->readb.left == -1 && errno == EAGAIN);
+
+ if (s->readb.left <= 0) {
+ close_socketpair(s);
+ return;
+ }
+
+ s->need_read = FALSE;
+ update_chr_handlers(s);
+
+ s->readb.p = s->readb.data;
+ write_to_chr(NULL, 0, s);
+}
+
+static void nbd_write_handler(void *opaque)
+{
+ BDRVSpiceState *s = opaque;
+
+ DPRINTF("resuming chardev_read left: %d", s->writeb.left);
+
+ chardev_read(s, s->writeb.data, s->writeb.left);
+}
+
+static void update_chr_handlers(BDRVSpiceState *s)
+{
+ qemu_aio_set_fd_handler(s->sv[SOCKET_CHR],
+ s->need_read ? nbd_read_handler : NULL,
+ s->need_write ? nbd_write_handler : NULL,
+ s);
+}
+
+static int spice_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
+ Error **errp)
+{
+ BDRVSpiceState *s = bs->opaque;
+ int ret = -1;
+
+ s->bs = bs;
+
+ if (s->opened) {
+ DPRINTF("re-open spicebd");
+ s->client.bs = bs;
+ return 0;
+ }
+
+ DPRINTF("open %p device=%s flags=0x%x", s,
+ bs->child_device_name, bdrv_flags);
+ if (strlen(bs->child_device_name) == 0) {
+ fprintf(stderr, "spicebd: missing associated child device\n");
+ return -1;
+ }
+
+ if (bdrv_flags & BDRV_O_RDWR) {
+ fprintf(stderr, "spicebd: only read-only supported\n");
+ return -1;
+ }
+
+ s->chr = qemu_chr_open_spice_vmc("nbd", true);
+ if (!s->chr) {
+ goto err;
+ }
+
+ qemu_chr_add_handlers(s->chr, chardev_can_read,
+ chardev_read, chardev_event, s);
+ spice_init(s);
+
+ return 0;
+
+ err:
+ return ret;
+}
+
+static void spice_close(BlockDriverState *bs)
+{
+ BDRVSpiceState *s = bs->opaque;
+
+ DPRINTF("spice close %p\n", s);
+
+ if (s == NULL) {
+ /* changing bd */
+ return;
+ }
+
+ s->bs = NULL;
+
+ close_socketpair(s);
+ assert(!s->coroutine); /* after close_socketpair */
+
+ if (s->chr) {
+ s->chr->chr_close(s->chr);
+ g_free(s->chr);
+ s->chr = NULL;
+ }
+}
+
+static coroutine_fn int spice_co_readv(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov)
+{
+ BDRVSpiceState *s = bs->opaque;
+
+ return nbd_client_session_co_readv(&s->client, sector_num,
+ nb_sectors, qiov);
+}
+
+static coroutine_fn int spice_co_writev(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors, QEMUIOVector *qiov)
+{
+ BDRVSpiceState *s = bs->opaque;
+
+ return nbd_client_session_co_writev(&s->client, sector_num,
+ nb_sectors, qiov);
+}
+
+static coroutine_fn int spice_co_flush(BlockDriverState *bs)
+{
+ BDRVSpiceState *s = bs->opaque;
+
+ if (s == NULL) {
+ /* changing bd */
+ return -1;
+ }
+
+ return nbd_client_session_co_flush(&s->client);
+}
+
+static coroutine_fn int spice_co_discard(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors)
+{
+ BDRVSpiceState *s = bs->opaque;
+
+ return nbd_client_session_co_discard(&s->client, sector_num, nb_sectors);
+}
+
+static coroutine_fn int64_t spice_getlength(BlockDriverState *bs)
+{
+ BDRVSpiceState *s = bs->opaque;
+
+ DPRINTF("length=%" PRIi64, s->client.size);
+
+ return s->client.size;
+}
+
+static BlockDriver bdrv_spice = {
+ .format_name = "spicebd",
+ .protocol_name = "spicebd",
+ .instance_size = sizeof(BDRVSpiceState),
+ .bdrv_parse_filename = spice_parse_filename,
+ .bdrv_file_open = spice_file_open,
+ .bdrv_close = spice_close,
+ .bdrv_co_readv = spice_co_readv,
+ .bdrv_co_writev = spice_co_writev,
+ .bdrv_getlength = spice_getlength,
+ .bdrv_co_flush_to_os = spice_co_flush,
+ .bdrv_co_discard = spice_co_discard,
+};
+
+static void bdrv_spice_init(void)
+{
+ bdrv_register(&bdrv_spice);
+}
+
+block_init(bdrv_spice_init);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 21/21] block: add spice block device backend
2013-11-18 12:25 ` [Qemu-devel] [PATCH 21/21] block: add spice block device backend Marc-André Lureau
@ 2013-11-20 11:00 ` Marc-André Lureau
0 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-20 11:00 UTC (permalink / raw)
To: qemu-devel
/note to self:
- add failing case where nbd channel isn't connected before and after
migration (do not wait for nbd init or disconnection)
On Mon, Nov 18, 2013 at 1:25 PM, Marc-André Lureau
<marcandre.lureau@gmail.com> wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> block/Makefile.objs | 1 +
> block/spicebd.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 537 insertions(+)
> create mode 100644 block/spicebd.c
>
> diff --git a/block/Makefile.objs b/block/Makefile.objs
> index 4e8c91e..f49b7c3 100644
> --- a/block/Makefile.objs
> +++ b/block/Makefile.objs
> @@ -16,6 +16,7 @@ block-obj-$(CONFIG_CURL) += curl.o
> block-obj-$(CONFIG_RBD) += rbd.o
> block-obj-$(CONFIG_GLUSTERFS) += gluster.o
> block-obj-$(CONFIG_LIBSSH2) += ssh.o
> +common-obj-$(CONFIG_SPICE) += spicebd.o
> endif
>
> common-obj-y += stream.o
> diff --git a/block/spicebd.c b/block/spicebd.c
> new file mode 100644
> index 0000000..6b23b61
> --- /dev/null
> +++ b/block/spicebd.c
> @@ -0,0 +1,536 @@
> +/*
> + * Spice block backend for QEMU.
> + *
> + * Copyright (C) 2013 Red Hat, Inc.
> + * Author: Marc-André Lureau <marcandre.lureau@redhat.com>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <spice/protocol.h>
> +
> +#include "nbd-client.h"
> +#include "ui/qemu-spice.h"
> +#include "block/block_int.h"
> +#include "qemu/sockets.h"
> +#include "qemu/uri.h"
> +#include "qapi/qmp/qint.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/char.h"
> +#include "qmp-commands.h"
> +#include "sysemu/blockdev.h"
> +#include "migration/migration.h"
> +
> +#ifndef DEBUG_SPICE
> +#define DEBUG_SPICE 0
> +#endif
> +
> +#define SOCKET_CHR 0
> +#define SOCKET_NBD 1
> +
> +#define DPRINTF(fmt, ...) \
> + do { \
> + if (DEBUG_SPICE) { \
> + fprintf(stderr, "spicebd: %-15s " fmt "\n", \
> + __func__, ##__VA_ARGS__); \
> + } \
> + } while (0)
> +
> +typedef struct Buffer {
> + uint8_t data[4096];
> + uint8_t *p;
> + char left;
> +} Buffer;
> +
> +typedef struct BDRVSpiceState {
> + BlockDriverState *bs;
> + QEMUBH *bh;
> + NbdClientSession client;
> +
> + /* our spicechr-fd pipe */
> + int sv[2];
> + Buffer readb;
> + Buffer writeb;
> +
> + int aio_count;
> + CharDriverState *chr;
> + guint chr_watch;
> +
> + Coroutine *coroutine;
> + bool need_read;
> + bool need_write;
> + bool opened;
> + bool inmigrate;
> +} BDRVSpiceState;
> +
> +static void nbd_read_handler(void *opaque);
> +static void update_chr_handlers(BDRVSpiceState *s);
> +
> +static int parse_uri(const char *filename, QDict *options, Error **errp)
> +{
> + URI *uri = NULL;
> +
> + uri = uri_parse(filename);
> + if (!uri) {
> + return -EINVAL;
> + }
> +
> + if (strcmp(uri->scheme, "spicebd") != 0) {
> + error_setg(errp, "URI scheme must be 'spicebd'");
> + goto err;
> + }
> +
> + uri_free(uri);
> + return 0;
> +
> + err:
> + if (uri) {
> + uri_free(uri);
> + }
> + return -EINVAL;
> +}
> +
> +static void spice_parse_filename(const char *filename, QDict *options,
> + Error **errp)
> +{
> + parse_uri(filename, options, errp);
> +}
> +
> +static void co_restart(void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> +
> + qemu_coroutine_enter(s->coroutine, NULL);
> +}
> +
> +static void close_socketpair(BDRVSpiceState *s)
> +{
> + if (!s->opened) {
> + return;
> + }
> +
> + DPRINTF("");
> + nbd_client_session_close(&s->client);
> +
> + if (s->sv[SOCKET_NBD] >= 0) {
> + qemu_aio_set_fd_handler(s->sv[SOCKET_NBD], NULL, NULL, NULL);
> + closesocket(s->sv[SOCKET_NBD]);
> + s->sv[SOCKET_NBD] = -1;
> + }
> +
> + if (s->sv[SOCKET_CHR] >= 0) {
> + qemu_aio_set_fd_handler(s->sv[SOCKET_CHR], NULL, NULL, NULL);
> + closesocket(s->sv[SOCKET_CHR]);
> + s->sv[SOCKET_CHR] = -1;
> + }
> +
> + if (s->inmigrate) {
> + vm_start_release();
> + s->inmigrate = false;
> + }
> +
> + s->opened = FALSE;
> + if (s->coroutine && s->coroutine != qemu_coroutine_self()) {
> + co_restart(s);
> + }
> +}
> +
> +static int chardev_can_read(void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> + int retval = 0;
> +
> + GPollFD pfd = {
> + .fd = s->sv[SOCKET_CHR],
> + .events = G_IO_OUT
> + };
> + g_poll(&pfd, 1, 0);
> + if (pfd.revents & G_IO_OUT) {
> + retval = s->writeb.left == 0 ? sizeof(s->writeb.data) : 0;
> + }
> +
> + return retval;
> +}
> +
> +static void chardev_read(void *opaque, const uint8_t *buf, int size)
> +{
> + BDRVSpiceState *s = opaque;
> + int written;
> +
> + DPRINTF("reply from client %d", size);
> + written = write(s->sv[SOCKET_CHR], buf, size);
> + if (written == -1) {
> + if (errno != EAGAIN) {
> + close_socketpair(s);
> + return;
> + } else {
> + written = 0;
> + }
> + }
> +
> + if (s->writeb.left == 0) {
> + size -= written;
> + assert(size <= sizeof(s->writeb.data));
> + memcpy(s->writeb.data, buf, size);
> + s->writeb.p = s->writeb.data;
> + s->writeb.left = size;
> + } else {
> + s->writeb.left -= written;
> + s->writeb.p += written;
> + }
> +
> + s->need_write = s->writeb.left > 0;
> + update_chr_handlers(s);
> +}
> +
> +static void change_blockdev_cb(void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> + BlockDriverState *bs = s->bs;
> + Error *err = NULL;
> + int bdrv_flags;
> + QDict *options = NULL;
> + char device_name[32];
> +
> + qemu_bh_delete(s->bh);
> + s->bh = NULL;
> +
> + memcpy(device_name, bs->child_device_name, sizeof(device_name));
> + DPRINTF("set bs %p to NULL", bs);
> + bs->opaque = NULL;
> +
> + bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
> + if (bdrv_is_snapshot(bs)) {
> + bdrv_flags |= BDRV_O_SNAPSHOT;
> + options = qdict_new();
> + qdict_put(options, "snapshot.size", qint_from_int(s->client.size));
> + }
> +
> + qmp_eject(device_name, true, true, &err);
> + if (error_is_set(&err)) {
> + fprintf(stderr, "spicebd: %s\n", error_get_pretty(err));
> + error_free(err);
> + QDECREF(options);
> + free(s);
> + }
> +
> + qmp_change_blockdev_int(device_name, "spicebd:", NULL,
> + options, s, &err);
> + if (error_is_set(&err)) {
> + fprintf(stderr, "spicebd: %s\n", error_get_pretty(err));
> + error_free(err);
> + }
> +
> + if (s->inmigrate) {
> + vm_start_release();
> + s->inmigrate = false;
> + }
> +}
> +
> +static void coroutine_fn co_init(void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> + BlockDriverState *bs = s->bs;
> +
> + DPRINTF("temporary coroutine for session initialization %p, "
> + "device: %s", s, bs->child_device_name);
> +
> + qemu_set_nonblock(s->sv[SOCKET_NBD]);
> + /* After session_init, the fd_handler is managed by nbd-client */
> + qemu_aio_set_fd_handler(s->sv[SOCKET_NBD], co_restart, NULL, s);
> + if (nbd_client_session_init(&s->client, bs,
> + s->sv[SOCKET_NBD], NULL) < 0) {
> + close_socketpair(s);
> + } else {
> + assert(s->bh == NULL);
> + /* NOTE: need to defer out of current AIO call, to avoid non-blocking
> + drain_all when ejecting? */
> + s->bh = qemu_bh_new(change_blockdev_cb, s);
> + qemu_bh_schedule(s->bh);
> + }
> +
> + s->coroutine = NULL;
> + DPRINTF("end of temporary coroutine");
> +}
> +
> +static void spice_init(BDRVSpiceState *s)
> +{
> + if (s->opened) {
> + return;
> + }
> +
> + s->opened = TRUE;
> +
> + /* TODO: teach nbd to use a iostream api instead of a socket */
> + if (socketpair(PF_UNIX, SOCK_STREAM, 0, s->sv) == -1) {
> + fprintf(stderr, "failed to create socketpair\n");
> + return;
> + }
> +
> + s->need_read = TRUE;
> + update_chr_handlers(s);
> +
> + if (runstate_check(RUN_STATE_INMIGRATE)) {
> + vm_start_hold();
> + s->inmigrate = true;
> + }
> +
> + /* tell server we are ready */
> + qemu_chr_fe_event(s->chr, SPICE_PORT_EVENT_OPENED);
> + s->coroutine = qemu_coroutine_create(co_init);
> + qemu_coroutine_enter(s->coroutine, s);
> +}
> +
> +static void chardev_event(void *opaque, int event)
> +{
> + BDRVSpiceState *s = opaque;
> +
> + switch (event) {
> + case CHR_EVENT_CLOSED:
> + DPRINTF("chardev close");
> + close_socketpair(s);
> + break;
> + case CHR_EVENT_BREAK:
> + DPRINTF("chardev break");
> + if (s->coroutine) {
> + DPRINTF("already waiting for incoming session");
> + qemu_chr_fe_event(s->chr, SPICE_PORT_EVENT_OPENED);
> + return;
> + }
> + close_socketpair(s);
> + /* fall-through */
> + case CHR_EVENT_OPENED:
> + DPRINTF("chardev opened");
> + spice_init(s);
> + break;
> + default:
> + DPRINTF("unhandled chardev event %d", event);
> + }
> +}
> +
> +static gboolean write_to_chr(GIOChannel *chan, GIOCondition cond,
> + void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> + int r;
> +
> + r = qemu_chr_fe_write(s->chr, s->readb.p, s->readb.left);
> + DPRINTF("write_to_chr %d/%d", r, s->readb.left);
> + if (r <= 0) {
> + close_socketpair(s);
> + return FALSE;
> + }
> +
> + s->readb.p += r;
> + s->readb.left -= r;
> +
> + if (s->readb.left > 0) {
> + if (!s->chr_watch) {
> + s->chr_watch = qemu_chr_fe_add_watch(s->chr, G_IO_OUT,
> + write_to_chr, s);
> + }
> + return TRUE;
> + } else {
> + s->need_read = TRUE;
> + update_chr_handlers(s);
> + }
> +
> + return FALSE;
> +}
> +
> +static void nbd_read_handler(void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> +
> + DPRINTF("read from nbd");
> +
> + if (s->readb.left > 0) {
> + abort();
> + }
> +
> + do {
> + s->readb.left = recv(s->sv[SOCKET_CHR], s->readb.data,
> + sizeof(s->readb.data), MSG_DONTWAIT);
> + } while (s->readb.left == -1 && errno == EAGAIN);
> +
> + if (s->readb.left <= 0) {
> + close_socketpair(s);
> + return;
> + }
> +
> + s->need_read = FALSE;
> + update_chr_handlers(s);
> +
> + s->readb.p = s->readb.data;
> + write_to_chr(NULL, 0, s);
> +}
> +
> +static void nbd_write_handler(void *opaque)
> +{
> + BDRVSpiceState *s = opaque;
> +
> + DPRINTF("resuming chardev_read left: %d", s->writeb.left);
> +
> + chardev_read(s, s->writeb.data, s->writeb.left);
> +}
> +
> +static void update_chr_handlers(BDRVSpiceState *s)
> +{
> + qemu_aio_set_fd_handler(s->sv[SOCKET_CHR],
> + s->need_read ? nbd_read_handler : NULL,
> + s->need_write ? nbd_write_handler : NULL,
> + s);
> +}
> +
> +static int spice_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
> + Error **errp)
> +{
> + BDRVSpiceState *s = bs->opaque;
> + int ret = -1;
> +
> + s->bs = bs;
> +
> + if (s->opened) {
> + DPRINTF("re-open spicebd");
> + s->client.bs = bs;
> + return 0;
> + }
> +
> + DPRINTF("open %p device=%s flags=0x%x", s,
> + bs->child_device_name, bdrv_flags);
> + if (strlen(bs->child_device_name) == 0) {
> + fprintf(stderr, "spicebd: missing associated child device\n");
> + return -1;
> + }
> +
> + if (bdrv_flags & BDRV_O_RDWR) {
> + fprintf(stderr, "spicebd: only read-only supported\n");
> + return -1;
> + }
> +
> + s->chr = qemu_chr_open_spice_vmc("nbd", true);
> + if (!s->chr) {
> + goto err;
> + }
> +
> + qemu_chr_add_handlers(s->chr, chardev_can_read,
> + chardev_read, chardev_event, s);
> + spice_init(s);
> +
> + return 0;
> +
> + err:
> + return ret;
> +}
> +
> +static void spice_close(BlockDriverState *bs)
> +{
> + BDRVSpiceState *s = bs->opaque;
> +
> + DPRINTF("spice close %p\n", s);
> +
> + if (s == NULL) {
> + /* changing bd */
> + return;
> + }
> +
> + s->bs = NULL;
> +
> + close_socketpair(s);
> + assert(!s->coroutine); /* after close_socketpair */
> +
> + if (s->chr) {
> + s->chr->chr_close(s->chr);
> + g_free(s->chr);
> + s->chr = NULL;
> + }
> +}
> +
> +static coroutine_fn int spice_co_readv(BlockDriverState *bs,
> + int64_t sector_num,
> + int nb_sectors, QEMUIOVector *qiov)
> +{
> + BDRVSpiceState *s = bs->opaque;
> +
> + return nbd_client_session_co_readv(&s->client, sector_num,
> + nb_sectors, qiov);
> +}
> +
> +static coroutine_fn int spice_co_writev(BlockDriverState *bs,
> + int64_t sector_num,
> + int nb_sectors, QEMUIOVector *qiov)
> +{
> + BDRVSpiceState *s = bs->opaque;
> +
> + return nbd_client_session_co_writev(&s->client, sector_num,
> + nb_sectors, qiov);
> +}
> +
> +static coroutine_fn int spice_co_flush(BlockDriverState *bs)
> +{
> + BDRVSpiceState *s = bs->opaque;
> +
> + if (s == NULL) {
> + /* changing bd */
> + return -1;
> + }
> +
> + return nbd_client_session_co_flush(&s->client);
> +}
> +
> +static coroutine_fn int spice_co_discard(BlockDriverState *bs,
> + int64_t sector_num, int nb_sectors)
> +{
> + BDRVSpiceState *s = bs->opaque;
> +
> + return nbd_client_session_co_discard(&s->client, sector_num, nb_sectors);
> +}
> +
> +static coroutine_fn int64_t spice_getlength(BlockDriverState *bs)
> +{
> + BDRVSpiceState *s = bs->opaque;
> +
> + DPRINTF("length=%" PRIi64, s->client.size);
> +
> + return s->client.size;
> +}
> +
> +static BlockDriver bdrv_spice = {
> + .format_name = "spicebd",
> + .protocol_name = "spicebd",
> + .instance_size = sizeof(BDRVSpiceState),
> + .bdrv_parse_filename = spice_parse_filename,
> + .bdrv_file_open = spice_file_open,
> + .bdrv_close = spice_close,
> + .bdrv_co_readv = spice_co_readv,
> + .bdrv_co_writev = spice_co_writev,
> + .bdrv_getlength = spice_getlength,
> + .bdrv_co_flush_to_os = spice_co_flush,
> + .bdrv_co_discard = spice_co_discard,
> +};
> +
> +static void bdrv_spice_init(void)
> +{
> + bdrv_register(&bdrv_spice);
> +}
> +
> +block_init(bdrv_spice_init);
> --
> 1.8.3.1
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device
2013-11-18 12:25 [Qemu-devel] [PATCH 00/21] RFCv2: add Spice block device Marc-André Lureau
` (20 preceding siblings ...)
2013-11-18 12:25 ` [Qemu-devel] [PATCH 21/21] block: add spice block device backend Marc-André Lureau
@ 2013-11-22 13:28 ` Marc-André Lureau
2013-11-29 9:51 ` Gerd Hoffmann
21 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2013-11-22 13:28 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, jcody, Marc-André Lureau, Gerd Hoffmann
Hi there,
Even though there is no rush to review this series, it would be nice
to get the first ~10 patches. It would make the next rebase easier,
and the review smaller.
cheers
On Mon, Nov 18, 2013 at 1:25 PM, Marc-André Lureau
<marcandre.lureau@gmail.com> wrote:
> Hi,
>
> The following patch series implement a Spice block device, which
> allows the client to redirect a block device using the NBD protocol,
> which greatly simplifies the Spice code by reusing an existing
> protocol, and allows sharing existing qemu NBD implementation.
>
> The backend only support read-only device atm (although it shouldn't
> be hard to add write support if necessary)
>
> Usage with a CDROM drive:
> -device ide-cd,drive=cd -drive if=none,id=cd,readonly,file=spicebd:
>
> The associated server and client bits are:
> http://lists.freedesktop.org/archives/spice-devel/2013-June/013608.html
> http://lists.freedesktop.org/archives/spice-devel/2013-November/015452.html
> http://lists.freedesktop.org/archives/spice-devel/2013-November/015431.html
>
> Caveats: This block device driver is a bit special, since it is
> successfully initialized with size 0, and once the client is connected
> (or want to change block device) it re-opens itself. For this to work,
> we allow a block driver to be open with an existing opaque data. We
> also save the associate device name in the block drivers.
>
> During migration, the source needs to be able to flush pending
> operations, so the Spice channel context must be in a running loop. A
> modification to the Spice server API allows to associate a particular
> channel with the AIO loop, and may be used in the future to associate
> channels with different context or athreads. However, the AIO context
> doesn't have timers yet. Since they aren't really needed for the NBD
> channel, it's not a problem. I have been told timers in AIO are on
> their way, so this could be updated later.
>
> Since the block driver state is not migrated, the destination needs to
> wait until the block driver is initialized before the VM can run. This
> is done with a simple hold count. It is also necessary to avoid extra
> media changed notifications, which is easily done by checking
> migration state.
>
>
> Marc-André Lureau (21):
> vscclient: do not add a socket watch if there is not data to send
> spice-char: remove unused field
> qmp_change_blockdev() remove unused has_format
> include: add missing config-host.h include
> char: add qemu_chr_fe_event()
> Split nbd block client code
> nbd: don't change socket block during negotiate
> nbd: pass export name as init argument
> nbd: make session_close() idempotent
> nbd: finish any pending coroutine
> nbd: avoid uninitialized warnings
> block: save the associated child name in BlockDriverState
> blockdev: add qmp_change_blockdev_int()
> block: extract make_snapshot() from bdrv_open()
> block: add "snapshot.size" option to avoid extra bdrv_open()
> block: learn to open a driver with a given opaque
> block: allow to call bdrv_open() with an opaque
> block: do not notify change during migration
> sysemu: add vm_start_hold/release
> spice-core: allow an interface to be in AIO context
> block: add spice block device backend
>
> block.c | 225 ++++++++++++-------
> block/Makefile.objs | 3 +-
> block/nbd-client.c | 384 +++++++++++++++++++++++++++++++++
> block/nbd-client.h | 50 +++++
> block/nbd.c | 380 +++-----------------------------
> block/spicebd.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++
> blockdev.c | 24 ++-
> hw/block/fdc.c | 8 +-
> hw/ide/core.c | 12 +-
> hw/scsi/scsi-disk.c | 11 +-
> hw/sd/sd.c | 6 +-
> include/block/block.h | 2 +-
> include/block/block_int.h | 1 +
> include/sysemu/blockdev.h | 5 +-
> include/sysemu/char.h | 10 +
> include/sysemu/sysemu.h | 2 +
> include/ui/qemu-spice.h | 4 +-
> libcacard/vscclient.c | 10 +-
> nbd.c | 1 -
> qemu-char.c | 9 +-
> qmp.c | 2 +-
> spice-qemu-char.c | 20 +-
> stubs/vm-stop.c | 5 +
> ui/spice-core.c | 62 +++++-
> vl.c | 17 ++
> 25 files changed, 1320 insertions(+), 469 deletions(-)
> create mode 100644 block/nbd-client.c
> create mode 100644 block/nbd-client.h
> create mode 100644 block/spicebd.c
>
> --
> 1.8.3.1
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 28+ messages in thread