@@ -18,6 +18,7 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "trace.h"
+#include "hw/boards.h"
#include "hw/block/block.h"
#include "hw/qdev-properties.h"
#include "sysemu/blockdev.h"
@@ -1119,6 +1120,18 @@ static const BlockDevOps virtio_block_ops = {
.resize_cb = virtio_blk_resize,
};
+static uint32_t virtio_blk_get_num_virtqueues(VirtIODevice *vdev)
+{
+ VirtIOBlock *s = VIRTIO_BLK(vdev);
+ VirtIOBlkConf *conf = &s->conf;
+
+ if (conf->num_queues == 1 && conf->auto_num_queues) {
+ return current_machine->smp.cpus;
+ }
+
+ return conf->num_queues;
+}
+
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -1135,6 +1148,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Device needs media, but drive is empty");
return;
}
+ conf->num_queues = virtio_blk_get_num_virtqueues(vdev);
if (!conf->num_queues) {
error_setg(errp, "num-queues property must be larger than 0");
return;
@@ -1272,6 +1286,8 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
+ DEFINE_PROP_BOOL("auto-num-queues", VirtIOBlock,
+ conf.auto_num_queues, true),
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
DEFINE_PROP_BOOL("seg-max-adjust", VirtIOBlock, conf.seg_max_adjust, true),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
@@ -1297,6 +1313,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
dc->props = virtio_blk_properties;
dc->vmsd = &vmstate_virtio_blk;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ vdc->get_num_virtqueues = virtio_blk_get_num_virtqueues;
vdc->realize = virtio_blk_device_realize;
vdc->unrealize = virtio_blk_device_unrealize;
vdc->get_config = virtio_blk_update_config;
@@ -28,6 +28,7 @@
#include "hw/mem/nvdimm.h"
GlobalProperty hw_compat_4_2[] = {
+ { "virtio-blk-device", "auto-num-queues", "off"},
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
{ "virtio-blk-device", "seg-max-adjust", "off"},
{ "virtio-scsi-device", "auto_num_queues", "off"},
@@ -50,9 +50,10 @@ static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = dev->vdev.conf.num_queues + 1;
+ vpci_dev->nvectors = vdc->get_num_virtqueues(VIRTIO_DEVICE(vdev)) + 1;
}
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
@@ -37,6 +37,7 @@ struct VirtIOBlkConf
char *serial;
uint32_t request_merging;
uint16_t num_queues;
+ bool auto_num_queues;
uint16_t queue_size;
bool seg_max_adjust;
uint32_t max_discard_sectors;
Automatically size the number of request virtqueues to match the number of vCPUs. This ensures that completion interrupts are handled on the same vCPU that submitted the request. No IPI is necessary to complete an I/O request and performance is improved. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- hw/block/virtio-blk.c | 17 +++++++++++++++++ hw/core/machine.c | 1 + hw/virtio/virtio-blk-pci.c | 3 ++- include/hw/virtio/virtio-blk.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-)