virtio: make seg_max virtqueue size dependent
Before the patch, seg_max parameter was immutable and hardcoded to 126 (128 - 2) without respect to queue size. This has two negative effects: 1. when queue size is < 128, we have Virtio 1.1 specfication violation: (2.6.5.3.1 Driver Requirements) seq_max must be <= queue_size. This violation affects the old Linux guests (ver < 4.14). These guests crash on these queue_size setups. 2. when queue_size > 128, as was pointed out by Denis Lunev <den@virtuozzo.com>, seg_max restrics guest's block request length which affects guests' performance making them issues more block request than needed. https://lists.gnu.org/archive/html/qemu-devel/2017-12/msg03721.html To mitigate this two effects, the patch adds the property adjusting seg_max to queue size automaticaly. Since seg_max is a guest visible parameter, the property is machine type managable and allows to choose between old (seg_max = 126 always) and new (seg_max = queue_size - 2) behaviors. Not to change the behavior of the older VMs, prevent setting the default seg_max_adjust value for older machine types. Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com> Message-Id: <20191220140905.1718-2-dplotnikov@virtuozzo.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
d940208cbb
commit
1bf8a989a5
@ -913,7 +913,8 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
|||||||
blk_get_geometry(s->blk, &capacity);
|
blk_get_geometry(s->blk, &capacity);
|
||||||
memset(&blkcfg, 0, sizeof(blkcfg));
|
memset(&blkcfg, 0, sizeof(blkcfg));
|
||||||
virtio_stq_p(vdev, &blkcfg.capacity, capacity);
|
virtio_stq_p(vdev, &blkcfg.capacity, capacity);
|
||||||
virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
|
virtio_stl_p(vdev, &blkcfg.seg_max,
|
||||||
|
s->conf.seg_max_adjust ? s->conf.queue_size - 2 : 128 - 2);
|
||||||
virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls);
|
virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls);
|
||||||
virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
|
virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
|
||||||
virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
|
virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
|
||||||
@ -1138,6 +1139,11 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
|||||||
error_setg(errp, "num-queues property must be larger than 0");
|
error_setg(errp, "num-queues property must be larger than 0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (conf->queue_size <= 2) {
|
||||||
|
error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
|
||||||
|
"must be > 2", conf->queue_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!is_power_of_2(conf->queue_size) ||
|
if (!is_power_of_2(conf->queue_size) ||
|
||||||
conf->queue_size > VIRTQUEUE_MAX_SIZE) {
|
conf->queue_size > VIRTQUEUE_MAX_SIZE) {
|
||||||
error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
|
error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
|
||||||
@ -1267,6 +1273,7 @@ static Property virtio_blk_properties[] = {
|
|||||||
true),
|
true),
|
||||||
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
|
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
|
||||||
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
|
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,
|
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
|
||||||
IOThread *),
|
IOThread *),
|
||||||
DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
|
DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
GlobalProperty hw_compat_4_2[] = {
|
GlobalProperty hw_compat_4_2[] = {
|
||||||
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
|
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
|
||||||
|
{ "virtio-blk-device", "seg-max-adjust", "off"},
|
||||||
|
{ "virtio-scsi-device", "seg_max_adjust", "off"},
|
||||||
|
{ "vhost-blk-device", "seg_max_adjust", "off"},
|
||||||
};
|
};
|
||||||
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
|
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
|
||||||
|
|
||||||
|
@ -275,6 +275,8 @@ static Property vhost_scsi_properties[] = {
|
|||||||
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
|
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
|
||||||
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
|
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
|
||||||
128),
|
128),
|
||||||
|
DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust,
|
||||||
|
true),
|
||||||
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
|
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
|
||||||
0xFFFF),
|
0xFFFF),
|
||||||
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
|
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
|
||||||
|
@ -659,7 +659,8 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
|
|||||||
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
|
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
|
||||||
|
|
||||||
virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
|
virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
|
||||||
virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2);
|
virtio_stl_p(vdev, &scsiconf->seg_max,
|
||||||
|
s->conf.seg_max_adjust ? s->conf.virtqueue_size - 2 : 128 - 2);
|
||||||
virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
|
virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
|
||||||
virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
|
virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
|
||||||
virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
||||||
@ -898,6 +899,11 @@ void virtio_scsi_common_realize(DeviceState *dev,
|
|||||||
virtio_cleanup(vdev);
|
virtio_cleanup(vdev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (s->conf.virtqueue_size <= 2) {
|
||||||
|
error_setg(errp, "invalid virtqueue_size property (= %" PRIu32 "), "
|
||||||
|
"must be > 2", s->conf.virtqueue_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
|
s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
|
||||||
s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
|
s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
|
||||||
s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
|
s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
|
||||||
@ -954,6 +960,8 @@ 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, 1),
|
||||||
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
|
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
|
||||||
parent_obj.conf.virtqueue_size, 128),
|
parent_obj.conf.virtqueue_size, 128),
|
||||||
|
DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSI,
|
||||||
|
parent_obj.conf.seg_max_adjust, true),
|
||||||
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
|
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
|
||||||
0xFFFF),
|
0xFFFF),
|
||||||
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
|
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
|
||||||
|
@ -38,6 +38,7 @@ struct VirtIOBlkConf
|
|||||||
uint32_t request_merging;
|
uint32_t request_merging;
|
||||||
uint16_t num_queues;
|
uint16_t num_queues;
|
||||||
uint16_t queue_size;
|
uint16_t queue_size;
|
||||||
|
bool seg_max_adjust;
|
||||||
uint32_t max_discard_sectors;
|
uint32_t max_discard_sectors;
|
||||||
uint32_t max_write_zeroes_sectors;
|
uint32_t max_write_zeroes_sectors;
|
||||||
bool x_enable_wce_if_config_wce;
|
bool x_enable_wce_if_config_wce;
|
||||||
|
@ -48,6 +48,7 @@ typedef struct virtio_scsi_config VirtIOSCSIConfig;
|
|||||||
struct VirtIOSCSIConf {
|
struct VirtIOSCSIConf {
|
||||||
uint32_t num_queues;
|
uint32_t num_queues;
|
||||||
uint32_t virtqueue_size;
|
uint32_t virtqueue_size;
|
||||||
|
bool seg_max_adjust;
|
||||||
uint32_t max_sectors;
|
uint32_t max_sectors;
|
||||||
uint32_t cmd_per_lun;
|
uint32_t cmd_per_lun;
|
||||||
#ifdef CONFIG_VHOST_SCSI
|
#ifdef CONFIG_VHOST_SCSI
|
||||||
|
Loading…
Reference in New Issue
Block a user