From ba7eadb5927633d487064b518bf6fd001369e30c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:16 +0200 Subject: virtio-net: handle virtio_net_handle_ctrl() error This error is caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Also we detach the element from the virtqueue and free it. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 6b8ae2c1fa..a1584e1e67 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -880,6 +880,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_OK; } + static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = VIRTIO_NET(vdev); @@ -897,8 +898,10 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { - error_report("virtio-net ctrl missing headers"); - exit(1); + virtio_error(vdev, "virtio-net ctrl missing headers"); + virtqueue_detach_element(vq, elem, 0); + g_free(elem); + break; } iov_cnt = elem->out_num; -- cgit v1.2.3-55-g7522 From ba10b9c0038e201d7ea28a9e3908928439ff7fa4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:24 +0200 Subject: virtio-net: handle virtio_net_receive() errors All these errors are caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Also we detach the element from the virtqueue and free it. Signed-off-by: Greg Kurz Reviewed-by: Cornelia Huck Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a1584e1e67..5c0b2e0db5 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1130,21 +1130,24 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); if (!elem) { - if (i == 0) - return -1; - error_report("virtio-net unexpected empty queue: " - "i %zd mergeable %d offset %zd, size %zd, " - "guest hdr len %zd, host hdr len %zd " - "guest features 0x%" PRIx64, - i, n->mergeable_rx_bufs, offset, size, - n->guest_hdr_len, n->host_hdr_len, - vdev->guest_features); - exit(1); + if (i) { + virtio_error(vdev, "virtio-net unexpected empty queue: " + "i %zd mergeable %d offset %zd, size %zd, " + "guest hdr len %zd, host hdr len %zd " + "guest features 0x%" PRIx64, + i, n->mergeable_rx_bufs, offset, size, + n->guest_hdr_len, n->host_hdr_len, + vdev->guest_features); + } + return -1; } if (elem->in_num < 1) { - error_report("virtio-net receive queue contains no in buffers"); - exit(1); + virtio_error(vdev, + "virtio-net receive queue contains no in buffers"); + virtqueue_detach_element(q->rx_vq, elem, 0); + g_free(elem); + return -1; } sg = elem->in_sg; -- cgit v1.2.3-55-g7522 From fa5e56c2a73501427203c34d702fccc2fbcb5eab Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:32 +0200 Subject: virtio-net: handle virtio_net_flush_tx() errors All these errors are caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Also we detach the element from the virtqueue and free it. If this happens, virtio_net_flush_tx() also returns -EINVAL, so that all callers can stop processing the virtqueue immediatly. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 5c0b2e0db5..ca1b46956b 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1249,15 +1249,19 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) out_num = elem->out_num; out_sg = elem->out_sg; if (out_num < 1) { - error_report("virtio-net header not in first element"); - exit(1); + virtio_error(vdev, "virtio-net header not in first element"); + virtqueue_detach_element(q->tx_vq, elem, 0); + g_free(elem); + return -EINVAL; } if (n->has_vnet_hdr) { if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < n->guest_hdr_len) { - error_report("virtio-net header incorrect"); - exit(1); + virtio_error(vdev, "virtio-net header incorrect"); + virtqueue_detach_element(q->tx_vq, elem, 0); + g_free(elem); + return -EINVAL; } if (n->needs_vnet_hdr_swap) { virtio_net_hdr_swap(vdev, (void *) &mhdr); @@ -1325,7 +1329,9 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) virtio_queue_set_notification(vq, 1); timer_del(q->tx_timer); q->tx_waiting = 0; - virtio_net_flush_tx(q); + if (virtio_net_flush_tx(q) == -EINVAL) { + return; + } } else { timer_mod(q->tx_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); @@ -1396,8 +1402,9 @@ static void virtio_net_tx_bh(void *opaque) } ret = virtio_net_flush_tx(q); - if (ret == -EBUSY) { - return; /* Notification re-enable handled by tx_complete */ + if (ret == -EBUSY || ret == -EINVAL) { + return; /* Notification re-enable handled by tx_complete or device + * broken */ } /* If we flush a full burst of packets, assume there are @@ -1412,7 +1419,10 @@ static void virtio_net_tx_bh(void *opaque) * anything that may have come in while we weren't looking. If * we find something, assume the guest is still active and reschedule */ virtio_queue_set_notification(q->tx_vq, 1); - if (virtio_net_flush_tx(q) > 0) { + ret = virtio_net_flush_tx(q); + if (ret == -EINVAL) { + return; + } else if (ret > 0) { virtio_queue_set_notification(q->tx_vq, 0); qemu_bh_schedule(q->tx_bh); q->tx_waiting = 1; -- cgit v1.2.3-55-g7522 From 4d45dcfbf2bb606316e13f70aeb3f0709384f9f5 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:41 +0200 Subject: virtio-net: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index ca1b46956b..b2198a550e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -11,6 +11,8 @@ * */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qemu/iov.h" #include "hw/virtio/virtio.h" @@ -1514,17 +1516,6 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) virtio_net_set_queues(n); } -static void virtio_net_save(QEMUFile *f, void *opaque, size_t size) -{ - VirtIONet *n = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(n); - - /* At this point, backend must be stopped, otherwise - * it might keep writing to memory. */ - assert(!n->vhost_started); - virtio_save(vdev, f); -} - static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) { VirtIONet *n = VIRTIO_NET(vdev); @@ -1560,14 +1551,6 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) } } -static int virtio_net_load(QEMUFile *f, void *opaque, size_t size) -{ - VirtIONet *n = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(n); - - return virtio_load(vdev, f, VIRTIO_NET_VM_VERSION); -} - static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, int version_id) { @@ -1870,8 +1853,25 @@ static void virtio_net_instance_init(Object *obj) DEVICE(n), NULL); } -VMSTATE_VIRTIO_DEVICE(net, VIRTIO_NET_VM_VERSION, virtio_net_load, - virtio_net_save); +static void virtio_net_pre_save(void *opaque) +{ + VirtIONet *n = opaque; + + /* At this point, backend must be stopped, otherwise + * it might keep writing to memory. */ + assert(!n->vhost_started); +} + +static const VMStateDescription vmstate_virtio_net = { + .name = "virtio-net", + .minimum_version_id = VIRTIO_NET_VM_VERSION, + .version_id = VIRTIO_NET_VM_VERSION, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, + .pre_save = virtio_net_pre_save, +}; static Property virtio_net_properties[] = { DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true), -- cgit v1.2.3-55-g7522 From 5705653ff8666ffb247971361904f902aa033351 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:50 +0200 Subject: virtio: cleanup VMSTATE_VIRTIO_DEVICE Now all the usages of the old version of VMSTATE_VIRTIO_DEVICE are gone, so we can get rid of the conditionals, and the old macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 2 -- hw/block/virtio-blk.c | 2 -- hw/char/virtio-serial-bus.c | 2 -- hw/display/virtio-gpu.c | 2 -- hw/input/virtio-input.c | 2 -- hw/net/virtio-net.c | 2 -- hw/scsi/virtio-scsi.c | 2 -- hw/virtio/vhost-vsock.c | 2 -- hw/virtio/virtio-balloon.c | 2 -- hw/virtio/virtio-rng.c | 2 -- hw/virtio/virtio.c | 6 ------ include/hw/virtio/virtio.h | 27 --------------------------- 12 files changed, 53 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 526ec7d08f..e98dd0c4c0 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -11,8 +11,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "hw/virtio/virtio.h" #include "qemu/sockets.h" diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 10c5794063..37fe72bdcd 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -11,8 +11,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index c9b0fc8325..7975c2cda1 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -18,8 +18,6 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 4fcd63cdb6..fa6fd0e53f 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -11,8 +11,6 @@ * See the COPYING file in the top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/iov.h" diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 5e31033c4d..b678ee9f20 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -4,8 +4,6 @@ * top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index b2198a550e..06bfe4bcc9 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -11,8 +11,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qemu/iov.h" #include "hw/virtio/virtio.h" diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 9473e1099f..4762f05274 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -13,8 +13,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "standard-headers/linux/virtio_ids.h" diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 99cb216ae1..b4815629e1 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -11,8 +11,6 @@ * top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include #include "qemu/osdep.h" #include "standard-headers/linux/virtio_vsock.h" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 2c68d3dc5f..1d77028236 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -13,8 +13,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qemu/iov.h" #include "qemu/timer.h" diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 62867d141e..9639f4e89b 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -9,8 +9,6 @@ * top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 62b9c002ff..d48d1a98a7 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1639,12 +1639,6 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) vmstate_save_state(f, &vmstate_virtio, vdev, NULL); } -/* A wrapper for use as a VMState .put function */ -void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size) -{ - virtio_save(VIRTIO_DEVICE(opaque), f); -} - /* A wrapper for use as a VMState .put function */ static void virtio_device_put(QEMUFile *f, void *opaque, size_t size) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 929fa92c32..b913aac455 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -177,12 +177,9 @@ bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_save(VirtIODevice *vdev, QEMUFile *f); -void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size); extern const VMStateInfo virtio_vmstate_info; -#ifdef VMSTATE_VIRTIO_DEVICE_USE_NEW - #define VMSTATE_VIRTIO_DEVICE \ { \ .name = "virtio", \ @@ -190,30 +187,6 @@ extern const VMStateInfo virtio_vmstate_info; .flags = VMS_SINGLE, \ } -#else -/* TODO remove conditional as soon as all users are converted */ - -#define VMSTATE_VIRTIO_DEVICE(devname, v, getf, putf) \ - static const VMStateDescription vmstate_virtio_ ## devname = { \ - .name = "virtio-" #devname , \ - .minimum_version_id = v, \ - .version_id = v, \ - .fields = (VMStateField[]) { \ - { \ - .name = "virtio", \ - .info = &(const VMStateInfo) {\ - .name = "virtio", \ - .get = getf, \ - .put = putf, \ - }, \ - .flags = VMS_SINGLE, \ - }, \ - VMSTATE_END_OF_LIST() \ - } \ - } - -#endif - int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); void virtio_notify_config(VirtIODevice *vdev); -- cgit v1.2.3-55-g7522