@samitouri / QOSamiQemu / commits / ddbae214b1

vhost: make vhost_dev.features private

It's hard to control where and how do we use this field. Let's cover all usages by getters/setters, and keep direct access to the field only in vhost.c. It will help to control migration of this field in further commits. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Reviewed-by: Daniil Tatianin <d-tatianin@yandex-team.ru> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Tested-by: Lei Yang <leiyang@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260420200339.708640-7-vsementsov@yandex-team.ru>

Vladimir Sementsov-Ogievskiy committed Apr 20, 2026 at 23:03 UTC ddbae214b1874ef97bda6cd7bf3a3cfbf9ceb82b
9 files changed +65 -28
hw/display/vhost-user-gpu.c
+3 -4
@@ -631,17 +631,16 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
631
632 /* existing backend may send DMABUF, so let's add that requirement */
633 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED;
634 - if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_VIRGL)) {
634 + if (vhost_dev_has_feature(&g->vhost->dev, VIRTIO_GPU_F_VIRGL)) {
635 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED;
636 }
637 - if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_EDID)) {
637 + if (vhost_dev_has_feature(&g->vhost->dev, VIRTIO_GPU_F_EDID)) {
638 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_EDID_ENABLED;
639 } else {
640 error_report("EDID requested but the backend doesn't support it.");
641 g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
642 }
643 - if (virtio_has_feature(g->vhost->dev.features,
644 - VIRTIO_GPU_F_RESOURCE_UUID)) {
643 + if (vhost_dev_has_feature(&g->vhost->dev, VIRTIO_GPU_F_RESOURCE_UUID)) {
644 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
645 }
646
hw/net/vhost_net.c
+9 -9
@@ -54,8 +54,8 @@ void vhost_net_ack_features_ex(struct vhost_net *net, const uint64_t *features)
54 {
55 virtio_features_clear(net->dev.acked_features_ex);
56 if (net->backend == -1) {
57 - net->dev.acked_features =
58 - net->dev.features & (1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
57 + net->dev.acked_features = (vhost_dev_features(&net->dev) &
58 + (1ULL << VHOST_USER_F_PROTOCOL_FEATURES));
59 } else if (!qemu_has_vnet_hdr(net->nc)) {
60 net->dev.acked_features = 1ULL << VHOST_NET_F_VIRTIO_NET_HDR;
61 }
@@ -282,15 +282,15 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
282 if (backend_kernel) {
283 if (!qemu_has_vnet_hdr_len(options->net_backend,
284 sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
285 - net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF);
285 + vhost_dev_clear_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF);
286 }
287
288 if (!qemu_has_vnet_hdr(options->net_backend) &&
289 - (~net->dev.features & (1ULL << VHOST_NET_F_VIRTIO_NET_HDR))) {
290 - fprintf(stderr, "vhost lacks feature mask 0x%llx for backend\n",
291 - ~net->dev.features & (1ULL << VHOST_NET_F_VIRTIO_NET_HDR));
292 - goto fail;
293 - }
289 + !vhost_dev_has_feature(&net->dev, VHOST_NET_F_VIRTIO_NET_HDR)) {
290 + fprintf(stderr, "vhost lacks VHOST_NET_F_VIRTIO_NET_HDR "
291 + "feature for backend\n");
292 + goto fail;
293 + }
294 }
295
296 /* Set sane init value. Override when guest acks. */
@@ -298,7 +298,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
298 virtio_features_from_u64(features,
299 options->get_acked_features(net->nc));
300 if (virtio_features_andnot(missing_features, features,
301 - net->dev.features_ex)) {
301 + vhost_dev_features_ex(&net->dev))) {
302 fprintf(stderr, "vhost lacks feature mask 0x" VIRTIO_FEATURES_FMT
303 " for backend\n", VIRTIO_FEATURES_PR(missing_features));
304 goto fail;
hw/virtio/vdpa-dev.c
+1 -1
@@ -224,7 +224,7 @@ static uint64_t vhost_vdpa_device_get_features(VirtIODevice *vdev,
224 Error **errp)
225 {
226 VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
227 - uint64_t backend_features = s->dev.features;
227 + uint64_t backend_features = vhost_dev_features(&s->dev);
228
229 if (!virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM)) {
230 virtio_clear_feature(&backend_features, VIRTIO_F_IOMMU_PLATFORM);
hw/virtio/vhost-user-base.c
+6 -2
@@ -118,9 +118,13 @@ static uint64_t vub_get_features(VirtIODevice *vdev,
118 uint64_t requested_features, Error **errp)
119 {
120 VHostUserBase *vub = VHOST_USER_BASE(vdev);
121 + uint64_t backend_features = vhost_dev_features(&vub->vhost_dev);
122 +
123 /* This should be set when the vhost connection initialises */
122 - g_assert(vub->vhost_dev.features);
123 - return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
124 + g_assert(backend_features);
125 + virtio_clear_feature(&backend_features, VHOST_USER_F_PROTOCOL_FEATURES);
126 +
127 + return backend_features;
128 }
129
130 /*
hw/virtio/vhost-user.c
+2 -2
@@ -1249,7 +1249,7 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
1249 {
1250 int i;
1251
1252 - if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
1252 + if (!vhost_dev_has_feature(dev, VHOST_USER_F_PROTOCOL_FEATURES)) {
1253 /*
1254 * For vhost-user devices, if VHOST_USER_F_PROTOCOL_FEATURES has not
1255 * been negotiated, the rings start directly in the enabled state,
@@ -1488,7 +1488,7 @@ static int vhost_user_set_features(struct vhost_dev *dev,
1488 * Don't lose VHOST_USER_F_PROTOCOL_FEATURES, which is vhost-user
1489 * specific.
1490 */
1491 - if (virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
1491 + if (vhost_dev_has_feature(dev, VHOST_USER_F_PROTOCOL_FEATURES)) {
1492 features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
1493 }
1494
hw/virtio/vhost.c
+3 -3
@@ -1612,7 +1612,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
1612 }
1613 }
1614
1615 - virtio_features_copy(hdev->features_ex, features);
1615 + virtio_features_copy(hdev->_features_ex, features);
1616
1617 hdev->memory_listener = (MemoryListener) {
1618 .name = "vhost",
@@ -1635,7 +1635,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
1635 };
1636
1637 if (hdev->migration_blocker == NULL) {
1638 - if (!virtio_has_feature_ex(hdev->features_ex, VHOST_F_LOG_ALL)) {
1638 + if (!vhost_dev_has_feature_ex(hdev, VHOST_F_LOG_ALL)) {
1639 error_setg(&hdev->migration_blocker,
1640 "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature.");
1641 } else if (vhost_dev_log_is_shared(hdev) && !qemu_memfd_alloc_check()) {
@@ -1909,7 +1909,7 @@ void vhost_get_features_ex(struct vhost_dev *hdev,
1909 const int *bit = feature_bits;
1910
1911 while (*bit != VHOST_INVALID_FEATURE_BIT) {
1912 - if (!virtio_has_feature_ex(hdev->features_ex, *bit)) {
1912 + if (!vhost_dev_has_feature_ex(hdev, *bit)) {
1913 virtio_clear_feature_ex(features, *bit);
1914 }
1915 bit++;
hw/virtio/virtio-qmp.c
+1 -1
@@ -747,7 +747,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
747 status->vhost_dev->nvqs = hdev->nvqs;
748 status->vhost_dev->vq_index = hdev->vq_index;
749 status->vhost_dev->features =
750 - qmp_decode_features(vdev->device_id, hdev->features_ex);
750 + qmp_decode_features(vdev->device_id, vhost_dev_features_ex(hdev));
751 status->vhost_dev->acked_features =
752 qmp_decode_features(vdev->device_id, hdev->acked_features_ex);
753
include/hw/virtio/vhost.h
+37 -2
@@ -98,10 +98,11 @@ struct vhost_dev {
98 * offered by a backend which may be a subset of the total
99 * features eventually offered to the guest.
100 *
101 - * @features: available features provided by the backend
101 + * @_features: available features provided by the backend, private,
102 + * direct access only in vhost.h/vhost.c
103 * @acked_features: final negotiated features with front-end driver
104 */
104 - VIRTIO_DECLARE_FEATURES(features);
105 + VIRTIO_DECLARE_FEATURES(_features);
106 VIRTIO_DECLARE_FEATURES(acked_features);
107
108 uint64_t max_queues;
@@ -403,6 +404,40 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
404 struct vhost_inflight *inflight);
405 bool vhost_dev_has_iommu(struct vhost_dev *dev);
406
407 +static inline bool vhost_dev_has_feature(struct vhost_dev *dev,
408 + uint64_t feature)
409 +{
410 + return virtio_has_feature(dev->_features, feature);
411 +}
412 +
413 +static inline bool vhost_dev_has_feature_ex(struct vhost_dev *dev,
414 + uint64_t feature)
415 +{
416 + return virtio_has_feature_ex(dev->_features_ex, feature);
417 +}
418 +
419 +static inline uint64_t vhost_dev_features(struct vhost_dev *dev)
420 +{
421 + return dev->_features;
422 +}
423 +
424 +static inline const uint64_t *vhost_dev_features_ex(struct vhost_dev *dev)
425 +{
426 + return dev->_features_ex;
427 +}
428 +
429 +static inline void vhost_dev_clear_feature(struct vhost_dev *dev,
430 + uint64_t feature)
431 +{
432 + virtio_clear_feature(&dev->_features, feature);
433 +}
434 +
435 +static inline void vhost_dev_clear_feature_ex(struct vhost_dev *dev,
436 + uint64_t feature)
437 +{
438 + virtio_clear_feature_ex(dev->_features_ex, feature);
439 +}
440 +
441 #ifdef CONFIG_VHOST
442 int vhost_reset_device(struct vhost_dev *hdev);
443 #else
net/vhost-vdpa.c
+3 -4
@@ -257,15 +257,14 @@ static bool vhost_vdpa_get_vnet_hash_supported_types(NetClientState *nc,
257 {
258 assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
259 VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
260 - uint64_t features = s->vhost_vdpa.dev->features;
260 int fd = s->vhost_vdpa.shared->device_fd;
261 struct {
262 struct vhost_vdpa_config hdr;
263 uint32_t supported_hash_types;
264 } config;
265
267 - if (!virtio_has_feature(features, VIRTIO_NET_F_HASH_REPORT) &&
268 - !virtio_has_feature(features, VIRTIO_NET_F_RSS)) {
266 + if (!vhost_dev_has_feature(s->vhost_vdpa.dev, VIRTIO_NET_F_HASH_REPORT) &&
267 + !vhost_dev_has_feature(s->vhost_vdpa.dev, VIRTIO_NET_F_RSS)) {
268 return false;
269 }
270
@@ -586,7 +585,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
585 * If we early return in these cases SVQ will not be enabled. The migration
586 * will be blocked as long as vhost-vdpa backends will not offer _F_LOG.
587 */
589 - if (!vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) {
588 + if (!vhost_vdpa_net_valid_svq_features(vhost_dev_features(v->dev), NULL)) {
589 return 0;
590 }
591