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