[Spice-commits] 52 commits - VERSION block.c block/commit.c block/cow.c block/qed.c block/raw-posix.c block/stream.c block/vdi.c block/vmdk.c block/vpc.c blockdev.c configure docs/qmp exec.c hmp.c hw/block hw/core hw/input hw/s390x hw/timer hw/usb hw/virtio include/block include/exec include/hw include/qom memory.c net/Makefile.objs net/net.c qapi/block-core.json qapi/event.json qemu-doc.texi qemu-img.texi qmp-commands.hx qom/object.c tests/fdc-test.c tests/libqtest.c tests/qemu-iotests tests/qemu-iotests-quick.sh tests/qom-test.c tests/tmp105-test.c trace-events ui/vnc.c ui/vnc.h vl.c
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Wed Jul 2 01:06:32 PDT 2014
VERSION | 2
block.c | 64 ++++------
block/commit.c | 9 +
block/cow.c | 7 -
block/qed.c | 6 -
block/raw-posix.c | 25 ++++
block/stream.c | 11 -
block/vdi.c | 29 ++++
block/vmdk.c | 6 -
block/vpc.c | 29 ++++
blockdev.c | 126 ++++++++++++++++++++-
configure | 16 ++
docs/qmp/qmp-events.txt | 26 ++--
exec.c | 12 +-
hmp.c | 2
hw/block/dataplane/virtio-blk.c | 12 +-
hw/block/virtio-blk.c | 28 +++-
hw/core/qdev-properties-system.c | 50 --------
hw/core/qdev.c | 26 ++++
hw/input/hid.c | 4
hw/s390x/s390-virtio-bus.c | 12 --
hw/s390x/s390-virtio-bus.h | 1
hw/s390x/virtio-ccw.c | 9 -
hw/s390x/virtio-ccw.h | 1
hw/timer/mc146818rtc.c | 9 +
hw/usb/ccid-card-emulated.c | 29 +---
hw/usb/dev-bluetooth.c | 24 ++--
hw/usb/host-libusb.c | 4
hw/virtio/virtio-pci.c | 9 -
hw/virtio/virtio-pci.h | 1
include/block/block.h | 4
include/block/block_int.h | 4
include/exec/memory.h | 9 +
include/hw/qdev-core.h | 1
include/hw/qdev-properties.h | 5
include/hw/virtio/virtio-blk.h | 19 ---
include/qom/object.h | 54 ++++++++-
memory.c | 231 ++++++++++++++++++++++++++++++++++-----
net/Makefile.objs | 2
net/net.c | 4
qapi/block-core.json | 72 ++++++++++--
qapi/event.json | 8 -
qemu-doc.texi | 16 ++
qemu-img.texi | 16 ++
qmp-commands.hx | 63 ++++++++++
qom/object.c | 147 +++++++++++++++++++-----
tests/fdc-test.c | 2
tests/libqtest.c | 47 ++++++-
tests/qemu-iotests-quick.sh | 12 --
tests/qemu-iotests/040 | 28 +++-
tests/qemu-iotests/082.out | 24 ++++
tests/qemu-iotests/group | 56 ++++-----
tests/qom-test.c | 6 -
tests/tmp105-test.c | 4
trace-events | 2
ui/vnc.c | 162 +++++++++++++--------------
ui/vnc.h | 14 +-
vl.c | 5
58 files changed, 1151 insertions(+), 455 deletions(-)
New commits:
commit 92259b7f434b382fc865d1f65f7d5adeed295749
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jul 1 18:48:01 2014 +0100
Update version for v2.1.0-rc0 release
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/VERSION b/VERSION
index 52be4db..36831c3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.0.50
+2.0.90
commit 015a33bd05b7fd69f400d4e0e4a9925af9292548
Author: Gonglei <arei.gonglei at huawei.com>
Date: Tue Jul 1 20:58:08 2014 +0800
net: add mmsghdr struct check for L2TPV3
The mmsghdr struct is only introduced in Linux 2.6.32; add a
configure check for it and disable L2TPV3 on hosts which are
too old to provide it, rather than simply failing to compile.
Reported-by: chenliang <chenliang88 at huawei.com>
Signed-off-by: Gonglei <arei.gonglei at huawei.com>
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
Message-id: 1404219488-11196-1-git-send-email-arei.gonglei at huawei.com
[PMM: cleaned up commit message and corrected kernel version number]
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/configure b/configure
index ed41eda..7dd43fd 100755
--- a/configure
+++ b/configure
@@ -1712,6 +1712,19 @@ else
fi
##########################################
+# L2TPV3 probe
+
+cat > $TMPC <<EOF
+#include <sys/socket.h>
+int main(void) { return sizeof(struct mmsghdr); }
+EOF
+if compile_prog "" "" ; then
+ l2tpv3=yes
+else
+ l2tpv3=no
+fi
+
+##########################################
# pkg-config probe
if ! has "$pkg_config_exe"; then
@@ -4343,6 +4356,9 @@ fi
if test "$netmap" = "yes" ; then
echo "CONFIG_NETMAP=y" >> $config_host_mak
fi
+if test "$l2tpv3" = "yes" ; then
+ echo "CONFIG_L2TPV3=y" >> $config_host_mak
+fi
if test "$cap_ng" = "yes" ; then
echo "CONFIG_LIBCAP=y" >> $config_host_mak
fi
diff --git a/net/Makefile.objs b/net/Makefile.objs
index a06ba59..ec19cb3 100644
--- a/net/Makefile.objs
+++ b/net/Makefile.objs
@@ -2,7 +2,7 @@ common-obj-y = net.o queue.o checksum.o util.o hub.o
common-obj-y += socket.o
common-obj-y += dump.o
common-obj-y += eth.o
-common-obj-$(CONFIG_LINUX) += l2tpv3.o
+common-obj-$(CONFIG_L2TPV3) += l2tpv3.o
common-obj-$(CONFIG_POSIX) += tap.o vhost-user.o
common-obj-$(CONFIG_LINUX) += tap-linux.o
common-obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/net/net.c b/net/net.c
index 0869c60..6d930ea 100644
--- a/net/net.c
+++ b/net/net.c
@@ -806,7 +806,7 @@ static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
#ifdef CONFIG_VHOST_NET_USED
[NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user,
#endif
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_L2TPV3
[NET_CLIENT_OPTIONS_KIND_L2TPV3] = net_init_l2tpv3,
#endif
};
@@ -845,7 +845,7 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
#ifdef CONFIG_VHOST_NET_USED
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
#endif
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_L2TPV3
case NET_CLIENT_OPTIONS_KIND_L2TPV3:
#endif
break;
commit 596742db3341390dfd386ec434165e0118cfc0f8
Merge: f9119a2 c1129f6
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jul 1 16:16:19 2014 +0100
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20140701-1' into staging
usb bugfixes.
# gpg: Signature made Tue 01 Jul 2014 14:51:19 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel at redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd at kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel at gmail.com>"
* remotes/kraxel/tags/pull-usb-20140701-1:
ccid-card-emulated: use EventNotifier
usb: initialize libusb_device to avoid crash
usb: Fix usb-bt-dongle initialization.
input: fix jumpy mouse cursor with USB mouse emulation
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
commit f9119a25729644300046efda3dd9f50d68fe2106
Merge: 1aa85f4 bea60dd
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jul 1 15:12:05 2014 +0100
Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-20140701-1' into staging
vnc: two bugfixes (by Peter Lieven).
# gpg: Signature made Tue 01 Jul 2014 12:32:19 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel at redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd at kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel at gmail.com>"
* remotes/kraxel/tags/pull-vnc-20140701-1:
ui/vnc: fix potential memory corruption issues
ui/vnc: limit client_cut_text msg payload size
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
commit c1129f6bffb6fc756f53c06bc554a7997b1f4be4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Jun 23 12:30:36 2014 +0200
ccid-card-emulated: use EventNotifier
Shut up Coverity's complaint about unchecked fcntl return values,
and especially make the code simpler and more efficient.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index 7213c89..aa1c37a 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -126,7 +126,7 @@ struct EmulatedState {
QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
QemuMutex handle_apdu_mutex;
QemuCond handle_apdu_cond;
- int pipe[2];
+ EventNotifier notifier;
int quit_apdu_thread;
QemuThread apdu_thread_id;
};
@@ -162,9 +162,7 @@ static void emulated_push_event(EmulatedState *card, EmulEvent *event)
qemu_mutex_lock(&card->event_list_mutex);
QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
qemu_mutex_unlock(&card->event_list_mutex);
- if (write(card->pipe[1], card, 1) != 1) {
- DPRINTF(card, 1, "write to pipe failed\n");
- }
+ event_notifier_set(&card->notifier);
}
static void emulated_push_type(EmulatedState *card, uint32_t type)
@@ -358,16 +356,12 @@ static void *event_thread(void *arg)
return NULL;
}
-static void pipe_read(void *opaque)
+static void card_event_handler(EventNotifier *notifier)
{
- EmulatedState *card = opaque;
+ EmulatedState *card = container_of(notifier, EmulatedState, notifier);
EmulEvent *event, *next;
- char dummy;
- int len;
- do {
- len = read(card->pipe[0], &dummy, sizeof(dummy));
- } while (len == sizeof(dummy));
+ event_notifier_test_and_clear(&card->notifier);
qemu_mutex_lock(&card->event_list_mutex);
QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
@@ -404,16 +398,13 @@ static void pipe_read(void *opaque)
qemu_mutex_unlock(&card->event_list_mutex);
}
-static int init_pipe_signaling(EmulatedState *card)
+static int init_event_notifier(EmulatedState *card)
{
- if (pipe(card->pipe) < 0) {
- DPRINTF(card, 2, "pipe creation failed\n");
+ if (event_notifier_init(&card->notifier, false) < 0) {
+ DPRINTF(card, 2, "event notifier creation failed\n");
return -1;
}
- fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
- fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
- fcntl(card->pipe[0], F_SETOWN, getpid());
- qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
+ event_notifier_set_handler(&card->notifier, card_event_handler);
return 0;
}
@@ -500,7 +491,7 @@ static int emulated_initfn(CCIDCardState *base)
qemu_cond_init(&card->handle_apdu_cond);
card->reader = NULL;
card->quit_apdu_thread = 0;
- if (init_pipe_signaling(card) < 0) {
+ if (init_event_notifier(card) < 0) {
return -1;
}
commit 1aa85f46b336b6b07d3a03e9807578b0bc081b7b
Merge: 8593efa bc78cff
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jul 1 14:21:50 2014 +0100
Merge remote-tracking branch 'remotes/stefanha/tags/tracing-pull-request' into staging
Tracing pull request
# gpg: Signature made Tue 01 Jul 2014 09:56:27 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha at redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha at gmail.com>"
* remotes/stefanha/tags/tracing-pull-request:
trace: add qemu_system_powerdown_request and qemu_system_shutdown_request trace events
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
commit 8593efa4fb33b8c1f3e3af04f771d8376ae61092
Merge: c26f3a0 13d8cc5
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jul 1 13:13:04 2014 +0100
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
Block pull request
# gpg: Signature made Tue 01 Jul 2014 09:47:15 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha at redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha at gmail.com>"
* remotes/stefanha/tags/block-pull-request: (23 commits)
block: add backing-file option to block-stream
block: extend block-commit to accept a string for the backing file
block: add helper function to determine if a BDS is in a chain
block: add QAPI command to allow live backing file change
qapi: Change back sector-count to sectors-count in quorum QAPI events.
block/cow: Avoid use of uninitialized cow_bs in error path
block: simplify bdrv_find_base() and bdrv_find_overlay()
block: make 'top' argument to block-commit optional
iotests: Add more tests to quick group
iotests: Add qemu tests to quick group
iotests: Simplify qemu-iotests-quick.sh
qemu-img create: add 'nocow' option
virtio-blk: remove need for explicit x-data-plane=on option
qdev: drop iothread property type
virtio-blk: replace x-iothread with iothread link property
virtio-blk: move qdev properties into virtio-blk.c
virtio: fix virtio-blk child refcount in transports
virtio-blk: drop virtio_blk_set_conf()
virtio-blk: use aliases instead of duplicate qdev properties
qdev: add qdev_alias_all_properties()
...
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
commit bea60dd7679364493a0d7f5b54316c767cf894ef
Author: Peter Lieven <pl at kamp.de>
Date: Mon Jun 30 10:57:51 2014 +0200
ui/vnc: fix potential memory corruption issues
this patch makes the VNC server work correctly if the
server surface and the guest surface have different sizes.
Basically the server surface is adjusted to not exceed VNC_MAX_WIDTH
x VNC_MAX_HEIGHT and additionally the width is rounded up to multiple of
VNC_DIRTY_PIXELS_PER_BIT.
If we have a resolution whose width is not dividable by VNC_DIRTY_PIXELS_PER_BIT
we now get a small black bar on the right of the screen.
If the surface is too big to fit the limits only the upper left area is shown.
On top of that this fixes 2 memory corruption issues:
The first was actually discovered during playing
around with a Windows 7 vServer. During resolution
change in Windows 7 it happens sometimes that Windows
changes to an intermediate resolution where
server_stride % cmp_bytes != 0 (in vnc_refresh_server_surface).
This happens only if width % VNC_DIRTY_PIXELS_PER_BIT != 0.
The second is a theoretical issue, but is maybe exploitable
by the guest. If for some reason the guest surface size is bigger
than VNC_MAX_WIDTH x VNC_MAX_HEIGHT we end up in severe corruption since
this limit is nowhere enforced.
Signed-off-by: Peter Lieven <pl at kamp.de>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/vnc.c b/ui/vnc.c
index 19ce988..548588a 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -432,14 +432,10 @@ static void framebuffer_update_request(VncState *vs, int incremental,
static void vnc_refresh(DisplayChangeListener *dcl);
static int vnc_refresh_server_surface(VncDisplay *vd);
-static void vnc_dpy_update(DisplayChangeListener *dcl,
- int x, int y, int w, int h)
-{
- VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
- struct VncSurface *s = &vd->guest;
- int width = surface_width(vd->ds);
- int height = surface_height(vd->ds);
-
+static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
+ VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
+ int width, int height,
+ int x, int y, int w, int h) {
/* this is needed this to ensure we updated all affected
* blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
w += (x % VNC_DIRTY_PIXELS_PER_BIT);
@@ -451,11 +447,22 @@ static void vnc_dpy_update(DisplayChangeListener *dcl,
h = MIN(y + h, height);
for (; y < h; y++) {
- bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
+ bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
}
}
+static void vnc_dpy_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
+ struct VncSurface *s = &vd->guest;
+ int width = pixman_image_get_width(vd->server);
+ int height = pixman_image_get_height(vd->server);
+
+ vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
+}
+
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
int32_t encoding)
{
@@ -517,17 +524,15 @@ void buffer_advance(Buffer *buf, size_t len)
static void vnc_desktop_resize(VncState *vs)
{
- DisplaySurface *ds = vs->vd->ds;
-
if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
return;
}
- if (vs->client_width == surface_width(ds) &&
- vs->client_height == surface_height(ds)) {
+ if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
+ vs->client_height == pixman_image_get_height(vs->vd->server)) {
return;
}
- vs->client_width = surface_width(ds);
- vs->client_height = surface_height(ds);
+ vs->client_width = pixman_image_get_width(vs->vd->server);
+ vs->client_height = pixman_image_get_height(vs->vd->server);
vnc_lock_output(vs);
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
@@ -571,31 +576,24 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
ptr += x * VNC_SERVER_FB_BYTES;
return ptr;
}
-/* this sets only the visible pixels of a dirty bitmap */
-#define VNC_SET_VISIBLE_PIXELS_DIRTY(bitmap, w, h) {\
- int y;\
- memset(bitmap, 0x00, sizeof(bitmap));\
- for (y = 0; y < h; y++) {\
- bitmap_set(bitmap[y], 0,\
- DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));\
- } \
- }
static void vnc_dpy_switch(DisplayChangeListener *dcl,
DisplaySurface *surface)
{
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
VncState *vs;
+ int width, height;
vnc_abort_display_jobs(vd);
/* server surface */
qemu_pixman_image_unref(vd->server);
vd->ds = surface;
+ width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
+ VNC_DIRTY_PIXELS_PER_BIT));
+ height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
- surface_width(vd->ds),
- surface_height(vd->ds),
- NULL, 0);
+ width, height, NULL, 0);
/* guest surface */
#if 0 /* FIXME */
@@ -605,9 +603,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
qemu_pixman_image_unref(vd->guest.fb);
vd->guest.fb = pixman_image_ref(surface->image);
vd->guest.format = surface->format;
- VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty,
- surface_width(vd->ds),
- surface_height(vd->ds));
+ memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
+ vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
+ width, height);
QTAILQ_FOREACH(vs, &vd->clients, next) {
vnc_colordepth(vs);
@@ -615,9 +613,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
if (vs->vd->cursor) {
vnc_cursor_define(vs);
}
- VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty,
- surface_width(vd->ds),
- surface_height(vd->ds));
+ memset(vs->dirty, 0x00, sizeof(vs->dirty));
+ vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
+ width, height);
}
}
@@ -911,8 +909,8 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
*/
job = vnc_job_new(vs);
- height = MIN(pixman_image_get_height(vd->server), vs->client_height);
- width = MIN(pixman_image_get_width(vd->server), vs->client_width);
+ height = pixman_image_get_height(vd->server);
+ width = pixman_image_get_width(vd->server);
y = 0;
for (;;) {
@@ -1501,8 +1499,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, absolute, 0,
- surface_width(vs->vd->ds),
- surface_height(vs->vd->ds),
+ pixman_image_get_width(vs->vd->server),
+ pixman_image_get_height(vs->vd->server),
VNC_ENCODING_POINTER_TYPE_CHANGE);
vnc_unlock_output(vs);
vnc_flush(vs);
@@ -1520,8 +1518,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
[INPUT_BUTTON_WHEEL_DOWN] = 0x10,
};
QemuConsole *con = vs->vd->dcl.con;
- int width = surface_width(vs->vd->ds);
- int height = surface_height(vs->vd->ds);
+ int width = pixman_image_get_width(vs->vd->server);
+ int height = pixman_image_get_height(vs->vd->server);
if (vs->last_bmask != button_mask) {
qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
@@ -1869,29 +1867,18 @@ static void ext_key_event(VncState *vs, int down,
}
static void framebuffer_update_request(VncState *vs, int incremental,
- int x_position, int y_position,
- int w, int h)
+ int x, int y, int w, int h)
{
- int i;
- const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT;
- const size_t height = surface_height(vs->vd->ds);
-
- if (y_position > height) {
- y_position = height;
- }
- if (y_position + h >= height) {
- h = height - y_position;
- }
+ int width = pixman_image_get_width(vs->vd->server);
+ int height = pixman_image_get_height(vs->vd->server);
vs->need_update = 1;
- if (!incremental) {
- vs->force_update = 1;
- for (i = 0; i < h; i++) {
- bitmap_set(vs->dirty[y_position + i], 0, width);
- bitmap_clear(vs->dirty[y_position + i], width,
- VNC_DIRTY_BITS - width);
- }
+
+ if (incremental) {
+ return;
}
+
+ vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
}
static void send_ext_key_event_ack(VncState *vs)
@@ -1901,8 +1888,8 @@ static void send_ext_key_event_ack(VncState *vs)
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, 0, 0,
- surface_width(vs->vd->ds),
- surface_height(vs->vd->ds),
+ pixman_image_get_width(vs->vd->server),
+ pixman_image_get_height(vs->vd->server),
VNC_ENCODING_EXT_KEY_EVENT);
vnc_unlock_output(vs);
vnc_flush(vs);
@@ -1915,8 +1902,8 @@ static void send_ext_audio_ack(VncState *vs)
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, 0, 0,
- surface_width(vs->vd->ds),
- surface_height(vs->vd->ds),
+ pixman_image_get_width(vs->vd->server),
+ pixman_image_get_height(vs->vd->server),
VNC_ENCODING_AUDIO);
vnc_unlock_output(vs);
vnc_flush(vs);
@@ -2094,8 +2081,8 @@ static void vnc_colordepth(VncState *vs)
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); /* number of rects */
vnc_framebuffer_update(vs, 0, 0,
- surface_width(vs->vd->ds),
- surface_height(vs->vd->ds),
+ pixman_image_get_width(vs->vd->server),
+ pixman_image_get_height(vs->vd->server),
VNC_ENCODING_WMVi);
pixel_format_message(vs);
vnc_unlock_output(vs);
@@ -2317,8 +2304,8 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
}
vnc_set_share_mode(vs, mode);
- vs->client_width = surface_width(vs->vd->ds);
- vs->client_height = surface_height(vs->vd->ds);
+ vs->client_width = pixman_image_get_width(vs->vd->server);
+ vs->client_height = pixman_image_get_height(vs->vd->server);
vnc_write_u16(vs, vs->client_width);
vnc_write_u16(vs, vs->client_height);
@@ -2685,12 +2672,12 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
static int vnc_refresh_server_surface(VncDisplay *vd)
{
- int width = pixman_image_get_width(vd->guest.fb);
- int height = pixman_image_get_height(vd->guest.fb);
- int y;
+ int width = MIN(pixman_image_get_width(vd->guest.fb),
+ pixman_image_get_width(vd->server));
+ int height = MIN(pixman_image_get_height(vd->guest.fb),
+ pixman_image_get_height(vd->server));
+ int cmp_bytes, server_stride, min_stride, guest_stride, y = 0;
uint8_t *guest_row0 = NULL, *server_row0;
- int guest_stride = 0, server_stride;
- int cmp_bytes;
VncState *vs;
int has_dirty = 0;
pixman_image_t *tmpbuf = NULL;
@@ -2707,10 +2694,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
* Check and copy modified bits from guest to server surface.
* Update server dirty map.
*/
- cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES;
- if (cmp_bytes > vnc_server_fb_stride(vd)) {
- cmp_bytes = vnc_server_fb_stride(vd);
- }
+ server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
+ server_stride = guest_stride = pixman_image_get_stride(vd->server);
+ cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
+ server_stride);
if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
int width = pixman_image_get_width(vd->server);
tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
@@ -2718,10 +2705,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
guest_stride = pixman_image_get_stride(vd->guest.fb);
}
- server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
- server_stride = pixman_image_get_stride(vd->server);
+ min_stride = MIN(server_stride, guest_stride);
- y = 0;
for (;;) {
int x;
uint8_t *guest_ptr, *server_ptr;
@@ -2747,13 +2732,17 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
+ int _cmp_bytes = cmp_bytes;
if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
continue;
}
- if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) {
+ if ((x + 1) * cmp_bytes > min_stride) {
+ _cmp_bytes = min_stride - x * cmp_bytes;
+ }
+ if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
continue;
}
- memcpy(server_ptr, guest_ptr, cmp_bytes);
+ memcpy(server_ptr, guest_ptr, _cmp_bytes);
if (!vd->non_adaptive) {
vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
y, &tv);
diff --git a/ui/vnc.h b/ui/vnc.h
index 07af9f7..8f582fd 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -77,14 +77,15 @@ typedef void VncSendHextileTile(VncState *vs,
void *last_fg,
int *has_bg, int *has_fg);
-/* VNC_MAX_WIDTH must be a multiple of 16. */
-#define VNC_MAX_WIDTH 2560
-#define VNC_MAX_HEIGHT 2048
-
/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented
- * by one bit in the dirty bitmap */
+ * by one bit in the dirty bitmap, should be a power of 2 */
#define VNC_DIRTY_PIXELS_PER_BIT 16
+/* VNC_MAX_WIDTH must be a multiple of VNC_DIRTY_PIXELS_PER_BIT. */
+
+#define VNC_MAX_WIDTH ROUND_UP(2560, VNC_DIRTY_PIXELS_PER_BIT)
+#define VNC_MAX_HEIGHT 2048
+
/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
@@ -126,7 +127,8 @@ typedef struct VncRectStat VncRectStat;
struct VncSurface
{
struct timeval last_freq_check;
- DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16);
+ DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
+ VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT);
VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
pixman_image_t *fb;
pixman_format_code_t format;
commit f9a70e79391f6d7c2a912d785239ee8effc1922d
Author: Peter Lieven <pl at kamp.de>
Date: Mon Jun 30 10:07:54 2014 +0200
ui/vnc: limit client_cut_text msg payload size
currently a malicious client could define a payload
size of 2^32 - 1 bytes and send up to that size of
data to the vnc server. The server would allocated
that amount of memory which could easily create an
out of memory condition.
This patch limits the payload size to 1MB max.
Please note that client_cut_text messages are currently
silently ignored.
Signed-off-by: Peter Lieven <pl at kamp.de>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/ui/vnc.c b/ui/vnc.c
index 14a86c3..19ce988 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2165,13 +2165,20 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
break;
case VNC_MSG_CLIENT_CUT_TEXT:
- if (len == 1)
+ if (len == 1) {
return 8;
-
+ }
if (len == 8) {
uint32_t dlen = read_u32(data, 4);
- if (dlen > 0)
+ if (dlen > (1 << 20)) {
+ error_report("vnc: client_cut_text msg payload has %u bytes"
+ " which exceeds our limit of 1MB.", dlen);
+ vnc_client_error(vs);
+ break;
+ }
+ if (dlen > 0) {
return 8 + dlen;
+ }
}
client_cut_text(vs, read_u32(data, 4), data + 8);
commit 3ce21445387c64032a21ae73c995195307a28a36
Author: Jincheng Miao <jmiao at redhat.com>
Date: Fri Jun 20 14:12:52 2014 +0800
usb: initialize libusb_device to avoid crash
If libusb_get_device_list() fails, the uninitialized local variable
libusb_device would be passed to libusb_free_device_list(), that
will cause a crash, like:
(gdb) bt
#0 0x00007fbbb4bafc10 in pthread_mutex_lock () from /lib64/libpthread.so.0
#1 0x00007fbbb233e653 in libusb_unref_device (dev=0x6275682d627375)
at core.c:902
#2 0x00007fbbb233e739 in libusb_free_device_list (list=0x7fbbb6e8436e,
unref_devices=<optimized out>) at core.c:653
#3 0x00007fbbb6cd80a4 in usb_host_auto_check (unused=unused at entry=0x0)
at hw/usb/host-libusb.c:1446
#4 0x00007fbbb6cd8525 in usb_host_initfn (udev=0x7fbbbd3c5670)
at hw/usb/host-libusb.c:912
#5 0x00007fbbb6cc123b in usb_device_init (dev=0x7fbbbd3c5670)
at hw/usb/bus.c:106
...
So initialize libusb_device at the begin time.
Signed-off-by: Jincheng Miao <jmiao at redhat.com>
Reviewed-by: Gonglei <arei.gonglei at huawei.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 33b5b9f..c189147 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1522,7 +1522,7 @@ static void usb_host_auto_check(void *unused)
{
struct USBHostDevice *s;
struct USBAutoFilter *f;
- libusb_device **devs;
+ libusb_device **devs = NULL;
struct libusb_device_descriptor ddesc;
int unconnected = 0;
int i, n;
@@ -1623,7 +1623,7 @@ static void usb_host_auto_check(void *unused)
void usb_host_info(Monitor *mon, const QDict *qdict)
{
- libusb_device **devs;
+ libusb_device **devs = NULL;
struct libusb_device_descriptor ddesc;
char port[16];
int i, n;
commit c340a284f382a5f40774521f41b4bade76ddfa58
Author: Hani Benhabiles <kroosec at gmail.com>
Date: Wed Jun 18 00:23:34 2014 +0100
usb: Fix usb-bt-dongle initialization.
Due to an incomplete initialization, adding a usb-bt-dongle device through HMP
or QMP will cause a segmentation fault.
Signed-off-by: Hani Benhabiles <hani at linux.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index a9661d2..a76e581 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -19,6 +19,7 @@
*/
#include "qemu-common.h"
+#include "qemu/error-report.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "sysemu/bt.h"
@@ -506,6 +507,14 @@ static int usb_bt_initfn(USBDevice *dev)
usb_desc_create_serial(dev);
usb_desc_init(dev);
+ s->dev.opaque = s;
+ if (!s->hci) {
+ s->hci = bt_new_hci(qemu_find_bt_vlan(0));
+ }
+ s->hci->opaque = s;
+ s->hci->evt_recv = usb_bt_out_hci_packet_event;
+ s->hci->acl_recv = usb_bt_out_hci_packet_acl;
+ usb_bt_handle_reset(&s->dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP);
return 0;
@@ -516,6 +525,7 @@ static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline)
USBDevice *dev;
struct USBBtState *s;
HCIInfo *hci;
+ const char *name = "usb-bt-dongle";
if (*cmdline) {
hci = hci_init(cmdline);
@@ -525,19 +535,17 @@ static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline)
if (!hci)
return NULL;
- dev = usb_create_simple(bus, "usb-bt-dongle");
+ dev = usb_create(bus, name);
if (!dev) {
+ error_report("Failed to create USB device '%s'", name);
return NULL;
}
s = DO_UPCAST(struct USBBtState, dev, dev);
- s->dev.opaque = s;
-
s->hci = hci;
- s->hci->opaque = s;
- s->hci->evt_recv = usb_bt_out_hci_packet_event;
- s->hci->acl_recv = usb_bt_out_hci_packet_acl;
-
- usb_bt_handle_reset(&s->dev);
+ if (qdev_init(&dev->qdev) < 0) {
+ error_report("Failed to initialize USB device '%s'", name);
+ return NULL;
+ }
return dev;
}
commit 35e83d10f230616888cc4258ceddf06a612dde8a
Author: Christian Burger <christian at krikkel.de>
Date: Sat Jun 14 20:19:41 2014 +0100
input: fix jumpy mouse cursor with USB mouse emulation
Guest mouse pointer was jumpy, when moving host mouse in the vertical direction (see bug #1327800).
Signed-off-by: Christian Burger <christian at krikkel.de>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 9656e90..148c003 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -124,7 +124,7 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
if (evt->rel->axis == INPUT_AXIS_X) {
e->xdx += evt->rel->value;
} else if (evt->rel->axis == INPUT_AXIS_Y) {
- e->ydy -= evt->rel->value;
+ e->ydy += evt->rel->value;
}
break;
@@ -191,7 +191,7 @@ static void hid_pointer_sync(DeviceState *dev)
if (hs->kind == HID_MOUSE) {
prev->xdx += curr->xdx;
curr->xdx = 0;
- prev->ydy -= curr->ydy;
+ prev->ydy += curr->ydy;
curr->ydy = 0;
} else {
prev->xdx = curr->xdx;
commit c26f3a0a6dfe5ef2973ddfab03b1ceff641a7ebe
Merge: b3959ef 352e8da
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jul 1 11:55:48 2014 +0100
Merge remote-tracking branch 'remotes/bonzini/memory' into staging
* remotes/bonzini/memory:
qdev: correctly send DEVICE_DELETED for recursively-deleted devices
memory: do not give a name to the internal exec.c regions
memory: MemoryRegion: Add size property
memory: MemoryRegion: Add may-overlap and priority props
memory: MemoryRegion: Add container and addr props
memory: MemoryRegion: replace owner field with QOM parent
memory: MemoryRegion: QOMify
memory: MemoryRegion: use /machine as default owner
libqtest: escape strings in QMP commands, fix leak
qom: object: Ignore refs/unrefs of NULL
qom: object: remove parent pointer when unparenting
mc146818rtc: add "rtc-time" link to "/machine/rtc"
qom: allow creating an alias of a child<> property
qom: add a generic mechanism to resolve paths
qom: add object_property_add_alias()
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
commit bc78cff9757782501db15d39828e6af4186fe331
Author: Yang Zhiyong <yangzy.fnst at cn.fujitsu.com>
Date: Sun Jun 22 02:43:03 2014 +0800
trace: add qemu_system_powerdown_request and qemu_system_shutdown_request trace events
We have the experience that the guest doesn't stop successfully
though it was instructed to shut down.
The root cause may be not in QEMU mostly. However, QEMU is often
suspected at the beginning just because the issue occurred in
virtualization environment.
Therefore, we need to affirm that QEMU received the shutdown
request and raised ACPI irq from "virsh shutdown" command,
virt-manger or stopping QEMU process to the VM .
So that we can affirm the problems was belonged to the Guset OS
rather than the QEMU itself.
When we stop guests by "virsh shutdown" command or virt-manger,
or stopping QEMU process, qemu_system_powerdown_request() or
qemu_system_shutdown_request() is called. Then the below functions
in main_loop_should_exit() of Vl.c are called roughly in the
following order.
if (qemu_powerdown_requested())
qemu_system_powerdown()
monitor_protocol_event(QEVENT_POWERDOWN, NULL)
OR
if(qemu_shutdown_requested()}
monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
The tracepoint of monitor_protocol_event() already exists, but no
tracepoints are defined for qemu_system_powerdown_request() and
qemu_system_shutdown_request(). So this patch adds two tracepoints for
the two functions. We believe that it will become much easier to
isolate the problem mentioned above by these tracepoints.
Signed-off-by: Yang Zhiyong <yangzy.fnst at cn.fujitsu.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/trace-events b/trace-events
index d071b97..11a17a8 100644
--- a/trace-events
+++ b/trace-events
@@ -511,6 +511,8 @@ g_malloc(size_t size, void *ptr) "size %zu ptr %p"
g_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p"
g_free(void *ptr) "ptr %p"
system_wakeup_request(int reason) "reason=%d"
+qemu_system_shutdown_request(void) ""
+qemu_system_powerdown_request(void) ""
# block/qcow2.c
qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d"
diff --git a/vl.c b/vl.c
index 41ddcd2..34f8726 100644
--- a/vl.c
+++ b/vl.c
@@ -1921,6 +1921,7 @@ void qemu_system_killed(int signal, pid_t pid)
void qemu_system_shutdown_request(void)
{
+ trace_qemu_system_shutdown_request();
shutdown_requested = 1;
qemu_notify_event();
}
@@ -1933,6 +1934,7 @@ static void qemu_system_powerdown(void)
void qemu_system_powerdown_request(void)
{
+ trace_qemu_system_powerdown_request();
powerdown_requested = 1;
qemu_notify_event();
}
commit 13d8cc515dfcf5574077f964332d34890c0101d0
Author: Jeff Cody <jcody at redhat.com>
Date: Wed Jun 25 15:40:11 2014 -0400
block: add backing-file option to block-stream
On some image chains, QEMU may not always be able to resolve the
filenames properly, when updating the backing file of an image
after a block job.
For instance, certain relative pathnames may fail, or drives may
have been specified originally by file descriptor (e.g. /dev/fd/???),
or a relative protocol pathname may have been used.
In these instances, QEMU may lack the information to be able to make
the correct choice, but the user or management layer most likely does
have that knowledge.
With this extension to the block-stream api, the user is able to change
the backing file of the active layer as part of the block-stream
operation.
This allows the change to be 'safe', in the sense that if the attempt
to write the active image metadata fails, then the block-stream
operation returns failure, without disrupting the guest.
If a backing file string is not specified in the command, the backing
file string to use is determined in the same manner as it was
previously.
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block/stream.c b/block/stream.c
index 0433409..34de8ba 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -32,7 +32,7 @@ typedef struct StreamBlockJob {
RateLimit limit;
BlockDriverState *base;
BlockdevOnError on_error;
- char backing_file_id[1024];
+ char *backing_file_str;
} StreamBlockJob;
static int coroutine_fn stream_populate(BlockDriverState *bs,
@@ -186,7 +186,7 @@ wait:
if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
const char *base_id = NULL, *base_fmt = NULL;
if (base) {
- base_id = s->backing_file_id;
+ base_id = s->backing_file_str;
if (base->drv) {
base_fmt = base->drv->format_name;
}
@@ -196,6 +196,7 @@ wait:
}
qemu_vfree(buf);
+ g_free(s->backing_file_str);
block_job_completed(&s->common, ret);
}
@@ -217,7 +218,7 @@ static const BlockJobDriver stream_job_driver = {
};
void stream_start(BlockDriverState *bs, BlockDriverState *base,
- const char *base_id, int64_t speed,
+ const char *backing_file_str, int64_t speed,
BlockdevOnError on_error,
BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
@@ -237,9 +238,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
}
s->base = base;
- if (base_id) {
- pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
- }
+ s->backing_file_str = g_strdup(backing_file_str);
s->on_error = on_error;
s->common.co = qemu_coroutine_create(stream_run);
diff --git a/blockdev.c b/blockdev.c
index 48315e8..48bd9a3 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1871,14 +1871,17 @@ static void block_job_cb(void *opaque, int ret)
bdrv_put_ref_bh_schedule(bs);
}
-void qmp_block_stream(const char *device, bool has_base,
- const char *base, bool has_speed, int64_t speed,
+void qmp_block_stream(const char *device,
+ bool has_base, const char *base,
+ bool has_backing_file, const char *backing_file,
+ bool has_speed, int64_t speed,
bool has_on_error, BlockdevOnError on_error,
Error **errp)
{
BlockDriverState *bs;
BlockDriverState *base_bs = NULL;
Error *local_err = NULL;
+ const char *base_name = NULL;
if (!has_on_error) {
on_error = BLOCKDEV_ON_ERROR_REPORT;
@@ -1894,15 +1897,27 @@ void qmp_block_stream(const char *device, bool has_base,
return;
}
- if (base) {
+ if (has_base) {
base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) {
error_set(errp, QERR_BASE_NOT_FOUND, base);
return;
}
+ base_name = base;
}
- stream_start(bs, base_bs, base, has_speed ? speed : 0,
+ /* if we are streaming the entire chain, the result will have no backing
+ * file, and specifying one is therefore an error */
+ if (base_bs == NULL && has_backing_file) {
+ error_setg(errp, "backing file specified, but streaming the "
+ "entire chain");
+ return;
+ }
+
+ /* backing_file string overrides base bs filename */
+ base_name = has_backing_file ? backing_file : base_name;
+
+ stream_start(bs, base_bs, base_name, has_speed ? speed : 0,
on_error, block_job_cb, bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hmp.c b/hmp.c
index 6429e6b..4d1838e 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1176,7 +1176,7 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
const char *base = qdict_get_try_str(qdict, "base");
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
- qmp_block_stream(device, base != NULL, base,
+ qmp_block_stream(device, base != NULL, base, false, NULL,
qdict_haskey(qdict, "speed"), speed,
true, BLOCKDEV_ON_ERROR_REPORT, &error);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5b4d75f..e378653 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -922,6 +922,21 @@
#
# @base: #optional the common backing file name
#
+# @backing-file: #optional The backing file string to write into the active
+# layer. This filename is not validated.
+#
+# If a pathname string is such that it cannot be
+# resolved by QEMU, that means that subsequent QMP or
+# HMP commands must use node-names for the image in
+# question, as filename lookup methods will fail.
+#
+# If not specified, QEMU will automatically determine
+# the backing file string to use, or error out if there
+# is no obvious choice. Care should be taken when
+# specifying the string, to specify a valid filename or
+# protocol.
+# (Since 2.1)
+#
# @speed: #optional the maximum speed, in bytes per second
#
# @on-error: #optional the action to take on an error (default report).
@@ -934,8 +949,8 @@
# Since: 1.1
##
{ 'command': 'block-stream',
- 'data': { 'device': 'str', '*base': 'str', '*speed': 'int',
- '*on-error': 'BlockdevOnError' } }
+ 'data': { 'device': 'str', '*base': 'str', '*backing-file': 'str',
+ '*speed': 'int', '*on-error': 'BlockdevOnError' } }
##
# @block-job-set-speed:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a3f932c..4be4765 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -979,7 +979,7 @@ EQMP
{
.name = "block-stream",
- .args_type = "device:B,base:s?,speed:o?,on-error:s?",
+ .args_type = "device:B,base:s?,speed:o?,backing-file:s?,on-error:s?",
.mhandler.cmd_new = qmp_marshal_input_block_stream,
},
commit 54e269009099cdc9483be115f1e12d56ad459c5e
Author: Jeff Cody <jcody at redhat.com>
Date: Wed Jun 25 15:40:10 2014 -0400
block: extend block-commit to accept a string for the backing file
On some image chains, QEMU may not always be able to resolve the
filenames properly, when updating the backing file of an image
after a block commit.
For instance, certain relative pathnames may fail, or drives may
have been specified originally by file descriptor (e.g. /dev/fd/???),
or a relative protocol pathname may have been used.
In these instances, QEMU may lack the information to be able to make
the correct choice, but the user or management layer most likely does
have that knowledge.
With this extension to the block-commit api, the user is able to change
the backing file of the overlay image as part of the block-commit
operation.
This allows the change to be 'safe', in the sense that if the attempt
to write the overlay image metadata fails, then the block-commit
operation returns failure, without disrupting the guest.
If the commit top is the active layer, then specifying the backing
file string will be treated as an error (there is no overlay image
to modify in that case).
If a backing file string is not specified in the command, the backing
file string to use is determined in the same manner as it was
previously.
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Jeff Cody <jcody at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block.c b/block.c
index f45e63c..f80e2b2 100644
--- a/block.c
+++ b/block.c
@@ -2555,12 +2555,15 @@ typedef struct BlkIntermediateStates {
*
* base <- active
*
+ * If backing_file_str is non-NULL, it will be used when modifying top's
+ * overlay image metadata.
+ *
* Error conditions:
* if active == top, that is considered an error
*
*/
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
- BlockDriverState *base)
+ BlockDriverState *base, const char *backing_file_str)
{
BlockDriverState *intermediate;
BlockDriverState *base_bs = NULL;
@@ -2612,7 +2615,8 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
}
/* success - we can delete the intermediate states, and link top->base */
- ret = bdrv_change_backing_file(new_top_bs, base_bs->filename,
+ backing_file_str = backing_file_str ? backing_file_str : base_bs->filename;
+ ret = bdrv_change_backing_file(new_top_bs, backing_file_str,
base_bs->drv ? base_bs->drv->format_name : "");
if (ret) {
goto exit;
diff --git a/block/commit.c b/block/commit.c
index 5c09f44..91517d3 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -37,6 +37,7 @@ typedef struct CommitBlockJob {
BlockdevOnError on_error;
int base_flags;
int orig_overlay_flags;
+ char *backing_file_str;
} CommitBlockJob;
static int coroutine_fn commit_populate(BlockDriverState *bs,
@@ -141,7 +142,7 @@ wait:
if (!block_job_is_cancelled(&s->common) && sector_num == end) {
/* success */
- ret = bdrv_drop_intermediate(active, top, base);
+ ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
}
exit_free_buf:
@@ -158,7 +159,7 @@ exit_restore_reopen:
if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
}
-
+ g_free(s->backing_file_str);
block_job_completed(&s->common, ret);
}
@@ -182,7 +183,7 @@ static const BlockJobDriver commit_job_driver = {
void commit_start(BlockDriverState *bs, BlockDriverState *base,
BlockDriverState *top, int64_t speed,
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
- void *opaque, Error **errp)
+ void *opaque, const char *backing_file_str, Error **errp)
{
CommitBlockJob *s;
BlockReopenQueue *reopen_queue = NULL;
@@ -244,6 +245,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
s->base_flags = orig_base_flags;
s->orig_overlay_flags = orig_overlay_flags;
+ s->backing_file_str = g_strdup(backing_file_str);
+
s->on_error = on_error;
s->common.co = qemu_coroutine_create(commit_run);
diff --git a/blockdev.c b/blockdev.c
index 57373d3..48315e8 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1915,6 +1915,7 @@ void qmp_block_stream(const char *device, bool has_base,
void qmp_block_commit(const char *device,
bool has_base, const char *base,
bool has_top, const char *top,
+ bool has_backing_file, const char *backing_file,
bool has_speed, int64_t speed,
Error **errp)
{
@@ -1980,11 +1981,16 @@ void qmp_block_commit(const char *device,
}
if (top_bs == bs) {
+ if (has_backing_file) {
+ error_setg(errp, "'backing-file' specified,"
+ " but 'top' is the active layer");
+ return;
+ }
commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
bs, &local_err);
} else {
commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs,
- &local_err);
+ has_backing_file ? backing_file : NULL, &local_err);
}
if (local_err != NULL) {
error_propagate(errp, local_err);
diff --git a/include/block/block.h b/include/block/block.h
index 29c9e50..baecc26 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -285,7 +285,8 @@ int bdrv_change_backing_file(BlockDriverState *bs,
const char *backing_file, const char *backing_fmt);
void bdrv_register(BlockDriver *bdrv);
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
- BlockDriverState *base);
+ BlockDriverState *base,
+ const char *backing_file_str);
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
BlockDriverState *bs);
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index eaf6e31..8f8e65e 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -463,13 +463,14 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
* @on_error: The action to take upon error.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
+ * @backing_file_str: String to use as the backing file in @top's overlay
* @errp: Error object.
*
*/
void commit_start(BlockDriverState *bs, BlockDriverState *base,
BlockDriverState *top, int64_t speed,
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
- void *opaque, Error **errp);
+ void *opaque, const char *backing_file_str, Error **errp);
/**
* commit_active_start:
* @bs: Active block device to be committed.
diff --git a/qapi/block-core.json b/qapi/block-core.json
index aa12527..5b4d75f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -720,6 +720,23 @@
# which contains the topmost data to be committed down. If
# not specified, this is the active layer.
#
+# @backing-file: #optional The backing file string to write into the overlay
+# image of 'top'. If 'top' is the active layer,
+# specifying a backing file string is an error. This
+# filename is not validated.
+#
+# If a pathname string is such that it cannot be
+# resolved by QEMU, that means that subsequent QMP or
+# HMP commands must use node-names for the image in
+# question, as filename lookup methods will fail.
+#
+# If not specified, QEMU will automatically determine
+# the backing file string to use, or error out if
+# there is no obvious choice. Care should be taken
+# when specifying the string, to specify a valid
+# filename or protocol.
+# (Since 2.1)
+#
# If top == base, that is an error.
# If top == active, the job will not be completed by itself,
# user needs to complete the job with the block-job-complete
@@ -732,7 +749,6 @@
# size of the smaller top, you can safely truncate it
# yourself once the commit operation successfully completes.
#
-#
# @speed: #optional the maximum speed, in bytes per second
#
# Returns: Nothing on success
@@ -747,7 +763,7 @@
##
{ 'command': 'block-commit',
'data': { 'device': 'str', '*base': 'str', '*top': 'str',
- '*speed': 'int' } }
+ '*backing-file': 'str', '*speed': 'int' } }
##
# @drive-backup
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8534948..a3f932c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -985,7 +985,7 @@ EQMP
{
.name = "block-commit",
- .args_type = "device:B,base:s?,top:s?,speed:o?",
+ .args_type = "device:B,base:s?,top:s?,backing-file:s?,speed:o?",
.mhandler.cmd_new = qmp_marshal_input_block_commit,
},
@@ -1006,6 +1006,23 @@ Arguments:
which contains the topmost data to be committed down. If
not specified, this is the active layer. (json-string, optional)
+- backing-file: The backing file string to write into the overlay
+ image of 'top'. If 'top' is the active layer,
+ specifying a backing file string is an error. This
+ filename is not validated.
+
+ If a pathname string is such that it cannot be
+ resolved by QEMU, that means that subsequent QMP or
+ HMP commands must use node-names for the image in
+ question, as filename lookup methods will fail.
+
+ If not specified, QEMU will automatically determine
+ the backing file string to use, or error out if
+ there is no obvious choice. Care should be taken
+ when specifying the string, to specify a valid
+ filename or protocol.
+ (json-string, optional) (Since 2.1)
+
If top == base, that is an error.
If top == active, the job will not be completed by itself,
user needs to complete the job with the block-job-complete
commit 5a6684d2b957f9ec75d7ed7b14332293abec1d6c
Author: Jeff Cody <jcody at redhat.com>
Date: Wed Jun 25 15:40:09 2014 -0400
block: add helper function to determine if a BDS is in a chain
This is a small helper function, to determine if 'base' is in the
chain of BlockDriverState 'top'. It returns true if it is in the chain,
and false otherwise.
If either argument is NULL, it will also return false.
Reviewed-by: Benoit Canet <benoit at irqsave.net>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Jeff Cody <jcody at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block.c b/block.c
index c111c29..f45e63c 100644
--- a/block.c
+++ b/block.c
@@ -3774,6 +3774,17 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
return NULL;
}
+/* If 'base' is in the same chain as 'top', return true. Otherwise,
+ * return false. If either argument is NULL, return false. */
+bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base)
+{
+ while (top && top != base) {
+ top = top->backing_hd;
+ }
+
+ return top != NULL;
+}
+
BlockDriverState *bdrv_next(BlockDriverState *bs)
{
if (!bs) {
diff --git a/include/block/block.h b/include/block/block.h
index 7e92f54..29c9e50 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -403,6 +403,7 @@ BlockDeviceInfoList *bdrv_named_nodes_list(void);
BlockDriverState *bdrv_lookup_bs(const char *device,
const char *node_name,
Error **errp);
+bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base);
BlockDriverState *bdrv_next(BlockDriverState *bs);
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
void *opaque);
commit fa40e65622352012dccd435147f28161375a6815
Author: Jeff Cody <jcody at redhat.com>
Date: Tue Jul 1 09:52:16 2014 +0200
block: add QAPI command to allow live backing file change
This allows a user to make a live change to the backing file recorded in
an open image.
The image file to modify can be specified 2 ways:
1) image filename
2) image node-name
Note: this does not cause the backing file itself to be reopened; it
merely changes the backing filename in the image file structure, and
in internal BDS structures.
It is the responsibility of the user to pass a filename string that
can be resolved when the image chain is reopened, and the filename
string is not validated.
A good analogy for this command is that it is a live version of
'qemu-img rebase -u', with respect to changing the backing file string.
[Jeff is offline so I respun this patch in his absence. Dropped image
filename since using node-name is preferred and this is a new command.
No need to introduce the limitations of finding images by filename.
--Stefan]
Reviewed-by: Eric Blake <eblake at redhat.com>
Reviewed-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index 79ce52b..57373d3 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2367,6 +2367,85 @@ void qmp_block_job_complete(const char *device, Error **errp)
block_job_complete(job, errp);
}
+void qmp_change_backing_file(const char *device,
+ const char *image_node_name,
+ const char *backing_file,
+ Error **errp)
+{
+ BlockDriverState *bs = NULL;
+ BlockDriverState *image_bs = NULL;
+ Error *local_err = NULL;
+ bool ro;
+ int open_flags;
+ int ret;
+
+ /* find the top layer BDS of the chain */
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
+ }
+
+ image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (!image_bs) {
+ error_setg(errp, "image file not found");
+ return;
+ }
+
+ if (bdrv_find_base(image_bs) == image_bs) {
+ error_setg(errp, "not allowing backing file change on an image "
+ "without a backing file");
+ return;
+ }
+
+ /* even though we are not necessarily operating on bs, we need it to
+ * determine if block ops are currently prohibited on the chain */
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
+ return;
+ }
+
+ /* final sanity check */
+ if (!bdrv_chain_contains(bs, image_bs)) {
+ error_setg(errp, "'%s' and image file are not in the same chain",
+ device);
+ return;
+ }
+
+ /* if not r/w, reopen to make r/w */
+ open_flags = image_bs->open_flags;
+ ro = bdrv_is_read_only(image_bs);
+
+ if (ro) {
+ bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ ret = bdrv_change_backing_file(image_bs, backing_file,
+ image_bs->drv ? image_bs->drv->format_name : "");
+
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not change backing file to '%s'",
+ backing_file);
+ /* don't exit here, so we can try to restore open flags if
+ * appropriate */
+ }
+
+ if (ro) {
+ bdrv_reopen(image_bs, open_flags, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err); /* will preserve prior errp */
+ }
+ }
+}
+
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6a697f1..aa12527 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -680,6 +680,32 @@
'data': 'BlockdevSnapshot' }
##
+# @change-backing-file
+#
+# Change the backing file in the image file metadata. This does not
+# cause QEMU to reopen the image file to reparse the backing filename
+# (it may, however, perform a reopen to change permissions from
+# r/o -> r/w -> r/o, if needed). The new backing file string is written
+# into the image file metadata, and the QEMU internal strings are
+# updated.
+#
+# @image-node-name: The name of the block driver state node of the
+# image to modify.
+#
+# @device: The name of the device that owns image-node-name.
+#
+# @backing-file: The string to write as the backing file. This
+# string is not validated, so care should be taken
+# when specifying the string or the image chain may
+# not be able to be reopened again.
+#
+# Since: 2.1
+##
+{ 'command': 'change-backing-file',
+ 'data': { 'device': 'str', 'image-node-name': 'str',
+ 'backing-file': 'str' } }
+
+##
# @block-commit
#
# Live commit of data from overlay image nodes into backing nodes - i.e.,
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8c5fdb5..8534948 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1353,6 +1353,45 @@ Example:
EQMP
{
+ .name = "change-backing-file",
+ .args_type = "device:s,image-node-name:s,backing-file:s",
+ .mhandler.cmd_new = qmp_marshal_input_change_backing_file,
+ },
+
+SQMP
+change-backing-file
+-------------------
+Since: 2.1
+
+Change the backing file in the image file metadata. This does not cause
+QEMU to reopen the image file to reparse the backing filename (it may,
+however, perform a reopen to change permissions from r/o -> r/w -> r/o,
+if needed). The new backing file string is written into the image file
+metadata, and the QEMU internal strings are updated.
+
+Arguments:
+
+- "image-node-name": The name of the block driver state node of the
+ image to modify. The "device" is argument is used to
+ verify "image-node-name" is in the chain described by
+ "device".
+ (json-string, optional)
+
+- "device": The name of the device.
+ (json-string)
+
+- "backing-file": The string to write as the backing file. This string is
+ not validated, so care should be taken when specifying
+ the string or the image chain may not be able to be
+ reopened again.
+ (json-string)
+
+Returns: Nothing on success
+ If "device" does not exist or cannot be determined, DeviceNotFound
+
+EQMP
+
+ {
.name = "balloon",
.args_type = "value:M",
.mhandler.cmd_new = qmp_marshal_input_balloon,
commit 352e8da743f26948cb12d0ee53c455f328f59bbe
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Jun 26 15:10:03 2014 +0200
qdev: correctly send DEVICE_DELETED for recursively-deleted devices
When a device is unparented (i.e. made completely hidden from management)
we want to send a DEVICE_DELETED event only if the device actually was
realized. This avoids raising DEVICE_DELETED events when device_add
fails.
However, this does not work right for recursively-deleted
devices: the whole tree is _first_ unrealized, _then_ unparented.
Then device_unparent sees realized==false and fails to trigger
the event. The solution is simply to move have_realized into
the DeviceState struct. If device_add fails, we never set the
new field to true and DEVICE_DELETED is not sent.
Fixes qemu-iotests testcase 067 (broken by commit 5942a19, though that
commit in turn fixed a possible segfault in the same test).
Reported-by: Markus Armbruster <armbru at redhat.com>
Reviewed-by: Markus Armbruster <armbru at redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index d1eba3c..c520415 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -848,6 +848,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
if (dev->hotplugged && local_err == NULL) {
device_reset(dev);
}
+ dev->pending_deleted_event = false;
} else if (!value && dev->realized) {
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
object_property_set_bool(OBJECT(bus), false, "realized",
@@ -862,6 +863,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
if (dc->unrealize && local_err == NULL) {
dc->unrealize(dev, &local_err);
}
+ dev->pending_deleted_event = true;
}
if (local_err != NULL) {
@@ -972,7 +974,6 @@ static void device_unparent(Object *obj)
{
DeviceState *dev = DEVICE(obj);
BusState *bus;
- bool have_realized = dev->realized;
if (dev->realized) {
object_property_set_bool(obj, false, "realized", NULL);
@@ -988,7 +989,7 @@ static void device_unparent(Object *obj)
}
/* Only send event if the device had been completely realized */
- if (have_realized) {
+ if (dev->pending_deleted_event) {
gchar *path = object_get_canonical_path(OBJECT(dev));
qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort);
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 9221cfc..0799ff2 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -156,6 +156,7 @@ struct DeviceState {
const char *id;
bool realized;
+ bool pending_deleted_event;
QemuOpts *opts;
int hotplugged;
BusState *parent_bus;
commit 1f6245e5aba94ff7acd34f8514da7dfb9712935d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Jun 13 10:48:06 2014 +0200
memory: do not give a name to the internal exec.c regions
There is no need to have them visible under /machine.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/exec.c b/exec.c
index df4a080..5a2a25e 100644
--- a/exec.c
+++ b/exec.c
@@ -1801,13 +1801,13 @@ MemoryRegion *iotlb_to_region(AddressSpace *as, hwaddr index)
static void io_mem_init(void)
{
- memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, "rom", UINT64_MAX);
+ memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX);
memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL,
- "unassigned", UINT64_MAX);
+ NULL, UINT64_MAX);
memory_region_init_io(&io_mem_notdirty, NULL, ¬dirty_mem_ops, NULL,
- "notdirty", UINT64_MAX);
+ NULL, UINT64_MAX);
memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL,
- "watch", UINT64_MAX);
+ NULL, UINT64_MAX);
}
static void mem_begin(MemoryListener *listener)
commit 52aef7bba74a65d0c9fbec7a6559cc8385ab0e17
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Thu Jun 5 23:17:35 2014 -0700
memory: MemoryRegion: Add size property
To allow devices to dynamically resize the device. The motivation is
to allow devices with variable size to init their memory_region
without size early and then correctly populate size at realize() time.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/memory.c b/memory.c
index 834959b..64d7176 100644
--- a/memory.c
+++ b/memory.c
@@ -971,6 +971,15 @@ static bool memory_region_get_may_overlap(Object *obj, Error **errp)
return mr->may_overlap;
}
+static void memory_region_get_size(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+ uint64_t value = memory_region_size(mr);
+
+ visit_type_uint64(v, &value, name, errp);
+}
+
static void memory_region_initfn(Object *obj)
{
MemoryRegion *mr = MEMORY_REGION(obj);
@@ -1002,6 +1011,10 @@ static void memory_region_initfn(Object *obj)
memory_region_get_may_overlap,
NULL, /* memory_region_set_may_overlap */
&error_abort);
+ object_property_add(OBJECT(mr), "size", "uint64",
+ memory_region_get_size,
+ NULL, /* memory_region_set_size, */
+ NULL, NULL, &error_abort);
}
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
commit d33382da9abe21cb42f26b55945845b56ce9324a
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Thu Jun 5 23:17:01 2014 -0700
memory: MemoryRegion: Add may-overlap and priority props
QOM propertyify the .may-overlap and .priority fields. The setters
will re-add the memory as a subregion if needed (i.e. the values change
when the memory region is already contained).
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
[Remove setters. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 0c7e825..e2c8e3e 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -157,7 +157,7 @@ struct MemoryRegion {
bool flush_coalesced_mmio;
MemoryRegion *alias;
hwaddr alias_offset;
- int priority;
+ int32_t priority;
bool may_overlap;
QTAILQ_HEAD(subregions, MemoryRegion) subregions;
QTAILQ_ENTRY(MemoryRegion) subregions_link;
diff --git a/memory.c b/memory.c
index 04dc933..834959b 100644
--- a/memory.c
+++ b/memory.c
@@ -955,6 +955,22 @@ static Object *memory_region_resolve_container(Object *obj, void *opaque,
return OBJECT(mr->container);
}
+static void memory_region_get_priority(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+ int32_t value = mr->priority;
+
+ visit_type_int32(v, &value, name, errp);
+}
+
+static bool memory_region_get_may_overlap(Object *obj, Error **errp)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+
+ return mr->may_overlap;
+}
+
static void memory_region_initfn(Object *obj)
{
MemoryRegion *mr = MEMORY_REGION(obj);
@@ -978,6 +994,14 @@ static void memory_region_initfn(Object *obj)
memory_region_get_addr,
NULL, /* memory_region_set_addr */
NULL, NULL, &error_abort);
+ object_property_add(OBJECT(mr), "priority", "uint32",
+ memory_region_get_priority,
+ NULL, /* memory_region_set_priority */
+ NULL, NULL, &error_abort);
+ object_property_add_bool(OBJECT(mr), "may-overlap",
+ memory_region_get_may_overlap,
+ NULL, /* memory_region_set_may_overlap */
+ &error_abort);
}
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
commit 409ddd0139c101f813d16e8ebaa7c7d4b4afb96e
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Thu Jun 5 23:16:27 2014 -0700
memory: MemoryRegion: Add container and addr props
Expose the already existing .parent and .addr fields as QOM properties.
.parent (i.e. the field describing the memory region that contains this
one in Memory hierachy) is renamed "container". This is to avoid
confusion with the QOM parent.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
[Remove setters. Do not unref parent on releasing the property. Clean
up error propagation. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/memory.c b/memory.c
index 8970081..04dc933 100644
--- a/memory.c
+++ b/memory.c
@@ -16,6 +16,7 @@
#include "exec/memory.h"
#include "exec/address-spaces.h"
#include "exec/ioport.h"
+#include "qapi/visitor.h"
#include "qemu/bitops.h"
#include "qom/object.h"
#include "trace.h"
@@ -922,9 +923,42 @@ void memory_region_init(MemoryRegion *mr,
}
}
+static void memory_region_get_addr(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+ uint64_t value = mr->addr;
+
+ visit_type_uint64(v, &value, name, errp);
+}
+
+static void memory_region_get_container(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+ gchar *path = (gchar *)"";
+
+ if (mr->container) {
+ path = object_get_canonical_path(OBJECT(mr->container));
+ }
+ visit_type_str(v, &path, name, errp);
+ if (mr->container) {
+ g_free(path);
+ }
+}
+
+static Object *memory_region_resolve_container(Object *obj, void *opaque,
+ const char *part)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+
+ return OBJECT(mr->container);
+}
+
static void memory_region_initfn(Object *obj)
{
MemoryRegion *mr = MEMORY_REGION(obj);
+ ObjectProperty *op;
mr->ops = &unassigned_mem_ops;
mr->enabled = true;
@@ -932,6 +966,18 @@ static void memory_region_initfn(Object *obj)
mr->destructor = memory_region_destructor_none;
QTAILQ_INIT(&mr->subregions);
QTAILQ_INIT(&mr->coalesced);
+
+ op = object_property_add(OBJECT(mr), "container",
+ "link<" TYPE_MEMORY_REGION ">",
+ memory_region_get_container,
+ NULL, /* memory_region_set_container */
+ NULL, NULL, &error_abort);
+ op->resolve = memory_region_resolve_container;
+
+ object_property_add(OBJECT(mr), "addr", "uint64",
+ memory_region_get_addr,
+ NULL, /* memory_region_set_addr */
+ NULL, NULL, &error_abort);
}
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
commit 22a893e4f55344f96e1aafc66f5fedc491a5ca97
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Jun 11 10:58:06 2014 +0200
memory: MemoryRegion: replace owner field with QOM parent
The two are now the same.
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 85b56e2..0c7e825 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -141,7 +141,6 @@ struct MemoryRegion {
const MemoryRegionOps *ops;
const MemoryRegionIOMMUOps *iommu_ops;
void *opaque;
- struct Object *owner;
MemoryRegion *container;
Int128 size;
hwaddr addr;
diff --git a/memory.c b/memory.c
index 9397fec..8970081 100644
--- a/memory.c
+++ b/memory.c
@@ -905,9 +905,11 @@ void memory_region_init(MemoryRegion *mr,
const char *name,
uint64_t size)
{
- object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
+ if (!owner) {
+ owner = qdev_get_machine();
+ }
- mr->owner = owner ? owner : qdev_get_machine();
+ object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
mr->size = int128_make64(size);
if (size == UINT64_MAX) {
mr->size = int128_2_64();
@@ -915,7 +917,7 @@ void memory_region_init(MemoryRegion *mr,
mr->name = g_strdup(name);
if (name) {
- object_property_add_child_array(mr->owner, name, OBJECT(mr));
+ object_property_add_child_array(owner, name, OBJECT(mr));
object_unref(OBJECT(mr));
}
}
@@ -1187,24 +1189,37 @@ void memory_region_destroy(MemoryRegion *mr)
Object *memory_region_owner(MemoryRegion *mr)
{
- return mr->owner;
+ Object *obj = OBJECT(mr);
+ return obj->parent;
}
void memory_region_ref(MemoryRegion *mr)
{
- if (mr && mr->owner) {
- object_ref(mr->owner);
+ /* MMIO callbacks most likely will access data that belongs
+ * to the owner, hence the need to ref/unref the owner whenever
+ * the memory region is in use.
+ *
+ * The memory region is a child of its owner. As long as the
+ * owner doesn't call unparent itself on the memory region,
+ * ref-ing the owner will also keep the memory region alive.
+ * Memory regions without an owner are supposed to never go away,
+ * but we still ref/unref them for debugging purposes.
+ */
+ Object *obj = OBJECT(mr);
+ if (obj && obj->parent) {
+ object_ref(obj->parent);
} else {
- object_ref(OBJECT(mr));
+ object_ref(obj);
}
}
void memory_region_unref(MemoryRegion *mr)
{
- if (mr && mr->owner) {
- object_unref(mr->owner);
+ Object *obj = OBJECT(mr);
+ if (obj && obj->parent) {
+ object_unref(obj->parent);
} else {
- object_unref(OBJECT(mr));
+ object_unref(obj);
}
}
commit b4fefef9d52003b6d09866501275a9a57995c6b0
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Thu Jun 5 23:15:52 2014 -0700
memory: MemoryRegion: QOMify
QOMify memory regions as an Object. The former init() and destroy()
routines become instance_init() and instance_finalize() resp.
memory_region_init() is re-implemented to be:
object_initialize() + set fields
memory_region_destroy() is re-implemented to call unparent().
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
[Add newly-created MR as child, unparent on destruction. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/exec.c b/exec.c
index 18d6c35..df4a080 100644
--- a/exec.c
+++ b/exec.c
@@ -883,7 +883,7 @@ static void phys_section_destroy(MemoryRegion *mr)
if (mr->subpage) {
subpage_t *subpage = container_of(mr, subpage_t, iomem);
- memory_region_destroy(&subpage->iomem);
+ object_unref(OBJECT(&subpage->iomem));
g_free(subpage);
}
}
@@ -1768,7 +1768,7 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
mmio->as = as;
mmio->base = base;
memory_region_init_io(&mmio->iomem, NULL, &subpage_ops, mmio,
- "subpage", TARGET_PAGE_SIZE);
+ NULL, TARGET_PAGE_SIZE);
mmio->iomem.subpage = true;
#if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x\n", __func__,
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 3d778d7..85b56e2 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -32,10 +32,15 @@
#include "qemu/int128.h"
#include "qemu/notify.h"
#include "qapi/error.h"
+#include "qom/object.h"
#define MAX_PHYS_ADDR_SPACE_BITS 62
#define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1)
+#define TYPE_MEMORY_REGION "qemu:memory-region"
+#define MEMORY_REGION(obj) \
+ OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION)
+
typedef struct MemoryRegionOps MemoryRegionOps;
typedef struct MemoryRegionMmio MemoryRegionMmio;
@@ -131,6 +136,7 @@ typedef struct CoalescedMemoryRange CoalescedMemoryRange;
typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
struct MemoryRegion {
+ Object parent_obj;
/* All fields are private - violators will be prosecuted */
const MemoryRegionOps *ops;
const MemoryRegionIOMMUOps *iommu_ops;
diff --git a/memory.c b/memory.c
index 7eaa1e9..9397fec 100644
--- a/memory.c
+++ b/memory.c
@@ -842,40 +842,94 @@ static void memory_region_destructor_rom_device(MemoryRegion *mr)
qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
}
+static bool memory_region_need_escape(char c)
+{
+ return c == '/' || c == '[' || c == '\\' || c == ']';
+}
+
+static char *memory_region_escape_name(const char *name)
+{
+ const char *p;
+ char *escaped, *q;
+ uint8_t c;
+ size_t bytes = 0;
+
+ for (p = name; *p; p++) {
+ bytes += memory_region_need_escape(*p) ? 4 : 1;
+ }
+ if (bytes == p - name) {
+ return g_memdup(name, bytes + 1);
+ }
+
+ escaped = g_malloc(bytes + 1);
+ for (p = name, q = escaped; *p; p++) {
+ c = *p;
+ if (unlikely(memory_region_need_escape(c))) {
+ *q++ = '\\';
+ *q++ = 'x';
+ *q++ = "0123456789abcdef"[c >> 4];
+ c = "0123456789abcdef"[c & 15];
+ }
+ *q++ = c;
+ }
+ *q = 0;
+ return escaped;
+}
+
+static void object_property_add_child_array(Object *owner,
+ const char *name,
+ Object *child)
+{
+ int i;
+ char *base_name = memory_region_escape_name(name);
+
+ for (i = 0; ; i++) {
+ char *full_name = g_strdup_printf("%s[%d]", base_name, i);
+ Error *local_err = NULL;
+
+ object_property_add_child(owner, full_name, child, &local_err);
+ g_free(full_name);
+ if (!local_err) {
+ break;
+ }
+
+ error_free(local_err);
+ }
+
+ g_free(base_name);
+}
+
+
void memory_region_init(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
- mr->ops = &unassigned_mem_ops;
- mr->opaque = NULL;
+ object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
+
mr->owner = owner ? owner : qdev_get_machine();
- mr->iommu_ops = NULL;
- mr->container = NULL;
mr->size = int128_make64(size);
if (size == UINT64_MAX) {
mr->size = int128_2_64();
}
- mr->addr = 0;
- mr->subpage = false;
+ mr->name = g_strdup(name);
+
+ if (name) {
+ object_property_add_child_array(mr->owner, name, OBJECT(mr));
+ object_unref(OBJECT(mr));
+ }
+}
+
+static void memory_region_initfn(Object *obj)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+
+ mr->ops = &unassigned_mem_ops;
mr->enabled = true;
- mr->terminates = false;
- mr->ram = false;
mr->romd_mode = true;
- mr->readonly = false;
- mr->rom_device = false;
mr->destructor = memory_region_destructor_none;
- mr->priority = 0;
- mr->may_overlap = false;
- mr->alias = NULL;
QTAILQ_INIT(&mr->subregions);
- memset(&mr->subregions_link, 0, sizeof mr->subregions_link);
QTAILQ_INIT(&mr->coalesced);
- mr->name = g_strdup(name);
- mr->dirty_log_mask = 0;
- mr->ioeventfd_nb = 0;
- mr->ioeventfds = NULL;
- mr->flush_coalesced_mmio = false;
}
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
@@ -1113,8 +1167,10 @@ void memory_region_init_reservation(MemoryRegion *mr,
memory_region_init_io(mr, owner, &unassigned_mem_ops, mr, name, size);
}
-void memory_region_destroy(MemoryRegion *mr)
+static void memory_region_finalize(Object *obj)
{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+
assert(QTAILQ_EMPTY(&mr->subregions));
assert(memory_region_transaction_depth == 0);
mr->destructor(mr);
@@ -1123,6 +1179,12 @@ void memory_region_destroy(MemoryRegion *mr)
g_free(mr->ioeventfds);
}
+void memory_region_destroy(MemoryRegion *mr)
+{
+ object_unparent(OBJECT(mr));
+}
+
+
Object *memory_region_owner(MemoryRegion *mr)
{
return mr->owner;
@@ -1132,6 +1194,8 @@ void memory_region_ref(MemoryRegion *mr)
{
if (mr && mr->owner) {
object_ref(mr->owner);
+ } else {
+ object_ref(OBJECT(mr));
}
}
@@ -1139,6 +1203,8 @@ void memory_region_unref(MemoryRegion *mr)
{
if (mr && mr->owner) {
object_unref(mr->owner);
+ } else {
+ object_unref(OBJECT(mr));
}
}
@@ -1946,3 +2012,18 @@ void mtree_info(fprintf_function mon_printf, void *f)
g_free(ml);
}
}
+
+static const TypeInfo memory_region_info = {
+ .parent = TYPE_OBJECT,
+ .name = TYPE_MEMORY_REGION,
+ .instance_size = sizeof(MemoryRegion),
+ .instance_init = memory_region_initfn,
+ .instance_finalize = memory_region_finalize,
+};
+
+static void memory_register_types(void)
+{
+ type_register_static(&memory_region_info);
+}
+
+type_init(memory_register_types)
commit b5c2c3d0c81ea97ac8443113b9a7a0c0ce25368e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Jun 11 10:52:32 2014 +0200
memory: MemoryRegion: use /machine as default owner
This will be added (after QOMification) as the QOM parent.
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/memory.c b/memory.c
index b91a60a..7eaa1e9 100644
--- a/memory.c
+++ b/memory.c
@@ -849,7 +849,7 @@ void memory_region_init(MemoryRegion *mr,
{
mr->ops = &unassigned_mem_ops;
mr->opaque = NULL;
- mr->owner = owner;
+ mr->owner = owner ? owner : qdev_get_machine();
mr->iommu_ops = NULL;
mr->container = NULL;
mr->size = int128_make64(size);
diff --git a/vl.c b/vl.c
index 41ddcd2..88feeab 100644
--- a/vl.c
+++ b/vl.c
@@ -3986,12 +3986,11 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
- cpu_exec_init_all();
-
current_machine = MACHINE(object_new(object_class_get_name(
OBJECT_CLASS(machine_class))));
object_property_add_child(object_get_root(), "machine",
OBJECT(current_machine), &error_abort);
+ cpu_exec_init_all();
if (machine_class->hw_version) {
qemu_set_version(machine_class->hw_version);
commit 563890c7c7e977842e2a35afe7a24d06d2103242
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Jun 13 09:35:18 2014 +0200
libqtest: escape strings in QMP commands, fix leak
libqtest is using g_strdup_printf to format QMP commands, but
this does not work if the argument strings need to be escaped.
Instead, use the fancy %-formatting functionality of QObject.
The only change required in tests is that strings have to be
formatted as %s, not '%s' or \"%s\". Luckily this usage of
parameterized QMP commands is not that frequent.
The leak is in socket_sendf. Since we are extracting the send
loop to a new function, fix it now.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 37096dc..c8e1e7b 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -291,7 +291,7 @@ static void test_media_insert(void)
/* Insert media in drive. DSKCHK should not be reset until a step pulse
* is sent. */
qmp_discard_response("{'execute':'change', 'arguments':{"
- " 'device':'floppy0', 'target': '%s' }}",
+ " 'device':'floppy0', 'target': %s }}",
test_image);
qmp_discard_response(""); /* ignore event
(FIXME open -> open transition?!) */
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 71468ac..98e8f4b 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -30,8 +30,9 @@
#include "qemu/compiler.h"
#include "qemu/osdep.h"
-#include "qapi/qmp/json-streamer.h"
#include "qapi/qmp/json-parser.h"
+#include "qapi/qmp/json-streamer.h"
+#include "qapi/qmp/qjson.h"
#define MAX_IRQ 256
#define SOCKET_TIMEOUT 5
@@ -220,19 +221,15 @@ void qtest_quit(QTestState *s)
g_free(s);
}
-static void socket_sendf(int fd, const char *fmt, va_list ap)
+static void socket_send(int fd, const char *buf, size_t size)
{
- gchar *str;
- size_t size, offset;
-
- str = g_strdup_vprintf(fmt, ap);
- size = strlen(str);
+ size_t offset;
offset = 0;
while (offset < size) {
ssize_t len;
- len = write(fd, str + offset, size - offset);
+ len = write(fd, buf + offset, size - offset);
if (len == -1 && errno == EINTR) {
continue;
}
@@ -244,6 +241,15 @@ static void socket_sendf(int fd, const char *fmt, va_list ap)
}
}
+static void socket_sendf(int fd, const char *fmt, va_list ap)
+{
+ gchar *str = g_strdup_vprintf(fmt, ap);
+ size_t size = strlen(str);
+
+ socket_send(fd, str, size);
+ g_free(str);
+}
+
static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
{
va_list ap;
@@ -378,8 +384,29 @@ QDict *qtest_qmp_receive(QTestState *s)
QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
{
- /* Send QMP request */
- socket_sendf(s->qmp_fd, fmt, ap);
+ va_list ap_copy;
+ QObject *qobj;
+
+ /* Going through qobject ensures we escape strings properly.
+ * This seemingly unnecessary copy is required in case va_list
+ * is an array type.
+ */
+ va_copy(ap_copy, ap);
+ qobj = qobject_from_jsonv(fmt, &ap_copy);
+ va_end(ap_copy);
+
+ /* No need to send anything for an empty QObject. */
+ if (qobj) {
+ QString *qstr = qobject_to_json(qobj);
+ const char *str = qstring_get_str(qstr);
+ size_t size = qstring_get_length(qstr);
+
+ /* Send QMP request */
+ socket_send(s->qmp_fd, str, size);
+
+ QDECREF(qstr);
+ qobject_decref(qobj);
+ }
/* Receive reply */
return qtest_qmp_receive(s);
diff --git a/tests/qom-test.c b/tests/qom-test.c
index d8d1d8d..4246382 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -53,7 +53,7 @@ static void test_properties(const char *path, bool recurse)
g_test_message("Obtaining properties of %s", path);
response = qmp("{ 'execute': 'qom-list',"
- " 'arguments': { 'path': '%s' } }", path);
+ " 'arguments': { 'path': %s } }", path);
g_assert(response);
if (!recurse) {
@@ -76,8 +76,8 @@ static void test_properties(const char *path, bool recurse)
const char *prop = qdict_get_str(tuple, "name");
g_test_message("Testing property %s.%s", path, prop);
response = qmp("{ 'execute': 'qom-get',"
- " 'arguments': { 'path': '%s',"
- " 'property': '%s' } }",
+ " 'arguments': { 'path': %s,"
+ " 'property': %s } }",
path, prop);
/* qom-get may fail but should not, e.g., segfault. */
g_assert(response);
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
index 15ddaf3..99db538 100644
--- a/tests/tmp105-test.c
+++ b/tests/tmp105-test.c
@@ -69,7 +69,7 @@ static int qmp_tmp105_get_temperature(const char *id)
QDict *response;
int ret;
- response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': '%s', "
+ response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
"'property': 'temperature' } }", id);
g_assert(qdict_haskey(response, "return"));
ret = qdict_get_int(response, "return");
@@ -81,7 +81,7 @@ static void qmp_tmp105_set_temperature(const char *id, int value)
{
QDict *response;
- response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': '%s', "
+ response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
"'property': 'temperature', 'value': %d } }", id, value);
g_assert(qdict_haskey(response, "return"));
QDECREF(response);
commit 8ffad850ef5ae14287d0e185d478c9a35820482c
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Thu Jun 5 23:13:36 2014 -0700
qom: object: Ignore refs/unrefs of NULL
Just do nothing if passed NULL for a ref or unref. This avoids
call sites that manage a combination of NULL or non-NULL pointers
having to add iffery around every ref and unref.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/qom/object.c b/qom/object.c
index d5de8f6..0e8267b 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -711,11 +711,17 @@ GSList *object_class_get_list(const char *implements_type,
void object_ref(Object *obj)
{
+ if (!obj) {
+ return;
+ }
atomic_inc(&obj->ref);
}
void object_unref(Object *obj)
{
+ if (!obj) {
+ return;
+ }
g_assert(obj->ref > 0);
/* parent always holds a reference to its children */
@@ -1160,13 +1166,9 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
return;
}
- if (new_target) {
- object_ref(new_target);
- }
+ object_ref(new_target);
*child = new_target;
- if (old_target != NULL) {
- object_unref(old_target);
- }
+ object_unref(old_target);
}
static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
commit c28322d10cd5f0529605b48684d2b82c9eb9c020
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date: Mon May 26 17:39:51 2014 -0700
qom: object: remove parent pointer when unparenting
Certain parts of the QOM framework test this pointer to determine if
an object is parented. Nuke it when the object is unparented to allow
for reuse of an object after unparenting.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/qom/object.c b/qom/object.c
index f49335f..d5de8f6 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -397,6 +397,7 @@ void object_unparent(Object *obj)
}
if (obj->parent) {
object_property_del_child(obj->parent, obj, NULL);
+ obj->parent = NULL;
}
object_unref(obj);
}
commit 654a36d857ff949e0d1989904b76f53fded9dc83
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date: Wed Jun 4 14:52:03 2014 -0300
mc146818rtc: add "rtc-time" link to "/machine/rtc"
Add a link to rtc under /machine providing a stable
location for management apps to query the value of the
time. The link should be added by any object that sends
RTC_TIME_CHANGE events.
{"execute":"qom-get","arguments":{"path":"/machine","property":"rtc-time"} }
Suggested by Paolo Bonzini and Andreas Faerber.
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 307732c..9d817ca 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -909,6 +909,9 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
object_property_add(OBJECT(s), "date", "struct tm",
rtc_get_date, NULL, NULL, s, NULL);
+
+ object_property_add_alias(qdev_get_machine(), "rtc-time",
+ OBJECT(s), "date", NULL);
}
ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
@@ -950,11 +953,17 @@ static void rtc_class_initfn(ObjectClass *klass, void *data)
dc->cannot_instantiate_with_device_add_yet = true;
}
+static void rtc_finalize(Object *obj)
+{
+ object_property_del(qdev_get_machine(), "rtc", NULL);
+}
+
static const TypeInfo mc146818rtc_info = {
.name = TYPE_MC146818_RTC,
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(RTCState),
.class_init = rtc_class_initfn,
+ .instance_finalize = rtc_finalize,
};
static void mc146818rtc_register_types(void)
commit d190698e6f806198da42c05c35b623760b6e1f00
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Tue Jun 10 11:17:35 2014 +0200
qom: allow creating an alias of a child<> property
Child properties must be unique. Fix this problem by
turning their aliases into links.
The resolve function that forwards to the target property
does not have any knowledge of the target property's type,
so it works fine.
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/qom/object.c b/qom/object.c
index 7a892ef..f49335f 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1607,22 +1607,32 @@ void object_property_add_alias(Object *obj, const char *name,
AliasProperty *prop;
ObjectProperty *op;
ObjectProperty *target_prop;
+ gchar *prop_type;
target_prop = object_property_find(target_obj, target_name, errp);
if (!target_prop) {
return;
}
+ if (object_property_is_child(target_prop)) {
+ prop_type = g_strdup_printf("link%s",
+ target_prop->type + strlen("child"));
+ } else {
+ prop_type = g_strdup(target_prop->type);
+ }
+
prop = g_malloc(sizeof(*prop));
prop->target_obj = target_obj;
prop->target_name = target_name;
- op = object_property_add(obj, name, target_prop->type,
+ op = object_property_add(obj, name, prop_type,
property_get_alias,
property_set_alias,
property_release_alias,
prop, errp);
op->resolve = property_resolve_alias;
+
+ g_free(prop_type);
}
static void object_instance_init(Object *obj)
commit 64607d088132abdb25bf30d93e97d0c8df7b364c
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Jun 5 13:11:51 2014 +0200
qom: add a generic mechanism to resolve paths
It may be desirable to have custom link<> properties that do more
than just store an object. Even the addition of a "check"
function is not enough if setting the link has side effects
or if a non-standard reference counting is preferrable.
Avoid the assumption that the opaque field of a link<> is a
LinkProperty struct, by adding a generic "resolve" callback
to ObjectProperty. This fixes aliases of link properties.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/include/qom/object.h b/include/qom/object.h
index 44c513f..8a05a81 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -304,6 +304,25 @@ typedef void (ObjectPropertyAccessor)(Object *obj,
Error **errp);
/**
+ * ObjectPropertyResolve:
+ * @obj: the object that owns the property
+ * @opaque: the opaque registered with the property
+ * @part: the name of the property
+ *
+ * Resolves the #Object corresponding to property @part.
+ *
+ * The returned object can also be used as a starting point
+ * to resolve a relative path starting with "@part".
+ *
+ * Returns: If @path is the path that led to @obj, the function
+ * returns the #Object corresponding to "@path/@part".
+ * If "@path/@part" is not a valid object path, it returns #NULL.
+ */
+typedef Object *(ObjectPropertyResolve)(Object *obj,
+ void *opaque,
+ const char *part);
+
+/**
* ObjectPropertyRelease:
* @obj: the object that owns the property
* @name: the name of the property
@@ -321,6 +340,7 @@ typedef struct ObjectProperty
gchar *type;
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
+ ObjectPropertyResolve *resolve;
ObjectPropertyRelease *release;
void *opaque;
@@ -787,12 +807,16 @@ void object_unref(Object *obj);
* destruction. This may be NULL.
* @opaque: an opaque pointer to pass to the callbacks for the property
* @errp: returns an error if this function fails
+ *
+ * Returns: The #ObjectProperty; this can be used to set the @resolve
+ * callback for child and link properties.
*/
-void object_property_add(Object *obj, const char *name, const char *type,
- ObjectPropertyAccessor *get,
- ObjectPropertyAccessor *set,
- ObjectPropertyRelease *release,
- void *opaque, Error **errp);
+ObjectProperty *object_property_add(Object *obj, const char *name,
+ const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp);
void object_property_del(Object *obj, const char *name, Error **errp);
diff --git a/qom/object.c b/qom/object.c
index a760514..7a892ef 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -356,11 +356,6 @@ static inline bool object_property_is_child(ObjectProperty *prop)
return strstart(prop->type, "child<", NULL);
}
-static inline bool object_property_is_link(ObjectProperty *prop)
-{
- return strstart(prop->type, "link<", NULL);
-}
-
static void object_property_del_all(Object *obj)
{
while (!QTAILQ_EMPTY(&obj->properties)) {
@@ -728,11 +723,12 @@ void object_unref(Object *obj)
}
}
-void object_property_add(Object *obj, const char *name, const char *type,
- ObjectPropertyAccessor *get,
- ObjectPropertyAccessor *set,
- ObjectPropertyRelease *release,
- void *opaque, Error **errp)
+ObjectProperty *
+object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp)
{
ObjectProperty *prop;
@@ -741,7 +737,7 @@ void object_property_add(Object *obj, const char *name, const char *type,
error_setg(errp, "attempt to add duplicate property '%s'"
" to object (type '%s')", name,
object_get_typename(obj));
- return;
+ return NULL;
}
}
@@ -756,6 +752,7 @@ void object_property_add(Object *obj, const char *name, const char *type,
prop->opaque = opaque;
QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
+ return prop;
}
ObjectProperty *object_property_find(Object *obj, const char *name,
@@ -1028,6 +1025,11 @@ static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
g_free(path);
}
+static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part)
+{
+ return opaque;
+}
+
static void object_finalize_child_property(Object *obj, const char *name,
void *opaque)
{
@@ -1041,15 +1043,18 @@ void object_property_add_child(Object *obj, const char *name,
{
Error *local_err = NULL;
gchar *type;
+ ObjectProperty *op;
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
- object_property_add(obj, name, type, object_get_child_property, NULL,
- object_finalize_child_property, child, &local_err);
+ op = object_property_add(obj, name, type, object_get_child_property, NULL,
+ object_finalize_child_property, child, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
+
+ op->resolve = object_resolve_child_property;
object_ref(child);
g_assert(child->parent == NULL);
child->parent = obj;
@@ -1163,6 +1168,13 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
}
}
+static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
+{
+ LinkProperty *lprop = opaque;
+
+ return *lprop->child;
+}
+
static void object_release_link_property(Object *obj, const char *name,
void *opaque)
{
@@ -1184,6 +1196,7 @@ void object_property_add_link(Object *obj, const char *name,
Error *local_err = NULL;
LinkProperty *prop = g_malloc(sizeof(*prop));
gchar *full_type;
+ ObjectProperty *op;
prop->child = child;
prop->check = check;
@@ -1191,17 +1204,21 @@ void object_property_add_link(Object *obj, const char *name,
full_type = g_strdup_printf("link<%s>", type);
- object_property_add(obj, name, full_type,
- object_get_link_property,
- check ? object_set_link_property : NULL,
- object_release_link_property,
- prop,
- &local_err);
+ op = object_property_add(obj, name, full_type,
+ object_get_link_property,
+ check ? object_set_link_property : NULL,
+ object_release_link_property,
+ prop,
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
g_free(prop);
+ goto out;
}
+ op->resolve = object_resolve_link_property;
+
+out:
g_free(full_type);
}
@@ -1260,11 +1277,8 @@ Object *object_resolve_path_component(Object *parent, const gchar *part)
return NULL;
}
- if (object_property_is_link(prop)) {
- LinkProperty *lprop = prop->opaque;
- return *lprop->child;
- } else if (object_property_is_child(prop)) {
- return prop->opaque;
+ if (prop->resolve) {
+ return prop->resolve(parent, prop->opaque, part);
} else {
return NULL;
}
@@ -1571,6 +1585,14 @@ static void property_set_alias(Object *obj, struct Visitor *v, void *opaque,
object_property_set(prop->target_obj, v, prop->target_name, errp);
}
+static Object *property_resolve_alias(Object *obj, void *opaque,
+ const gchar *part)
+{
+ AliasProperty *prop = opaque;
+
+ return object_resolve_path_component(prop->target_obj, prop->target_name);
+}
+
static void property_release_alias(Object *obj, const char *name, void *opaque)
{
AliasProperty *prop = opaque;
@@ -1583,6 +1605,7 @@ void object_property_add_alias(Object *obj, const char *name,
Error **errp)
{
AliasProperty *prop;
+ ObjectProperty *op;
ObjectProperty *target_prop;
target_prop = object_property_find(target_obj, target_name, errp);
@@ -1594,11 +1617,12 @@ void object_property_add_alias(Object *obj, const char *name,
prop->target_obj = target_obj;
prop->target_name = target_name;
- object_property_add(obj, name, target_prop->type,
- property_get_alias,
- property_set_alias,
- property_release_alias,
- prop, errp);
+ op = object_property_add(obj, name, target_prop->type,
+ property_get_alias,
+ property_set_alias,
+ property_release_alias,
+ prop, errp);
+ op->resolve = property_resolve_alias;
}
static void object_instance_init(Object *obj)
commit 4e855baabfb548067b618808c32dc413d40e0bc7
Author: Benoît Canet <benoit.canet at irqsave.net>
Date: Mon Jun 30 17:05:41 2014 +0200
qapi: Change back sector-count to sectors-count in quorum QAPI events.
fe069d9d had aligned code and documentation while dropping the s from the
actual JSON output. Fix that.
This also fix test/qemu-iotest/081 since the missing s was causing a permutation.
Signed-off-by: Benoit Canet <benoit at irqsave.net>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index 44be891..4a6c2a2 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -250,14 +250,14 @@ Emitted by the Quorum block driver if it fails to establish a quorum.
Data:
-- "reference": device name if defined else node name.
-- "sector-num": Number of the first sector of the failed read operation.
-- "sector-count": Failed read operation sector count.
+- "reference": device name if defined else node name.
+- "sector-num": Number of the first sector of the failed read operation.
+- "sectors-count": Failed read operation sector count.
Example:
{ "event": "QUORUM_FAILURE",
- "data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
+ "data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
QUORUM_REPORT_BAD
@@ -267,19 +267,19 @@ Emitted to report a corruption of a Quorum file.
Data:
-- "error": Error message (json-string, optional)
- Only present on failure. This field contains a human-readable
- error message. There are no semantics other than that the
- block layer reported an error and clients should not try to
- interpret the error string.
-- "node-name": The graph node name of the block driver state.
-- "sector-num": Number of the first sector of the failed read operation.
-- "sector-count": Failed read operation sector count.
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that the
+ block layer reported an error and clients should not try to
+ interpret the error string.
+- "node-name": The graph node name of the block driver state.
+- "sector-num": Number of the first sector of the failed read operation.
+- "sectors-count": Failed read operation sector count.
Example:
{ "event": "QUORUM_REPORT_BAD",
- "data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
+ "data": { "node-name": "1.raw", "sector-num": 345435, "sectors-count": 5 },
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
RESET
diff --git a/qapi/event.json b/qapi/event.json
index ff97aeb..c51dc49 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -288,12 +288,12 @@
#
# @sector-num: number of the first sector of the failed read operation
#
-# @sector-count: failed read operation sector count
+# @sectors-count: failed read operation sector count
#
# Since: 2.0
##
{ 'event': 'QUORUM_FAILURE',
- 'data': { 'reference': 'str', 'sector-num': 'int', 'sector-count': 'int' } }
+ 'data': { 'reference': 'str', 'sector-num': 'int', 'sectors-count': 'int' } }
##
# @QUORUM_REPORT_BAD
@@ -309,13 +309,13 @@
#
# @sector-num: number of the first sector of the failed read operation
#
-# @sector-count: failed read operation sector count
+# @sectors-count: failed read operation sector count
#
# Since: 2.0
##
{ 'event': 'QUORUM_REPORT_BAD',
'data': { '*error': 'str', 'node-name': 'str',
- 'sector-num': 'int', 'sector-count': 'int' } }
+ 'sector-num': 'int', 'sectors-count': 'int' } }
##
# @VSERPORT_CHANGE
commit 6764579f894950afe87d8ec3b323adde8925d4fd
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Mon Jun 30 19:03:37 2014 +0100
block/cow: Avoid use of uninitialized cow_bs in error path
Commit 25814e8987 introduced an error-exit code path which does
a "goto exit" before the cow_bs variable is initialized, meaning
we would call bdrv_unref() on an uninitialized variable and
likely segfault. Fix this by moving the NULL-initialization
to the top of the function and making the exit code path handle
the case where it is NULL.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block/cow.c b/block/cow.c
index 8f81ee6..6ee4833 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -332,7 +332,7 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
char *image_filename = NULL;
Error *local_err = NULL;
int ret;
- BlockDriverState *cow_bs;
+ BlockDriverState *cow_bs = NULL;
/* Read out options */
image_sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
@@ -344,7 +344,6 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
goto exit;
}
- cow_bs = NULL;
ret = bdrv_open(&cow_bs, filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
if (ret < 0) {
@@ -383,7 +382,9 @@ static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
exit:
g_free(image_filename);
- bdrv_unref(cow_bs);
+ if (cow_bs) {
+ bdrv_unref(cow_bs);
+ }
return ret;
}
commit 4caf0fcd45db46920a6264b1621ae6adc772ef19
Author: Jeff Cody <jcody at redhat.com>
Date: Wed Jun 25 15:35:26 2014 -0400
block: simplify bdrv_find_base() and bdrv_find_overlay()
This simplifies the function bdrv_find_overlay(). With this change,
bdrv_find_base() is just a subset of usage of bdrv_find_overlay(),
so this also takes advantage of that.
Reviewed-by: Eric Blake <eblake at redhat.com>
Reviewed-by: Benoit Canet <benoit at irqsave.net>
Signed-off-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block.c b/block.c
index 6856c18..c111c29 100644
--- a/block.c
+++ b/block.c
@@ -2508,32 +2508,23 @@ int bdrv_change_backing_file(BlockDriverState *bs,
*
* Returns NULL if bs is not found in active's image chain,
* or if active == bs.
+ *
+ * Returns the bottommost base image if bs == NULL.
*/
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
BlockDriverState *bs)
{
- BlockDriverState *overlay = NULL;
- BlockDriverState *intermediate;
-
- assert(active != NULL);
- assert(bs != NULL);
-
- /* if bs is the same as active, then by definition it has no overlay
- */
- if (active == bs) {
- return NULL;
+ while (active && bs != active->backing_hd) {
+ active = active->backing_hd;
}
- intermediate = active;
- while (intermediate->backing_hd) {
- if (intermediate->backing_hd == bs) {
- overlay = intermediate;
- break;
- }
- intermediate = intermediate->backing_hd;
- }
+ return active;
+}
- return overlay;
+/* Given a BDS, searches for the base layer. */
+BlockDriverState *bdrv_find_base(BlockDriverState *bs)
+{
+ return bdrv_find_overlay(bs, NULL);
}
typedef struct BlkIntermediateStates {
@@ -4326,22 +4317,6 @@ int bdrv_get_backing_file_depth(BlockDriverState *bs)
return 1 + bdrv_get_backing_file_depth(bs->backing_hd);
}
-BlockDriverState *bdrv_find_base(BlockDriverState *bs)
-{
- BlockDriverState *curr_bs = NULL;
-
- if (!bs) {
- return NULL;
- }
-
- curr_bs = bs;
-
- while (curr_bs->backing_hd) {
- curr_bs = curr_bs->backing_hd;
- }
- return curr_bs;
-}
-
/**************************************************************/
/* async I/Os */
commit 7676e2c597000eff3a7233b40cca768b358f9bc9
Author: Jeff Cody <jcody at redhat.com>
Date: Mon Jun 30 15:14:15 2014 +0200
block: make 'top' argument to block-commit optional
Now that active layer block-commit is supported, the 'top' argument
no longer needs to be mandatory.
Change it to optional, with the default being the active layer in the
device chain.
[kwolf: Rebased and resolved conflict in tests/qemu-iotests/040]
Reviewed-by: Eric Blake <eblake at redhat.com>
Reviewed-by: Benoit Canet <benoit at irqsave.net>
Signed-off-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/blockdev.c b/blockdev.c
index 69b7c2a..79ce52b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1913,7 +1913,8 @@ void qmp_block_stream(const char *device, bool has_base,
}
void qmp_block_commit(const char *device,
- bool has_base, const char *base, const char *top,
+ bool has_base, const char *base,
+ bool has_top, const char *top,
bool has_speed, int64_t speed,
Error **errp)
{
@@ -1932,6 +1933,11 @@ void qmp_block_commit(const char *device,
/* drain all i/o before commits */
bdrv_drain_all();
+ /* Important Note:
+ * libvirt relies on the DeviceNotFound error class in order to probe for
+ * live commit feature versions; for this to work, we must make sure to
+ * perform the device lookup before any generic errors that may occur in a
+ * scenario in which all optional arguments are omitted. */
bs = bdrv_find(device);
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
@@ -1945,7 +1951,7 @@ void qmp_block_commit(const char *device,
/* default top_bs is the active layer */
top_bs = bs;
- if (top) {
+ if (has_top && top) {
if (strcmp(bs->filename, top) != 0) {
top_bs = bdrv_find_backing_image(bs, top);
}
@@ -1967,6 +1973,12 @@ void qmp_block_commit(const char *device,
return;
}
+ /* Do not allow attempts to commit an image into itself */
+ if (top_bs == base_bs) {
+ error_setg(errp, "cannot commit an image into itself");
+ return;
+ }
+
if (top_bs == bs) {
commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
bs, &local_err);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index faf394c..6a697f1 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -690,8 +690,9 @@
# @base: #optional The file name of the backing image to write data into.
# If not specified, this is the deepest backing image
#
-# @top: The file name of the backing image within the image chain,
-# which contains the topmost data to be committed down.
+# @top: #optional The file name of the backing image within the image chain,
+# which contains the topmost data to be committed down. If
+# not specified, this is the active layer.
#
# If top == base, that is an error.
# If top == active, the job will not be completed by itself,
@@ -719,7 +720,7 @@
#
##
{ 'command': 'block-commit',
- 'data': { 'device': 'str', '*base': 'str', 'top': 'str',
+ 'data': { 'device': 'str', '*base': 'str', '*top': 'str',
'*speed': 'int' } }
##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 1ea18b2..8c5fdb5 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -985,7 +985,7 @@ EQMP
{
.name = "block-commit",
- .args_type = "device:B,base:s?,top:s,speed:o?",
+ .args_type = "device:B,base:s?,top:s?,speed:o?",
.mhandler.cmd_new = qmp_marshal_input_block_commit,
},
@@ -1003,7 +1003,8 @@ Arguments:
If not specified, this is the deepest backing image
(json-string, optional)
- "top": The file name of the backing image within the image chain,
- which contains the topmost data to be committed down.
+ which contains the topmost data to be committed down. If
+ not specified, this is the active layer. (json-string, optional)
If top == base, that is an error.
If top == active, the job will not be completed by itself,
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
index d166810..f1e16c1 100755
--- a/tests/qemu-iotests/040
+++ b/tests/qemu-iotests/040
@@ -35,11 +35,7 @@ test_img = os.path.join(iotests.test_dir, 'test.img')
class ImageCommitTestCase(iotests.QMPTestCase):
'''Abstract base class for image commit test cases'''
- def run_commit_test(self, top, base, need_ready=False):
- self.assert_no_active_block_jobs()
- result = self.vm.qmp('block-commit', device='drive0', top=top, base=base)
- self.assert_qmp(result, 'return', {})
-
+ def wait_for_complete(self, need_ready=False):
completed = False
ready = False
while not completed:
@@ -62,6 +58,18 @@ class ImageCommitTestCase(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
self.vm.shutdown()
+ def run_commit_test(self, top, base, need_ready=False):
+ self.assert_no_active_block_jobs()
+ result = self.vm.qmp('block-commit', device='drive0', top=top, base=base)
+ self.assert_qmp(result, 'return', {})
+ self.wait_for_complete(need_ready)
+
+ def run_default_commit_test(self):
+ self.assert_no_active_block_jobs()
+ result = self.vm.qmp('block-commit', device='drive0')
+ self.assert_qmp(result, 'return', {})
+ self.wait_for_complete()
+
class TestSingleDrive(ImageCommitTestCase):
image_len = 1 * 1024 * 1024
test_len = 1 * 1024 * 256
@@ -113,17 +121,17 @@ class TestSingleDrive(ImageCommitTestCase):
self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
+ def test_top_is_default_active(self):
+ self.run_default_commit_test()
+ self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
+ self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
+
def test_top_and_base_reversed(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img)
- def test_top_omitted(self):
- self.assert_no_active_block_jobs()
- result = self.vm.qmp('block-commit', device='drive0')
- self.assert_qmp(result, 'error/class', 'GenericError')
- self.assert_qmp(result, 'error/desc', "Parameter 'top' is missing")
class TestRelativePaths(ImageCommitTestCase):
image_len = 1 * 1024 * 1024
commit c891e3bbc5bc3d74ad0ba896852a9796ceb147c2
Author: Max Reitz <mreitz at redhat.com>
Date: Fri Jun 27 22:47:48 2014 +0200
iotests: Add more tests to quick group
While at it, add some more tests to the quick group (those that run with
-nocache in under three seconds on my HDD).
Signed-off-by: Max Reitz <mreitz at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 7a2bfca..6e67f61 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -7,16 +7,16 @@
#
# test-group association ... one line per test
#
-001 rw auto
+001 rw auto quick
002 rw auto quick
003 rw auto
004 rw auto quick
-005 img auto
+005 img auto quick
006 img auto
007 snapshot auto
-008 rw auto
-009 rw auto
-010 rw auto
+008 rw auto quick
+009 rw auto quick
+010 rw auto quick
011 rw auto quick
012 auto quick
013 rw auto
@@ -24,36 +24,36 @@
015 rw snapshot auto
016 rw auto quick
017 rw backing auto quick
-018 rw backing auto
+018 rw backing auto quick
019 rw backing auto quick
020 rw backing auto quick
-021 io auto
+021 io auto quick
022 rw snapshot auto
023 rw auto
024 rw backing auto quick
025 rw auto quick
026 rw blkdbg auto
027 rw auto quick
-028 rw backing auto
+028 rw backing auto quick
029 rw auto quick
030 rw auto backing
031 rw auto quick
-032 rw auto
+032 rw auto quick
033 rw auto quick
-034 rw auto backing
+034 rw auto backing quick
035 rw auto quick
036 rw auto quick
-037 rw auto backing
-038 rw auto backing
-039 rw auto
+037 rw auto backing quick
+038 rw auto backing quick
+039 rw auto quick
040 rw auto
041 rw auto backing
042 rw auto quick
043 rw auto backing
044 rw auto
045 rw auto quick
-046 rw auto aio
-047 rw auto
+046 rw auto aio quick
+047 rw auto quick
048 img auto quick
049 rw auto
050 rw auto backing quick
@@ -81,20 +81,20 @@
072 rw auto quick
073 rw auto quick
074 rw auto quick
-075 rw auto
+075 rw auto quick
076 auto
077 rw auto quick
-078 rw auto
+078 rw auto quick
079 rw auto
080 rw auto
081 rw auto quick
082 rw auto quick
083 rw auto
-084 img auto
+084 img auto quick
085 rw auto
086 rw auto quick
087 rw auto quick
-088 rw auto
+088 rw auto quick
089 rw auto quick
090 rw auto quick
091 rw auto quick
commit ee9dd1fc901f7098a1c2af5a2202bd7f41124dbc
Author: Max Reitz <mreitz at redhat.com>
Date: Fri Jun 27 22:47:47 2014 +0200
iotests: Add qemu tests to quick group
Now that qemu-iotests-quick.sh supports tests using the qemu binary, we
are free to add such tests to the quick group.
Signed-off-by: Max Reitz <mreitz at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index e3dc4e8..7a2bfca 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -51,7 +51,7 @@
042 rw auto quick
043 rw auto backing
044 rw auto
-045 rw auto
+045 rw auto quick
046 rw auto aio
047 rw auto
048 img auto quick
@@ -71,13 +71,13 @@
062 rw auto quick
063 rw auto quick
064 rw auto quick
-065 rw auto
+065 rw auto quick
066 rw auto quick
-067 rw auto
-068 rw auto
+067 rw auto quick
+068 rw auto quick
069 rw auto quick
070 rw auto quick
-071 rw auto
+071 rw auto quick
072 rw auto quick
073 rw auto quick
074 rw auto quick
@@ -87,16 +87,16 @@
078 rw auto
079 rw auto
080 rw auto
-081 rw auto
+081 rw auto quick
082 rw auto quick
083 rw auto
084 img auto
085 rw auto
086 rw auto quick
-087 rw auto
+087 rw auto quick
088 rw auto
089 rw auto quick
090 rw auto quick
-091 rw auto
+091 rw auto quick
092 rw auto quick
-095 rw auto
+095 rw auto quick
commit 214a081a0dd44e69f7db4a741880a8ae9d174fa2
Author: Max Reitz <mreitz at redhat.com>
Date: Fri Jun 27 22:47:46 2014 +0200
iotests: Simplify qemu-iotests-quick.sh
As of the "iotests: Allow out-of-tree run" series, the qemu-iotests may
(and should) be run directly in the build tree and will then guess the
binary paths themselves. Therefore, qemu-iotests-quick.sh does not need
to (and should not) enter the source path anymore; also, it does not
need to specify the binaries because "check" will guess them
automatically.
As a side-effect, tests using qemu may now be added to the quick group.
Signed-off-by: Max Reitz <mreitz at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/tests/qemu-iotests-quick.sh b/tests/qemu-iotests-quick.sh
index c449e8a..8a9a4c6 100755
--- a/tests/qemu-iotests-quick.sh
+++ b/tests/qemu-iotests-quick.sh
@@ -1,16 +1,6 @@
#!/bin/sh
-# We don't know which of the system emulator binaries there is (or if there is
-# any at all), so the 'quick' group doesn't contain any tests that require
-# running qemu proper. Assign a fake binary name so that qemu-iotests doesn't
-# complain about the missing binary.
-export QEMU_PROG="this_should_be_unused"
-
-export QEMU_IMG_PROG="$(pwd)/qemu-img"
-export QEMU_IO_PROG="$(pwd)/qemu-io"
-export QEMU_NBD_PROG="$(pwd)/qemu-nbd"
-
-cd $SRC_PATH/tests/qemu-iotests
+cd tests/qemu-iotests
ret=0
./check -T -nocache -qcow2 -g quick || ret=1
commit 4ab1559085d688dddf4de77f1ead3102e243e668
Author: Chunyan Liu <cyliu at suse.com>
Date: Mon Jun 30 14:29:58 2014 +0800
qemu-img create: add 'nocow' option
Add 'nocow' option so that users could have a chance to set NOCOW flag to
newly created files. It's useful on btrfs file system to enhance performance.
Btrfs has low performance when hosting VM images, even more when the guest
in those VM are also using btrfs as file system. One way to mitigate this bad
performance is to turn off COW attributes on VM files. Generally, there are
two ways to turn off NOCOW on btrfs: a) by mounting fs with nodatacow, then
all newly created files will be NOCOW. b) per file. Add the NOCOW file
attribute. It could only be done to empty or new files.
This patch tries the second way, according to the option, it could add NOCOW
per file.
For most block drivers, since the create file step is in raw-posix.c, so we
can do setting NOCOW flag ioctl in raw-posix.c only.
But there are some exceptions, like block/vpc.c and block/vdi.c, they are
creating file by calling qemu_open directly. For them, do the same setting
NOCOW flag ioctl work in them separately.
[Fixed up 082.out due to the new 'nocow' creation option
--Stefan]
Signed-off-by: Chunyan Liu <cyliu at suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/block/qed.c b/block/qed.c
index eddae92..b69374b 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -567,7 +567,7 @@ static void bdrv_qed_close(BlockDriverState *bs)
static int qed_create(const char *filename, uint32_t cluster_size,
uint64_t image_size, uint32_t table_size,
const char *backing_file, const char *backing_fmt,
- Error **errp)
+ QemuOpts *opts, Error **errp)
{
QEDHeader header = {
.magic = QED_MAGIC,
@@ -586,7 +586,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
int ret = 0;
BlockDriverState *bs;
- ret = bdrv_create_file(filename, NULL, &local_err);
+ ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return ret;
@@ -682,7 +682,7 @@ static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp)
}
ret = qed_create(filename, cluster_size, image_size, table_size,
- backing_file, backing_fmt, errp);
+ backing_file, backing_fmt, opts, errp);
finish:
g_free(backing_file);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index dacf4fb..825a0c8 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -55,6 +55,9 @@
#include <linux/cdrom.h>
#include <linux/fd.h>
#include <linux/fs.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
#endif
#ifdef CONFIG_FIEMAP
#include <linux/fiemap.h>
@@ -1278,12 +1281,14 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
int fd;
int result = 0;
int64_t total_size = 0;
+ bool nocow = false;
strstart(filename, "file:", &filename);
/* Read out options */
total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
+ nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
@@ -1291,6 +1296,21 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
result = -errno;
error_setg_errno(errp, -result, "Could not create file");
} else {
+ if (nocow) {
+#ifdef __linux__
+ /* Set NOCOW flag to solve performance issue on fs like btrfs.
+ * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
+ * will be ignored since any failure of this operation should not
+ * block the left work.
+ */
+ int attr;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
+ attr |= FS_NOCOW_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ }
+#endif
+ }
+
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
@@ -1477,6 +1497,11 @@ static QemuOptsList raw_create_opts = {
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size"
},
+ {
+ .name = BLOCK_OPT_NOCOW,
+ .type = QEMU_OPT_BOOL,
+ .help = "Turn off copy-on-write (valid only on btrfs)"
+ },
{ /* end of list */ }
}
};
diff --git a/block/vdi.c b/block/vdi.c
index 01fe22e..197bd77 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -53,6 +53,13 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
+#ifdef __linux__
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
+#endif
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
@@ -683,6 +690,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
VdiHeader header;
size_t i;
size_t bmap_size;
+ bool nocow = false;
logout("\n");
@@ -699,6 +707,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
image_type = VDI_TYPE_STATIC;
}
#endif
+ nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
if (bytes > VDI_DISK_SIZE_MAX) {
result = -ENOTSUP;
@@ -716,6 +725,21 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
goto exit;
}
+ if (nocow) {
+#ifdef __linux__
+ /* Set NOCOW flag to solve performance issue on fs like btrfs.
+ * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
+ * be ignored since any failure of this operation should not block the
+ * left work.
+ */
+ int attr;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
+ attr |= FS_NOCOW_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ }
+#endif
+ }
+
/* We need enough blocks to store the given disk size,
so always round up. */
blocks = (bytes + block_size - 1) / block_size;
@@ -818,6 +842,11 @@ static QemuOptsList vdi_create_opts = {
.def_value_str = "off"
},
#endif
+ {
+ .name = BLOCK_OPT_NOCOW,
+ .type = QEMU_OPT_BOOL,
+ .help = "Turn off copy-on-write (valid only on btrfs)"
+ },
/* TODO: An additional option to set UUID values might be useful. */
{ /* end of list */ }
}
diff --git a/block/vmdk.c b/block/vmdk.c
index d0de019..27a78da 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1529,7 +1529,7 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
static int vmdk_create_extent(const char *filename, int64_t filesize,
bool flat, bool compress, bool zeroed_grain,
- Error **errp)
+ QemuOpts *opts, Error **errp)
{
int ret, i;
BlockDriverState *bs = NULL;
@@ -1539,7 +1539,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
uint32_t *gd_buf = NULL;
int gd_buf_size;
- ret = bdrv_create_file(filename, NULL, &local_err);
+ ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto exit;
@@ -1845,7 +1845,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
path, desc_filename);
if (vmdk_create_extent(ext_filename, size,
- flat, compress, zeroed_grain, errp)) {
+ flat, compress, zeroed_grain, opts, errp)) {
ret = -EINVAL;
goto exit;
}
diff --git a/block/vpc.c b/block/vpc.c
index 798d854..8b376a4 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -29,6 +29,13 @@
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
#endif
+#ifdef __linux__
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
+#endif
/**************************************************************/
@@ -751,6 +758,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
int64_t total_size;
int disk_type;
int ret = -EIO;
+ bool nocow = false;
/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
@@ -767,6 +775,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
} else {
disk_type = VHD_DYNAMIC;
}
+ nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
/* Create the file */
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
@@ -775,6 +784,21 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
goto out;
}
+ if (nocow) {
+#ifdef __linux__
+ /* Set NOCOW flag to solve performance issue on fs like btrfs.
+ * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
+ * be ignored since any failure of this operation should not block the
+ * left work.
+ */
+ int attr;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
+ attr |= FS_NOCOW_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ }
+#endif
+ }
+
/*
* Calculate matching total_size and geometry. Increase the number of
* sectors requested until we get enough (or fail). This ensures that
@@ -884,6 +908,11 @@ static QemuOptsList vpc_create_opts = {
"Type of virtual hard disk format. Supported formats are "
"{dynamic (default) | fixed} "
},
+ {
+ .name = BLOCK_OPT_NOCOW,
+ .type = QEMU_OPT_BOOL,
+ .help = "Turn off copy-on-write (valid only on btrfs)"
+ },
{ /* end of list */ }
}
};
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 53e77cf..eaf6e31 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -54,6 +54,7 @@
#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts"
#define BLOCK_OPT_ADAPTER_TYPE "adapter_type"
#define BLOCK_OPT_REDUNDANCY "redundancy"
+#define BLOCK_OPT_NOCOW "nocow"
typedef struct BdrvTrackedRequest {
BlockDriverState *bs;
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 88ec9bb..ad92c85 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -589,6 +589,22 @@ check -r all} is required, which may take some time.
This option can only be enabled if @code{compat=1.1} is specified.
+ at item nocow
+If this option is set to @code{on}, it will trun off COW of the file. It's only
+valid on btrfs, no effect on other file systems.
+
+Btrfs has low performance when hosting a VM image file, even more when the guest
+on the VM also using btrfs as file system. Turning off COW is a way to mitigate
+this bad performance. Generally there are two ways to turn off COW on btrfs:
+a) Disable it by mounting with nodatacow, then all newly created files will be
+NOCOW. b) For an empty file, add the NOCOW file attribute. That's what this option
+does.
+
+Note: this option is only valid to new or empty files. If there is an existing
+file which is COW and has data blocks already, it couldn't be changed to NOCOW
+by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
+the NOCOW flag is set or not (Capitabl 'C' is NOCOW flag).
+
@end table
@item qed
diff --git a/qemu-img.texi b/qemu-img.texi
index c68b541..8496f3b 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -474,6 +474,22 @@ check -r all} is required, which may take some time.
This option can only be enabled if @code{compat=1.1} is specified.
+ at item nocow
+If this option is set to @code{on}, it will trun off COW of the file. It's only
+valid on btrfs, no effect on other file systems.
+
+Btrfs has low performance when hosting a VM image file, even more when the guest
+on the VM also using btrfs as file system. Turning off COW is a way to mitigate
+this bad performance. Generally there are two ways to turn off COW on btrfs:
+a) Disable it by mounting with nodatacow, then all newly created files will be
+NOCOW. b) For an empty file, add the NOCOW file attribute. That's what this option
+does.
+
+Note: this option is only valid to new or empty files. If there is an existing
+file which is COW and has data blocks already, it couldn't be changed to NOCOW
+by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
+the NOCOW flag is set or not (Capitabl 'C' is NOCOW flag).
+
@end table
@item Other
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
index 28309a0..413e7ef 100644
--- a/tests/qemu-iotests/082.out
+++ b/tests/qemu-iotests/082.out
@@ -66,6 +66,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o ? TEST_DIR/t.qcow2 128M
Supported options:
@@ -77,6 +78,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 128M
Supported options:
@@ -88,6 +90,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 128M
Supported options:
@@ -99,6 +102,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 128M
Supported options:
@@ -110,6 +114,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 128M
Supported options:
@@ -121,6 +126,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 128M
Supported options:
@@ -132,6 +138,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 128M
Supported options:
@@ -143,6 +150,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,help' encryption=off cluster_size=65536 lazy_refcounts=off
@@ -247,6 +255,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -258,6 +267,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -269,6 +279,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -280,6 +291,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -291,6 +303,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -302,6 +315,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -313,6 +327,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
Supported options:
@@ -324,6 +339,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,help': No such file or directory
@@ -417,6 +433,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2
Supported options:
@@ -428,6 +445,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2
Supported options:
@@ -439,6 +457,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2
Supported options:
@@ -450,6 +469,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2
Supported options:
@@ -461,6 +481,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2
Supported options:
@@ -472,6 +493,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2
Supported options:
@@ -483,6 +505,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2
Supported options:
@@ -494,6 +517,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata)
lazy_refcounts Postpone refcount updates
+nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2
commit ef7c7ff6d4ca1955278af1bc5025f47044183250
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:28 2014 +0800
qom: add object_property_add_alias()
Sometimes an object needs to present a property which is actually on
another object, or it needs to provide an alias name for an existing
property.
Examples:
a.foo -> b.foo
a.old_name -> a.new_name
The new object_property_add_alias() API allows objects to alias a
property on the same object or another object. The source and target
names can be different.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/include/qom/object.h b/include/qom/object.h
index b882ccc..44c513f 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1231,6 +1231,26 @@ void object_property_add_uint64_ptr(Object *obj, const char *name,
const uint64_t *v, Error **Errp);
/**
+ * object_property_add_alias:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @target_obj: the object to forward property access to
+ * @target_name: the name of the property on the forwarded object
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Add an alias for a property on an object. This function will add a property
+ * of the same type as the forwarded property.
+ *
+ * The caller must ensure that <code>@target_obj</code> stays alive as long as
+ * this property exists. In the case of a child object or an alias on the same
+ * object this will be the case. For aliases to other objects the caller is
+ * responsible for taking a reference.
+ */
+void object_property_add_alias(Object *obj, const char *name,
+ Object *target_obj, const char *target_name,
+ Error **errp);
+
+/**
* object_child_foreach:
* @obj: the object whose children will be navigated
* @fn: the iterator function to be called
diff --git a/qom/object.c b/qom/object.c
index 3876618..a760514 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1550,6 +1550,57 @@ void object_property_add_uint64_ptr(Object *obj, const char *name,
NULL, NULL, (void *)v, errp);
}
+typedef struct {
+ Object *target_obj;
+ const char *target_name;
+} AliasProperty;
+
+static void property_get_alias(Object *obj, struct Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ AliasProperty *prop = opaque;
+
+ object_property_get(prop->target_obj, v, prop->target_name, errp);
+}
+
+static void property_set_alias(Object *obj, struct Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ AliasProperty *prop = opaque;
+
+ object_property_set(prop->target_obj, v, prop->target_name, errp);
+}
+
+static void property_release_alias(Object *obj, const char *name, void *opaque)
+{
+ AliasProperty *prop = opaque;
+
+ g_free(prop);
+}
+
+void object_property_add_alias(Object *obj, const char *name,
+ Object *target_obj, const char *target_name,
+ Error **errp)
+{
+ AliasProperty *prop;
+ ObjectProperty *target_prop;
+
+ target_prop = object_property_find(target_obj, target_name, errp);
+ if (!target_prop) {
+ return;
+ }
+
+ prop = g_malloc(sizeof(*prop));
+ prop->target_obj = target_obj;
+ prop->target_name = target_name;
+
+ object_property_add(obj, name, target_prop->type,
+ property_get_alias,
+ property_set_alias,
+ property_release_alias,
+ prop, errp);
+}
+
static void object_instance_init(Object *obj)
{
object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
commit 8698e110f8aa1cdf8ba1afdda8f2658333a4ab01
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Tue Jun 10 09:03:22 2014 +0200
virtio-blk: remove need for explicit x-data-plane=on option
The x-data-plane=on|off option is no longer useful because the
iothread=<iothread> option conveys the same information plus which
IOThread to use.
Do not delete x-data-plane=on|off yet as a convenience to people using
this legacy experimental option. We will drop it in QEMU 2.2.
Instead, turn on data-plane when either x-data-plane=on or
iothread=<iothread> are used. The following command-line uses
data-plane:
qemu -device virtio-blk-pci,iothread=foo,drive=drive0
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index f6e1a5d..4c5ba18 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -132,7 +132,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
*dataplane = NULL;
- if (!blk->data_plane) {
+ if (!blk->data_plane && !blk->iothread) {
return;
}
commit 1351d1ec89eabebc9fdff20451a62c413d7accc1
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Tue Jun 10 09:03:21 2014 +0200
qdev: drop iothread property type
The iothread property type is no longer used and can be removed.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 52c2f8a..8e140af 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -385,56 +385,6 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
nd->instantiated = 1;
}
-/* --- iothread --- */
-
-static char *print_iothread(void *ptr)
-{
- return iothread_get_id(ptr);
-}
-
-static int parse_iothread(DeviceState *dev, const char *str, void **ptr)
-{
- IOThread *iothread;
-
- iothread = iothread_find(str);
- if (!iothread) {
- return -ENOENT;
- }
- object_ref(OBJECT(iothread));
- *ptr = iothread;
- return 0;
-}
-
-static void get_iothread(Object *obj, struct Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- get_pointer(obj, v, opaque, print_iothread, name, errp);
-}
-
-static void set_iothread(Object *obj, struct Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- set_pointer(obj, v, opaque, parse_iothread, name, errp);
-}
-
-static void release_iothread(Object *obj, const char *name, void *opaque)
-{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
- IOThread **ptr = qdev_get_prop_ptr(dev, prop);
-
- if (*ptr) {
- object_unref(OBJECT(*ptr));
- }
-}
-
-PropertyInfo qdev_prop_iothread = {
- .name = "iothread",
- .get = get_iothread,
- .set = set_iothread,
- .release = release_iothread,
-};
-
static int qdev_add_one_global(QemuOpts *opts, void *opaque)
{
GlobalProperty *g;
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 3726bf3..77fe3a1 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -22,7 +22,6 @@ extern PropertyInfo qdev_prop_bios_chs_trans;
extern PropertyInfo qdev_prop_drive;
extern PropertyInfo qdev_prop_netdev;
extern PropertyInfo qdev_prop_vlan;
-extern PropertyInfo qdev_prop_iothread;
extern PropertyInfo qdev_prop_pci_devfn;
extern PropertyInfo qdev_prop_blocksize;
extern PropertyInfo qdev_prop_pci_host_devaddr;
@@ -143,8 +142,6 @@ extern PropertyInfo qdev_prop_arraylen;
DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers)
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
-#define DEFINE_PROP_IOTHREAD(_n, _s, _f) \
- DEFINE_PROP(_n, _s, _f, qdev_prop_iothread, IOThread *)
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
commit 467b3f33e9b094bf6db5a4d6e6905f077edca0fb
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Tue Jun 10 09:03:20 2014 +0200
virtio-blk: replace x-iothread with iothread link property
Up until now -device virtio-blk-pci,x-iothread=<id> was used to assign
an IOThread. This was a temporary solution while we cleaned up QOM link
properties.
This patch switches over to a QOM link property since it is now possible
to restrict the setter to unrealized instances and automatically unref
the IOThread when the virtio-blk-pci device is freed.
Since the "iothread" property is a QOM property and not a qdev property,
we must alias it explicitly for virtio-blk-pci, as well as CCW and
s390-virtio.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index b8d51bb..aec3146 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -784,12 +784,21 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
virtio_cleanup(vdev);
}
+static void virtio_blk_instance_init(Object *obj)
+{
+ VirtIOBlock *s = VIRTIO_BLK(obj);
+
+ object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
+ (Object **)&s->blk.iothread,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
+}
+
static Property virtio_blk_properties[] = {
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, blk.conf),
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, blk.conf),
DEFINE_PROP_STRING("serial", VirtIOBlock, blk.serial),
DEFINE_PROP_BIT("config-wce", VirtIOBlock, blk.config_wce, 0, true),
- DEFINE_PROP_IOTHREAD("x-iothread", VirtIOBlock, blk.iothread),
#ifdef __linux__
DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
#endif
@@ -821,6 +830,7 @@ static const TypeInfo virtio_device_info = {
.name = TYPE_VIRTIO_BLK,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBlock),
+ .instance_init = virtio_blk_instance_init,
.class_init = virtio_blk_class_init,
};
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 3438a88..c0dc365 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -181,6 +181,8 @@ static void s390_virtio_blk_instance_init(Object *obj)
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
object_unref(OBJECT(&dev->vdev));
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
+ &error_abort);
}
static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 0553fea..c279968 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -815,6 +815,8 @@ static void virtio_ccw_blk_instance_init(Object *obj)
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
object_unref(OBJECT(&dev->vdev));
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
+ &error_abort);
}
static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index d41b864..3c42cda 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1103,6 +1103,8 @@ static void virtio_blk_pci_instance_init(Object *obj)
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
object_unref(OBJECT(&dev->vdev));
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
+ &error_abort);
}
static const TypeInfo virtio_blk_pci_info = {
commit 32a877e4059ad7fd428bdd31d3e954fed72fa21b
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:36 2014 +0800
virtio-blk: move qdev properties into virtio-blk.c
There is no need to make DEFINE_VIRTIO_BLK_PROPERTIES() public. Inline
it into virtio-blk.c so it cannot be used by mistake from other source
files.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index f1a667c..b8d51bb 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -785,7 +785,17 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
}
static Property virtio_blk_properties[] = {
- DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlock, blk),
+ DEFINE_BLOCK_PROPERTIES(VirtIOBlock, blk.conf),
+ DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, blk.conf),
+ DEFINE_PROP_STRING("serial", VirtIOBlock, blk.serial),
+ DEFINE_PROP_BIT("config-wce", VirtIOBlock, blk.config_wce, 0, true),
+ DEFINE_PROP_IOTHREAD("x-iothread", VirtIOBlock, blk.iothread),
+#ifdef __linux__
+ DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
+#endif
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+ DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false),
+#endif
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 52e5add..223530e 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -155,29 +155,6 @@ typedef struct VirtIOBlockReq {
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
-#ifdef __linux__
-#define DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field) \
- DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true),
-#else
-#define DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field)
-#endif
-
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-#define DEFINE_VIRTIO_BLK_PROPERTIES_DATA_PLANE(_state, _field) \
- DEFINE_PROP_BIT("x-data-plane", _state, _field.data_plane, 0, false),
-#else
-#define DEFINE_VIRTIO_BLK_PROPERTIES_DATA_PLANE(_state, _field)
-#endif
-
-#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \
- DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field) \
- DEFINE_VIRTIO_BLK_PROPERTIES_DATA_PLANE(_state, _field) \
- DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \
- DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \
- DEFINE_PROP_STRING("serial", _state, _field.serial), \
- DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \
- DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread)
-
int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
VirtQueueElement *elem);
commit c5d49db4469dfc0cc7f4c01dfb4ed4e8b96bdbcd
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:35 2014 +0800
virtio: fix virtio-blk child refcount in transports
object_initialize() leaves the object with a refcount of 1.
object_property_add_child() adds its own reference which is dropped
again when the property is deleted.
The upshot of this is that we always have a refcount >= 1. Upon hot
unplug the virtio-blk child is not finalized!
Drop our reference after the child property has been added to the
parent.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 38984ab..3438a88 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -179,6 +179,7 @@ static void s390_virtio_blk_instance_init(Object *obj)
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+ object_unref(OBJECT(&dev->vdev));
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
}
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 9fa6f32..0553fea 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -813,6 +813,7 @@ static void virtio_ccw_blk_instance_init(Object *obj)
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+ object_unref(OBJECT(&dev->vdev));
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 7359d8d..d41b864 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1101,6 +1101,7 @@ static void virtio_blk_pci_instance_init(Object *obj)
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+ object_unref(OBJECT(&dev->vdev));
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
}
commit f7fedda84a8eb316c99a9de647c4844b862a7b38
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:34 2014 +0800
virtio-blk: drop virtio_blk_set_conf()
This function is no longer used since parent objects now use child
aliases to set the VirtIOBlkConf directly.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index e59ebc9..f1a667c 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -677,12 +677,6 @@ static const BlockDevOps virtio_block_ops = {
.resize_cb = virtio_blk_resize,
};
-void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk)
-{
- VirtIOBlock *s = VIRTIO_BLK(dev);
- memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
-}
-
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
/* Disable dataplane thread during live migration since it does not
* update the dirty memory bitmap yet.
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 1d80bcc..52e5add 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -178,8 +178,6 @@ typedef struct VirtIOBlockReq {
DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \
DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread)
-void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk);
-
int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
VirtQueueElement *elem);
commit caffdac363801cd2cf2bf01ad013a8c1e1e43800
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:33 2014 +0800
virtio-blk: use aliases instead of duplicate qdev properties
virtio-blk-pci, virtio-blk-s390, and virtio-blk-ccw all duplicate the
qdev properties of their VirtIOBlock child. This approach does not work
well with string or pointer properties since we must be careful about
leaking or double-freeing them.
Use the QOM alias property to forward property accesses to the
VirtIOBlock child. This way no duplication is necessary.
Remember to stop calling virtio_blk_set_conf() so that we don't clobber
the values already set on the VirtIOBlock instance.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 7c8c81b..38984ab 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -167,7 +167,6 @@ static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
{
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- virtio_blk_set_conf(vdev, &(dev->blk));
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) {
return -1;
@@ -180,6 +179,7 @@ static void s390_virtio_blk_instance_init(Object *obj)
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
}
static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
@@ -513,18 +513,11 @@ static const TypeInfo s390_virtio_net = {
.class_init = s390_virtio_net_class_init,
};
-static Property s390_virtio_blk_properties[] = {
- DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkS390, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
k->init = s390_virtio_blk_init;
- dc->props = s390_virtio_blk_properties;
}
static const TypeInfo s390_virtio_blk = {
diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h
index ac81bd8..ffd0df7 100644
--- a/hw/s390x/s390-virtio-bus.h
+++ b/hw/s390x/s390-virtio-bus.h
@@ -124,7 +124,6 @@ void s390_virtio_reset_idx(VirtIOS390Device *dev);
typedef struct VirtIOBlkS390 {
VirtIOS390Device parent_obj;
VirtIOBlock vdev;
- VirtIOBlkConf blk;
} VirtIOBlkS390;
/* virtio-scsi-s390 */
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index d7ff0a0..9fa6f32 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -800,7 +800,6 @@ static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
{
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- virtio_blk_set_conf(vdev, &(dev->blk));
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) {
return -1;
@@ -814,6 +813,7 @@ static void virtio_ccw_blk_instance_init(Object *obj)
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
}
static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
@@ -1400,7 +1400,6 @@ static const TypeInfo virtio_ccw_net = {
static Property virtio_ccw_blk_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
- DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index b8b8a8a..5a1f16e 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -144,7 +144,6 @@ typedef struct VHostSCSICcw {
typedef struct VirtIOBlkCcw {
VirtioCcwDevice parent_obj;
VirtIOBlock vdev;
- VirtIOBlkConf blk;
} VirtIOBlkCcw;
/* virtio-balloon-ccw */
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 653d74e..7359d8d 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1067,7 +1067,6 @@ static Property virtio_blk_pci_properties[] = {
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1075,7 +1074,6 @@ static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
{
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- virtio_blk_set_conf(vdev, &(dev->blk));
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
if (qdev_init(vdev) < 0) {
return -1;
@@ -1103,6 +1101,7 @@ static void virtio_blk_pci_instance_init(Object *obj)
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
}
static const TypeInfo virtio_blk_pci_info = {
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index dc332ae..1cea157 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -131,7 +131,6 @@ struct VHostSCSIPCI {
struct VirtIOBlkPCI {
VirtIOPCIProxy parent_obj;
VirtIOBlock vdev;
- VirtIOBlkConf blk;
};
/*
commit 67cc7e0aaca835ed68cf3bd34f4d51a21232792f
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:32 2014 +0800
qdev: add qdev_alias_all_properties()
The qdev_alias_all_properties() function creates QOM alias properties
for each qdev property on a DeviceState. This is useful for parent
objects that wish to forward property accesses to their children.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index d1eba3c..732e729 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -780,6 +780,27 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
}
}
+/* @qdev_alias_all_properties - Add alias properties to the source object for
+ * all qdev properties on the target DeviceState.
+ */
+void qdev_alias_all_properties(DeviceState *target, Object *source)
+{
+ ObjectClass *class;
+ Property *prop;
+
+ class = object_get_class(OBJECT(target));
+ do {
+ DeviceClass *dc = DEVICE_CLASS(class);
+
+ for (prop = dc->props; prop && prop->name; prop++) {
+ object_property_add_alias(source, prop->name,
+ OBJECT(target), prop->name,
+ &error_abort);
+ }
+ class = object_class_get_parent(class);
+ } while (class != object_class_by_name(TYPE_DEVICE));
+}
+
static bool device_get_realized(Object *obj, Error **errp)
{
DeviceState *dev = DEVICE(obj);
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index c962b6b..3726bf3 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -193,6 +193,8 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
*/
void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
+void qdev_alias_all_properties(DeviceState *target, Object *source);
+
/**
* @qdev_prop_set_after_realize:
* @dev: device
commit ee512c6f21b2f76ae923e3a4cabbd58899ff7ae1
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:31 2014 +0800
virtio-blk: move x-data-plane qdev property to virtio-blk.h
Move the x-data-plane property. Originally it was outside since not
every transport may wish to support dataplane. But that makes little
sense when we have a dedicated CONFIG_VIRTIO_BLK_DATA_PLANE ifdef
already.
This move makes it easier to switch to property aliases in the next
patch.
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 05656a2..d7ff0a0 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -1403,9 +1403,6 @@ static Property virtio_ccw_blk_properties[] = {
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
- DEFINE_PROP_BIT("x-data-plane", VirtIOBlkCcw, blk.data_plane, 0, false),
-#endif
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 317324f..653d74e 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1066,9 +1066,6 @@ static Property virtio_blk_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
- DEFINE_PROP_BIT("x-data-plane", VirtIOBlkPCI, blk.data_plane, 0, false),
-#endif
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk),
DEFINE_PROP_END_OF_LIST(),
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index ee43f7a..1d80bcc 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -162,8 +162,16 @@ typedef struct VirtIOBlockReq {
#define DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field)
#endif
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+#define DEFINE_VIRTIO_BLK_PROPERTIES_DATA_PLANE(_state, _field) \
+ DEFINE_PROP_BIT("x-data-plane", _state, _field.data_plane, 0, false),
+#else
+#define DEFINE_VIRTIO_BLK_PROPERTIES_DATA_PLANE(_state, _field)
+#endif
+
#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \
DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field) \
+ DEFINE_VIRTIO_BLK_PROPERTIES_DATA_PLANE(_state, _field) \
DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \
DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \
DEFINE_PROP_STRING("serial", _state, _field.serial), \
commit a9968c77d5a56211ae22be2e6a1dcb07f2016010
Author: Cornelia Huck <cornelia.huck at de.ibm.com>
Date: Wed Jun 18 17:58:30 2014 +0800
dataplane: bail out on unsupported transport
If the virtio transport does not support notifiers (like s390-virtio),
we can't use dataplane. Bail out early and let the user know what is
wrong.
Signed-off-by: Cornelia Huck <cornelia.huck at de.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 09bd2c7..f6e1a5d 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -127,6 +127,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
VirtIOBlockDataPlane *s;
VirtIOBlock *vblk = VIRTIO_BLK(vdev);
Error *local_err = NULL;
+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
*dataplane = NULL;
@@ -134,6 +136,14 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
return;
}
+ /* Don't try if transport does not support notifiers. */
+ if (!k->set_guest_notifiers || !k->set_host_notifier) {
+ error_setg(errp,
+ "device is incompatible with x-data-plane "
+ "(transport does not support notifiers)");
+ return;
+ }
+
/* If dataplane is (re-)enabled while the guest is running there could be
* block jobs that can conflict.
*/
commit dc80ca6cd6cafdee174af3c883d85e19b7fd70a5
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date: Wed Jun 18 17:58:29 2014 +0800
virtio-blk: avoid qdev property definition duplication
It becomes unwiedly to duplicate all virtio-blk qdev property
definitions due to an #ifdef. The C preprocessor syntax makes it a
little hard to resolve this cleanly but we can extract the #ifdef and
call a macro it defines later.
Avoiding duplication is important since it will only get worse when we
move the x-data-plane qdev property here too. We'd have a combinatorial
explosion since x-data-plane has its own #ifdef.
Suggested-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index d0fb26f..ee43f7a 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -156,21 +156,19 @@ typedef struct VirtIOBlockReq {
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
#ifdef __linux__
-#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \
- DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \
- DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \
- DEFINE_PROP_STRING("serial", _state, _field.serial), \
- DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \
- DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true), \
- DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread)
+#define DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field) \
+ DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true),
#else
+#define DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field)
+#endif
+
#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \
+ DEFINE_VIRTIO_BLK_PROPERTIES_LINUX(_state, _field) \
DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \
DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \
DEFINE_PROP_STRING("serial", _state, _field.serial), \
DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \
DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread)
-#endif /* __linux__ */
void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk);
More information about the Spice-commits
mailing list