qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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>

authored by

Denis Plotnikov and committed by
Michael S. Tsirkin
1bf8a989 d940208c

+24 -2
+8 -1
hw/block/virtio-blk.c
··· 913 913 blk_get_geometry(s->blk, &capacity); 914 914 memset(&blkcfg, 0, sizeof(blkcfg)); 915 915 virtio_stq_p(vdev, &blkcfg.capacity, capacity); 916 - virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2); 916 + virtio_stl_p(vdev, &blkcfg.seg_max, 917 + s->conf.seg_max_adjust ? s->conf.queue_size - 2 : 128 - 2); 917 918 virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls); 918 919 virtio_stl_p(vdev, &blkcfg.blk_size, blk_size); 919 920 virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size); ··· 1138 1139 error_setg(errp, "num-queues property must be larger than 0"); 1139 1140 return; 1140 1141 } 1142 + if (conf->queue_size <= 2) { 1143 + error_setg(errp, "invalid queue-size property (%" PRIu16 "), " 1144 + "must be > 2", conf->queue_size); 1145 + return; 1146 + } 1141 1147 if (!is_power_of_2(conf->queue_size) || 1142 1148 conf->queue_size > VIRTQUEUE_MAX_SIZE) { 1143 1149 error_setg(errp, "invalid queue-size property (%" PRIu16 "), " ··· 1267 1273 true), 1268 1274 DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1), 1269 1275 DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128), 1276 + DEFINE_PROP_BOOL("seg-max-adjust", VirtIOBlock, conf.seg_max_adjust, true), 1270 1277 DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD, 1271 1278 IOThread *), 1272 1279 DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
+3
hw/core/machine.c
··· 29 29 30 30 GlobalProperty hw_compat_4_2[] = { 31 31 { "virtio-blk-device", "x-enable-wce-if-config-wce", "off" }, 32 + { "virtio-blk-device", "seg-max-adjust", "off"}, 33 + { "virtio-scsi-device", "seg_max_adjust", "off"}, 34 + { "vhost-blk-device", "seg_max_adjust", "off"}, 32 35 }; 33 36 const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); 34 37
+2
hw/scsi/vhost-scsi.c
··· 275 275 DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1), 276 276 DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size, 277 277 128), 278 + DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust, 279 + true), 278 280 DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors, 279 281 0xFFFF), 280 282 DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
+9 -1
hw/scsi/virtio-scsi.c
··· 659 659 VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev); 660 660 661 661 virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues); 662 - virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2); 662 + virtio_stl_p(vdev, &scsiconf->seg_max, 663 + s->conf.seg_max_adjust ? s->conf.virtqueue_size - 2 : 128 - 2); 663 664 virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors); 664 665 virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun); 665 666 virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); ··· 898 899 virtio_cleanup(vdev); 899 900 return; 900 901 } 902 + if (s->conf.virtqueue_size <= 2) { 903 + error_setg(errp, "invalid virtqueue_size property (= %" PRIu32 "), " 904 + "must be > 2", s->conf.virtqueue_size); 905 + return; 906 + } 901 907 s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues); 902 908 s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; 903 909 s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE; ··· 954 960 DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1), 955 961 DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI, 956 962 parent_obj.conf.virtqueue_size, 128), 963 + DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSI, 964 + parent_obj.conf.seg_max_adjust, true), 957 965 DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors, 958 966 0xFFFF), 959 967 DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
+1
include/hw/virtio/virtio-blk.h
··· 38 38 uint32_t request_merging; 39 39 uint16_t num_queues; 40 40 uint16_t queue_size; 41 + bool seg_max_adjust; 41 42 uint32_t max_discard_sectors; 42 43 uint32_t max_write_zeroes_sectors; 43 44 bool x_enable_wce_if_config_wce;
+1
include/hw/virtio/virtio-scsi.h
··· 48 48 struct VirtIOSCSIConf { 49 49 uint32_t num_queues; 50 50 uint32_t virtqueue_size; 51 + bool seg_max_adjust; 51 52 uint32_t max_sectors; 52 53 uint32_t cmd_per_lun; 53 54 #ifdef CONFIG_VHOST_SCSI