mirror of https://github.com/xqemu/xqemu.git
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 <groug@kaod.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
ba10b9c003
commit
fa5e56c2a7
|
@ -1249,15 +1249,19 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||||
out_num = elem->out_num;
|
out_num = elem->out_num;
|
||||||
out_sg = elem->out_sg;
|
out_sg = elem->out_sg;
|
||||||
if (out_num < 1) {
|
if (out_num < 1) {
|
||||||
error_report("virtio-net header not in first element");
|
virtio_error(vdev, "virtio-net header not in first element");
|
||||||
exit(1);
|
virtqueue_detach_element(q->tx_vq, elem, 0);
|
||||||
|
g_free(elem);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n->has_vnet_hdr) {
|
if (n->has_vnet_hdr) {
|
||||||
if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
|
if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
|
||||||
n->guest_hdr_len) {
|
n->guest_hdr_len) {
|
||||||
error_report("virtio-net header incorrect");
|
virtio_error(vdev, "virtio-net header incorrect");
|
||||||
exit(1);
|
virtqueue_detach_element(q->tx_vq, elem, 0);
|
||||||
|
g_free(elem);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (n->needs_vnet_hdr_swap) {
|
if (n->needs_vnet_hdr_swap) {
|
||||||
virtio_net_hdr_swap(vdev, (void *) &mhdr);
|
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);
|
virtio_queue_set_notification(vq, 1);
|
||||||
timer_del(q->tx_timer);
|
timer_del(q->tx_timer);
|
||||||
q->tx_waiting = 0;
|
q->tx_waiting = 0;
|
||||||
virtio_net_flush_tx(q);
|
if (virtio_net_flush_tx(q) == -EINVAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
timer_mod(q->tx_timer,
|
timer_mod(q->tx_timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
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);
|
ret = virtio_net_flush_tx(q);
|
||||||
if (ret == -EBUSY) {
|
if (ret == -EBUSY || ret == -EINVAL) {
|
||||||
return; /* Notification re-enable handled by tx_complete */
|
return; /* Notification re-enable handled by tx_complete or device
|
||||||
|
* broken */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we flush a full burst of packets, assume there are
|
/* 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
|
* anything that may have come in while we weren't looking. If
|
||||||
* we find something, assume the guest is still active and reschedule */
|
* we find something, assume the guest is still active and reschedule */
|
||||||
virtio_queue_set_notification(q->tx_vq, 1);
|
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);
|
virtio_queue_set_notification(q->tx_vq, 0);
|
||||||
qemu_bh_schedule(q->tx_bh);
|
qemu_bh_schedule(q->tx_bh);
|
||||||
q->tx_waiting = 1;
|
q->tx_waiting = 1;
|
||||||
|
|
Loading…
Reference in New Issue