Add I/O thread to handle I/O operations in virtio-blk. There is currently support for multiple virtio queues but the kernel side supports only one virtio queue. It's not too much of a performance impact and the ABI does support multiple queues there - So I've prefered to do it like that to keep it flexible. I/O performance itself doesn't increase much due to the patch, what changes is system responsiveness during I/O operations. On an unthreaded system, The VCPU is frozen up until the I/O request is complete. On the other hand, On a threaded system the VCPU is free to do other work or queue more I/O while waiting for the original I/O request to complete. Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> --- tools/kvm/virtio-blk.c | 61 ++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 56 insertions(+), 5 deletions(-) diff --git a/tools/kvm/virtio-blk.c b/tools/kvm/virtio-blk.c index 124ce95..029f753 100644 --- a/tools/kvm/virtio-blk.c +++ b/tools/kvm/virtio-blk.c @@ -30,9 +30,13 @@ struct blk_device { uint32_t guest_features; uint16_t config_vector; uint8_t status; + pthread_t io_thread; + pthread_mutex_t io_mutex; + pthread_cond_t io_cond; /* virtio queue */ uint16_t queue_selector; + uint64_t virtio_blk_queue_set_flags; struct virt_queue vqs[NUM_VIRT_QUEUES]; }; @@ -52,6 +56,9 @@ static struct blk_device blk_device = { * same applies to VIRTIO_BLK_F_BLK_SIZE */ .host_features = (1UL << VIRTIO_BLK_F_SEG_MAX), + + .io_mutex = PTHREAD_MUTEX_INITIALIZER, + .io_cond = PTHREAD_COND_INITIALIZER }; static bool virtio_blk_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count) @@ -148,15 +155,57 @@ static bool virtio_blk_do_io_request(struct kvm *self, struct virt_queue *queue) return true; } -static void virtio_blk_handle_callback(struct kvm *self, uint16_t queue_index) + + +static int virtio_blk_get_selected_queue(void) { - struct virt_queue *vq = &blk_device.vqs[queue_index]; + int i; - while (virt_queue__available(vq)) - virtio_blk_do_io_request(self, vq); + for (i = 0 ; i < NUM_VIRT_QUEUES ; i++) { + if (blk_device.virtio_blk_queue_set_flags & (1 << i)) { + blk_device.virtio_blk_queue_set_flags &= ~(1 << i); + return i; + } + } - kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); + return -1; +} +static void *virtio_blk_io_thread(void *ptr) +{ + struct kvm *self = ptr; + int ret; + mutex_lock(&blk_device.io_mutex); + ret = pthread_cond_wait(&blk_device.io_cond, &blk_device.io_mutex); + while (ret == 0) { + int queue_index = virtio_blk_get_selected_queue(); + mutex_unlock(&blk_device.io_mutex); + while (queue_index >= 0) { + struct virt_queue *vq = &blk_device.vqs[queue_index]; + + while (virt_queue__available(vq)) + virtio_blk_do_io_request(self, vq); + + kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); + + mutex_lock(&blk_device.io_mutex); + queue_index = virtio_blk_get_selected_queue(); + mutex_unlock(&blk_device.io_mutex); + } + mutex_lock(&blk_device.io_mutex); + ret = pthread_cond_wait(&(blk_device.io_cond), &(blk_device.io_mutex)); + } + + return NULL; +} + +static void virtio_blk_handle_callback(struct kvm *self, uint16_t queue_index) +{ + pthread_mutex_lock(&(blk_device.io_mutex)); + blk_device.virtio_blk_queue_set_flags |= (1 << queue_index); + pthread_mutex_unlock(&(blk_device.io_mutex)); + + pthread_cond_signal(&(blk_device.io_cond)); } static bool virtio_blk_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) @@ -242,6 +291,8 @@ void virtio_blk__init(struct kvm *self) if (!self->disk_image) return; + pthread_create(&blk_device.io_thread, NULL, virtio_blk_io_thread, self); + blk_device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE; pci__register(&virtio_blk_pci_device, PCI_VIRTIO_BLK_DEVNUM); -- 1.7.5.rc1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html