diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index f6fc639e88..2cb990997e 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -192,6 +192,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); while (i--) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } goto fail_guest_notifiers; } @@ -267,6 +268,7 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) for (i = 0; i < nvqs; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } /* Clean up guest notifier (irq) */ diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index add4b3f4a4..1c33322ba6 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -175,6 +175,7 @@ fail_vrings: aio_context_release(s->ctx); for (i = 0; i < vs->conf.num_queues + 2; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); fail_guest_notifiers: @@ -213,6 +214,7 @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev) for (i = 0; i < vs->conf.num_queues + 2; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } /* Clean up guest notifier (irq) */ diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 23b9e17675..56885aaf13 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1418,6 +1418,7 @@ fail_vq: error_report("vhost VQ %d notifier cleanup error: %d", i, -r); } assert (e >= 0); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); } virtio_device_release_ioeventfd(vdev); fail: @@ -1441,6 +1442,7 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) error_report("vhost VQ %d notifier cleanup failed: %d", i, -r); } assert (r >= 0); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); } virtio_device_release_ioeventfd(vdev); } diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 3042232daf..f9bc9ea46d 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -283,20 +283,26 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) r = k->ioeventfd_assign(proxy, notifier, n, true); if (r < 0) { error_report("%s: unable to assign ioeventfd: %d", __func__, r); - goto cleanup_event_notifier; + virtio_bus_cleanup_host_notifier(bus, n); } - return 0; } else { k->ioeventfd_assign(proxy, notifier, n, false); } -cleanup_event_notifier: + return r; +} + +void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n) +{ + VirtIODevice *vdev = virtio_bus_get_device(bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + /* Test and clear notifier after disabling event, * in case poll callback didn't have time to run. */ virtio_queue_host_notifier_read(notifier); event_notifier_cleanup(notifier); - return r; } static char *virtio_bus_get_dev_path(DeviceState *dev) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index d6002ee550..3667cd61fd 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2608,6 +2608,7 @@ assign_error: event_notifier_set_handler(&vq->host_notifier, NULL); r = virtio_bus_set_host_notifier(qbus, n, false); assert(r >= 0); + virtio_bus_cleanup_host_notifier(qbus, n); } return err; } @@ -2634,6 +2635,7 @@ static void virtio_device_stop_ioeventfd_impl(VirtIODevice *vdev) event_notifier_set_handler(&vq->host_notifier, NULL); r = virtio_bus_set_host_notifier(qbus, n, false); assert(r >= 0); + virtio_bus_cleanup_host_notifier(qbus, n); } } diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index a63c1d216d..ced3d2d2b0 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -148,5 +148,7 @@ int virtio_bus_grab_ioeventfd(VirtioBusState *bus); void virtio_bus_release_ioeventfd(VirtioBusState *bus); /* Switch from/to the generic ioeventfd handler */ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign); +/* Tell the bus that the ioeventfd handler is no longer required. */ +void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n); #endif /* VIRTIO_BUS_H */