[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] vhost-net: cleanup host notifiers at last step
From: |
Ryan Harper |
Subject: |
Re: [Qemu-devel] [PATCH] vhost-net: cleanup host notifiers at last step |
Date: |
Fri, 26 Aug 2011 13:29:23 -0500 |
User-agent: |
Mutt/1.5.6+20040907i |
* Michael S. Tsirkin <address@hidden> [2011-08-25 05:11]:
> When the vhost notifier is disabled, the userspace handler runs
> immediately: virtio_pci_set_host_notifier_internal might
> call virtio_queue_notify_vq.
> Since the VQ state and the tap backend state aren't
> recovered yet, this causes
> "Guest moved used index from XXX to YYY" assertions.
When do we see this message? I'm just wondering how we can test this?
>
> The solution is to split out host notifier handling
> from vhost VQ setup and disable notifiers as our last step
> when we stop vhost-net. For symmetry enable them first thing
> on start.
>
> Signed-off-by: Michael S. Tsirkin <address@hidden>
> ---
> hw/vhost.c | 74 +++++++++++++++++++++++++++++++++++++++++--------------
> hw/vhost.h | 2 +
> hw/vhost_net.c | 16 ++++++++++--
> 3 files changed, 70 insertions(+), 22 deletions(-)
>
> diff --git a/hw/vhost.c b/hw/vhost.c
> index 1886067..0870cb7 100644
> --- a/hw/vhost.c
> +++ b/hw/vhost.c
> @@ -515,11 +515,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
> };
> struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
>
> - if (!vdev->binding->set_host_notifier) {
> - fprintf(stderr, "binding does not support host notifiers\n");
> - return -ENOSYS;
> - }
> -
> vq->num = state.num = virtio_queue_get_num(vdev, idx);
> r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
> if (r) {
> @@ -567,12 +562,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
> r = -errno;
> goto fail_alloc;
> }
> - r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
> - if (r < 0) {
> - fprintf(stderr, "Error binding host notifier: %d\n", -r);
> - goto fail_host_notifier;
> - }
> -
> file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
> r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
> if (r) {
> @@ -591,8 +580,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
>
> fail_call:
> fail_kick:
> - vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
> -fail_host_notifier:
> fail_alloc:
> cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev,
> idx),
> 0, 0);
> @@ -618,12 +605,6 @@ static void vhost_virtqueue_cleanup(struct vhost_dev
> *dev,
> .index = idx,
> };
> int r;
> - r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
> - if (r < 0) {
> - fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
> - fflush(stderr);
> - }
> - assert (r >= 0);
> r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
> if (r < 0) {
> fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
> @@ -697,6 +678,60 @@ bool vhost_dev_query(struct vhost_dev *hdev,
> VirtIODevice *vdev)
> hdev->force;
> }
>
> +/* Stop processing guest IO notifications in qemu.
> + * Start processing them in vhost in kernel.
> + */
> +int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
> +{
> + int i, r;
> + if (!vdev->binding->set_host_notifier) {
> + fprintf(stderr, "binding does not support host notifiers\n");
> + r = -ENOSYS;
> + goto fail;
> + }
> +
> + for (i = 0; i < hdev->nvqs; ++i) {
> + r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, true);
> + if (r < 0) {
> + fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i,
> -r);
> + goto fail_vq;
> + }
> + }
> +
> + return 0;
> +fail_vq:
> + while (--i >= 0) {
> + r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false);
> + if (r < 0) {
> + fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i,
> -r);
> + fflush(stderr);
> + }
> + assert (r >= 0);
> + }
> +fail:
> + return r;
> +}
> +
> +/* Stop processing guest IO notifications in vhost.
> + * Start processing them in qemu.
> + * This might actually run the qemu handlers right away,
> + * so virtio in qemu must be completely setup when this is called.
> + */
> +void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
> +{
> + int i, r;
> +
> + for (i = 0; i < hdev->nvqs; ++i) {
> + r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false);
> + if (r < 0) {
> + fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i,
> -r);
> + fflush(stderr);
> + }
> + assert (r >= 0);
> + }
> +}
> +
> +/* Host notifiers must be enabled at this point. */
> int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
> {
> int i, r;
> @@ -762,6 +797,7 @@ fail:
> return r;
> }
>
> +/* Host notifiers must be enabled at this point. */
> void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
> {
> int i, r;
> diff --git a/hw/vhost.h b/hw/vhost.h
> index c8c595a..c9452f0 100644
> --- a/hw/vhost.h
> +++ b/hw/vhost.h
> @@ -46,5 +46,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev);
> bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
> int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
> void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
> +int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
> +void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
>
> #endif
> diff --git a/hw/vhost_net.c b/hw/vhost_net.c
> index a559812..950a6b8 100644
> --- a/hw/vhost_net.c
> +++ b/hw/vhost_net.c
> @@ -139,16 +139,22 @@ int vhost_net_start(struct vhost_net *net,
> {
> struct vhost_vring_file file = { };
> int r;
> +
> + net->dev.nvqs = 2;
> + net->dev.vqs = net->vqs;
> +
> + r = vhost_dev_enable_notifiers(&net->dev, dev);
> + if (r < 0) {
> + goto fail_notifiers;
> + }
> if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
> tap_set_vnet_hdr_len(net->vc,
> sizeof(struct virtio_net_hdr_mrg_rxbuf));
> }
>
> - net->dev.nvqs = 2;
> - net->dev.vqs = net->vqs;
> r = vhost_dev_start(&net->dev, dev);
> if (r < 0) {
> - return r;
> + goto fail_start;
> }
>
> net->vc->info->poll(net->vc, false);
> @@ -173,6 +179,9 @@ fail:
> if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
> tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
> }
> +fail_start:
> + vhost_dev_disable_notifiers(&net->dev, dev);
> +fail_notifiers:
> return r;
> }
>
> @@ -190,6 +199,7 @@ void vhost_net_stop(struct vhost_net *net,
> if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
> tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
> }
> + vhost_dev_disable_notifiers(&net->dev, dev);
> }
>
> void vhost_net_cleanup(struct vhost_net *net)
> --
> 1.7.5.53.gc233e
--
Ryan Harper
Software Engineer; Linux Technology Center
IBM Corp., Austin, Tx
address@hidden