@samitouri / QOSamiQemu / commits / 5d4d0f552b

vhost-user-blk: add seg-max-adjust flag

The virtio specification is not completely clear about seg_max and its relationship with queue_size. Some drivers (for example, the modern Linux kernel driver) rely on seg_max to set the maximum number of segments used in a request. If seg_max is set larger than queue_size, such a driver might overwhelm a virtqueue by trying to send more segments than it can handle. As a result, it either hangs or faults. One might argue that it is the vhost-user server's responsibility to set a valid seg_max value. However, due to the issue described in the previous paragraph, this value should generally depend on queue_size. That's why it may be necessary to control it on QEMU's side. This patch adds the seg-max-adjust flag. A flag with the same name already exists for virtio-blk (and it exists to solve the same problem, except that here we have a vhost-user server to consult). If seg-max-adjust is set, the final seg_max is the minimum of the value provided by the vhost-user server and (queue_size - 2). It is not enabled by default. Signed-off-by: Sergei Heifetz <heifetz@yandex-team.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260401230548.136541-1-heifetz@yandex-team.com>

Sergei Heifetz committed Apr 2, 2026 at 04:05 UTC 5d4d0f552bcbe784d74c405d205749384be16822
2 files changed +13
hw/block/vhost-user-blk.c
+12
@@ -66,6 +66,12 @@ static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
66 /* Our num_queues overrides the device backend */
67 virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues);
68
69 + if (s->seg_max_adjust) {
70 + uint32_t seg_max = MIN(s->blkcfg.seg_max, s->queue_size - 2);
71 +
72 + virtio_stl_p(vdev, &s->blkcfg.seg_max, seg_max);
73 + }
74 +
75 memcpy(config, &s->blkcfg, vdev->config_len);
76 }
77
@@ -489,6 +495,10 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
495 error_setg(errp, "queue size must be non-zero");
496 return;
497 }
498 + if (s->queue_size < 4 && s->seg_max_adjust) {
499 + error_setg(errp, "queue size must be >= 4 when seg-max-adjust is set");
500 + return;
501 + }
502 if (s->queue_size > VIRTQUEUE_MAX_SIZE) {
503 error_setg(errp, "queue size must not exceed %d",
504 VIRTQUEUE_MAX_SIZE);
@@ -624,6 +634,8 @@ static const Property vhost_user_blk_properties[] = {
634 DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues,
635 VHOST_USER_BLK_AUTO_NUM_QUEUES),
636 DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128),
637 + DEFINE_PROP_BOOL("seg-max-adjust", VHostUserBlk, seg_max_adjust,
638 + false),
639 DEFINE_PROP_BIT64("config-wce", VHostUserBlk, parent_obj.host_features,
640 VIRTIO_BLK_F_CONFIG_WCE, true),
641 DEFINE_PROP_BIT64("discard", VHostUserBlk, parent_obj.host_features,
include/hw/virtio/vhost-user-blk.h
+1
@@ -34,6 +34,7 @@ struct VHostUserBlk {
34 struct virtio_blk_config blkcfg;
35 uint16_t num_queues;
36 uint32_t queue_size;
37 + bool seg_max_adjust;
38 struct vhost_dev dev;
39 struct vhost_inflight *inflight;
40 VhostUserState vhost_user;