Automatically size the number of virtio-scsi-pci, vhost-scsi-pci, and
vhost-user-scsi-pci request virtqueues to match the number of vCPUs.
Other transports continue to default to 1 request virtqueue.
A 1:1 virtqueue:vCPU mapping 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. The
maximum number of MSI-X vectors and virtqueues limit are respected.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <
20200818143348.310613-6-stefanha@redhat.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
#include "hw/mem/nvdimm.h"
#include "migration/vmstate.h"
-GlobalProperty hw_compat_5_1[] = {};
+GlobalProperty hw_compat_5_1[] = {
+ { "vhost-scsi", "num_queues", "1"},
+ { "vhost-user-scsi", "num_queues", "1"},
+ { "virtio-scsi-device", "num_queues", "1"},
+};
const size_t hw_compat_5_1_len = G_N_ELEMENTS(hw_compat_5_1);
GlobalProperty hw_compat_5_0[] = {
DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
- DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
+ DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
+ VIRTIO_SCSI_AUTO_NUM_QUEUES),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
128),
DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust,
static Property vhost_user_scsi_properties[] = {
DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev),
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
- DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
+ DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
+ VIRTIO_SCSI_AUTO_NUM_QUEUES),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
128),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
sizeof(VirtIOSCSIConfig));
+ if (s->conf.num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
+ s->conf.num_queues = 1;
+ }
if (s->conf.num_queues == 0 ||
s->conf.num_queues > VIRTIO_QUEUE_MAX - VIRTIO_SCSI_VQ_NUM_FIXED) {
error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
}
static Property virtio_scsi_properties[] = {
- DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
+ DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues,
+ VIRTIO_SCSI_AUTO_NUM_QUEUES),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
parent_obj.conf.virtqueue_size, 256),
DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSI,
{
VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+ VirtIOSCSIConf *conf = &dev->vdev.parent_obj.parent_obj.conf;
+
+ if (conf->num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
+ conf->num_queues =
+ virtio_pci_optimal_num_queues(VIRTIO_SCSI_VQ_NUM_FIXED);
+ }
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues +
- VIRTIO_SCSI_VQ_NUM_FIXED + 1;
+ vpci_dev->nvectors = conf->num_queues + VIRTIO_SCSI_VQ_NUM_FIXED + 1;
}
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
{
VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+ VirtIOSCSIConf *conf = &dev->vdev.parent_obj.parent_obj.conf;
+
+ if (conf->num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
+ conf->num_queues =
+ virtio_pci_optimal_num_queues(VIRTIO_SCSI_VQ_NUM_FIXED);
+ }
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues +
- VIRTIO_SCSI_VQ_NUM_FIXED + 1;
+ vpci_dev->nvectors = conf->num_queues + VIRTIO_SCSI_VQ_NUM_FIXED + 1;
}
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
{
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
DeviceState *proxy = DEVICE(vpci_dev);
+ VirtIOSCSIConf *conf = &dev->vdev.parent_obj.conf;
char *bus_name;
+ if (conf->num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
+ conf->num_queues =
+ virtio_pci_optimal_num_queues(VIRTIO_SCSI_VQ_NUM_FIXED);
+ }
+
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues +
- VIRTIO_SCSI_VQ_NUM_FIXED + 1;
+ vpci_dev->nvectors = conf->num_queues + VIRTIO_SCSI_VQ_NUM_FIXED + 1;
}
/*
/* Number of virtqueues that are always present */
#define VIRTIO_SCSI_VQ_NUM_FIXED 2
+#define VIRTIO_SCSI_AUTO_NUM_QUEUES UINT32_MAX
+
typedef struct virtio_scsi_cmd_req VirtIOSCSICmdReq;
typedef struct virtio_scsi_cmd_resp VirtIOSCSICmdResp;
typedef struct virtio_scsi_ctrl_tmf_req VirtIOSCSICtrlTMFReq;