diff options
author | Jason Wang | 2013-01-30 12:12:35 +0100 |
---|---|---|
committer | Anthony Liguori | 2013-02-01 18:03:02 +0100 |
commit | a9f98bb5ebe6fb1869321dcc58e72041ae626ad8 (patch) | |
tree | fe66f183e45763207d12f5298fb8d8d9e3911228 /hw/vhost.c | |
parent | tap: multiqueue support (diff) | |
download | qemu-a9f98bb5ebe6fb1869321dcc58e72041ae626ad8.tar.gz qemu-a9f98bb5ebe6fb1869321dcc58e72041ae626ad8.tar.xz qemu-a9f98bb5ebe6fb1869321dcc58e72041ae626ad8.zip |
vhost: multiqueue support
This patch lets vhost support multiqueue. The idea is simple, just launching
multiple threads of vhost and let each of vhost thread processing a subset of
the virtqueues of the device. After this change each emulated device can have
multiple vhost threads as its backend.
To do this, a virtqueue index were introduced to record to first virtqueue that
will be handled by this vhost_net device. Based on this and nvqs, vhost could
calculate its relative index to setup vhost_net device.
Since we may have many vhost/net devices for a virtio-net device. The setting of
guest notifiers were moved out of the starting/stopping of a specific vhost
thread. The vhost_net_{start|stop}() were renamed to
vhost_net_{start|stop}_one(), and a new vhost_net_{start|stop}() were introduced
to configure the guest notifiers and start/stop all vhost/vhost_net devices.
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/vhost.c')
-rw-r--r-- | hw/vhost.c | 82 |
1 files changed, 36 insertions, 46 deletions
diff --git a/hw/vhost.c b/hw/vhost.c index 0dd2a9aa40..8d41fdb53f 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -616,14 +616,17 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, { hwaddr s, l, a; int r; + int vhost_vq_index = idx - dev->vq_index; struct vhost_vring_file file = { - .index = idx, + .index = vhost_vq_index }; struct vhost_vring_state state = { - .index = idx, + .index = vhost_vq_index }; struct VirtQueue *vvq = virtio_get_queue(vdev, idx); + assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); + vq->num = state.num = virtio_queue_get_num(vdev, idx); r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state); if (r) { @@ -666,11 +669,12 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, goto fail_alloc_ring; } - r = vhost_virtqueue_set_addr(dev, vq, idx, dev->log_enabled); + r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled); if (r < 0) { r = -errno; goto fail_alloc; } + file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file); if (r) { @@ -706,9 +710,10 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, unsigned idx) { struct vhost_vring_state state = { - .index = idx, + .index = idx - dev->vq_index }; int r; + assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state); if (r < 0) { fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r); @@ -864,7 +869,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) } for (i = 0; i < hdev->nvqs; ++i) { - r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, true); + r = vdev->binding->set_host_notifier(vdev->binding_opaque, + hdev->vq_index + i, + true); if (r < 0) { fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r); goto fail_vq; @@ -874,7 +881,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) return 0; fail_vq: while (--i >= 0) { - r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false); + r = vdev->binding->set_host_notifier(vdev->binding_opaque, + hdev->vq_index + i, + false); if (r < 0) { fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r); fflush(stderr); @@ -895,7 +904,9 @@ 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); + r = vdev->binding->set_host_notifier(vdev->binding_opaque, + hdev->vq_index + i, + false); if (r < 0) { fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r); fflush(stderr); @@ -909,8 +920,9 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) */ bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n) { - struct vhost_virtqueue *vq = hdev->vqs + n; + struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index; assert(hdev->started); + assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs); return event_notifier_test_and_clear(&vq->masked_notifier); } @@ -919,15 +931,16 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, bool mask) { struct VirtQueue *vvq = virtio_get_queue(vdev, n); - int r; + int r, index = n - hdev->vq_index; assert(hdev->started); + assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs); struct vhost_vring_file file = { - .index = n, + .index = index }; if (mask) { - file.fd = event_notifier_get_fd(&hdev->vqs[n].masked_notifier); + file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier); } else { file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); } @@ -942,20 +955,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->started = true; - if (!vdev->binding->set_guest_notifiers) { - fprintf(stderr, "binding does not support guest notifiers\n"); - r = -ENOSYS; - goto fail; - } - - r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, - hdev->nvqs, - true); - if (r < 0) { - fprintf(stderr, "Error binding guest notifier: %d\n", -r); - goto fail_notifiers; - } - r = vhost_dev_set_features(hdev, hdev->log_enabled); if (r < 0) { goto fail_features; @@ -967,9 +966,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } for (i = 0; i < hdev->nvqs; ++i) { r = vhost_virtqueue_start(hdev, - vdev, - hdev->vqs + i, - i); + vdev, + hdev->vqs + i, + hdev->vq_index + i); if (r < 0) { goto fail_vq; } @@ -992,15 +991,13 @@ fail_log: fail_vq: while (--i >= 0) { vhost_virtqueue_stop(hdev, - vdev, - hdev->vqs + i, - i); + vdev, + hdev->vqs + i, + hdev->vq_index + i); } + i = hdev->nvqs; fail_mem: fail_features: - vdev->binding->set_guest_notifiers(vdev->binding_opaque, hdev->nvqs, false); -fail_notifiers: -fail: hdev->started = false; return r; @@ -1009,29 +1006,22 @@ fail: /* Host notifiers must be enabled at this point. */ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) { - int i, r; + int i; for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_stop(hdev, - vdev, - hdev->vqs + i, - i); + vdev, + hdev->vqs + i, + hdev->vq_index + i); } for (i = 0; i < hdev->n_mem_sections; ++i) { vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i], 0, (hwaddr)~0x0ull); } - r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, - hdev->nvqs, - false); - if (r < 0) { - fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); - fflush(stderr); - } - assert (r >= 0); hdev->started = false; g_free(hdev->log); hdev->log = NULL; hdev->log_size = 0; } + |