On Fri, Jul 18, 2025 at 10:37 PM Stefano Garzarella <sgarz...@redhat.com> wrote: > > On Fri, Jul 18, 2025 at 10:52:33AM +0200, Paolo Abeni wrote: > >Similar to virtio infra, vhost core maintains the features status > >in the full extended format and allows the devices to implement > >extended version of the getter/setter. > > > >Note that 'protocol_features' are not extended: they are only > >used by vhost-user, and the latter device is not going to implement > >extended features soon. > > > >Signed-off-by: Paolo Abeni <pab...@redhat.com> > >--- > >v2 -> v3: > > - fix compile warning > > - _array -> _ex > > > >v1 -> v2: > > - uint128_t -> uint64_t[] > > - add _ex() variant of features manipulation helpers > >--- > > hw/virtio/vhost.c | 73 +++++++++++++++++++++++++++---- > > include/hw/virtio/vhost-backend.h | 6 +++ > > include/hw/virtio/vhost.h | 33 ++++++++++++-- > > 3 files changed, 100 insertions(+), 12 deletions(-) > > > >diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c > >index c30ea1156e..85ae1e4d4c 100644 > >--- a/hw/virtio/vhost.c > >+++ b/hw/virtio/vhost.c > >@@ -972,20 +972,34 @@ static int vhost_virtqueue_set_addr(struct vhost_dev > >*dev, > > static int vhost_dev_set_features(struct vhost_dev *dev, > > bool enable_log) > > { > >- uint64_t features = dev->acked_features; > >+ uint64_t features[VIRTIO_FEATURES_DWORDS]; > > int r; > >+ > >+ virtio_features_copy(features, dev->acked_features_ex); > > if (enable_log) { > >- features |= 0x1ULL << VHOST_F_LOG_ALL; > >+ virtio_add_feature_ex(features, VHOST_F_LOG_ALL); > > } > > if (!vhost_dev_has_iommu(dev)) { > >- features &= ~(0x1ULL << VIRTIO_F_IOMMU_PLATFORM); > >+ virtio_clear_feature_ex(features, VIRTIO_F_IOMMU_PLATFORM); > > } > > if (dev->vhost_ops->vhost_force_iommu) { > > if (dev->vhost_ops->vhost_force_iommu(dev) == true) { > >- features |= 0x1ULL << VIRTIO_F_IOMMU_PLATFORM; > >+ virtio_add_feature_ex(features, VIRTIO_F_IOMMU_PLATFORM); > > } > > } > >- r = dev->vhost_ops->vhost_set_features(dev, features); > >+
Hi Paolo > >+ if (virtio_features_use_extended(features) && > >+ !dev->vhost_ops->vhost_set_features_ex) { > >+ VHOST_OPS_DEBUG(r, "extended features without device support"); > >+ r = -EINVAL; > >+ goto out; > >+ } As we discussed in version 2, this code should be changed to: [1], otherwise the problem mentioned last time will occur when compiling. [1] if (virtio_features_use_extended(features) && !dev->vhost_ops->vhost_set_features_ex) { - VHOST_OPS_DEBUG(r, "extended features without device support"); r = -EINVAL; + VHOST_OPS_DEBUG(r, "extended features without device support"); goto out; } Thanks Lei > >+ > >+ if (dev->vhost_ops->vhost_set_features_ex) { > >+ r = dev->vhost_ops->vhost_set_features_ex(dev, features); > >+ } else { > >+ r = dev->vhost_ops->vhost_set_features(dev, features[0]); > >+ } > > if (r < 0) { > > VHOST_OPS_DEBUG(r, "vhost_set_features failed"); > > goto out; > >@@ -1506,12 +1520,27 @@ static void vhost_virtqueue_cleanup(struct > >vhost_virtqueue *vq) > > } > > } > > > >+static int vhost_dev_get_features(struct vhost_dev *hdev, > >+ uint64_t *features) > >+{ > >+ uint64_t features64; > >+ int r; > >+ > >+ if (hdev->vhost_ops->vhost_get_features_ex) { > >+ return hdev->vhost_ops->vhost_get_features_ex(hdev, features); > >+ } > >+ > >+ r = hdev->vhost_ops->vhost_get_features(hdev, &features64); > >+ virtio_features_from_u64(features, features64); > >+ return r; > >+} > >+ > > int vhost_dev_init(struct vhost_dev *hdev, void *opaque, > > VhostBackendType backend_type, uint32_t busyloop_timeout, > > Error **errp) > > { > >+ uint64_t features[VIRTIO_FEATURES_DWORDS]; > > unsigned int used, reserved, limit; > >- uint64_t features; > > int i, r, n_initialized_vqs = 0; > > > > hdev->vdev = NULL; > >@@ -1531,7 +1560,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void > >*opaque, > > goto fail; > > } > > > >- r = hdev->vhost_ops->vhost_get_features(hdev, &features); > >+ r = vhost_dev_get_features(hdev, features); > > if (r < 0) { > > error_setg_errno(errp, -r, "vhost_get_features failed"); > > goto fail; > >@@ -1569,7 +1598,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void > >*opaque, > > } > > } > > > >- hdev->features = features; > >+ virtio_features_copy(hdev->features_ex, features); > > > > hdev->memory_listener = (MemoryListener) { > > .name = "vhost", > >@@ -1592,7 +1621,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void > >*opaque, > > }; > > > > if (hdev->migration_blocker == NULL) { > >- if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) { > >+ if (!virtio_has_feature_ex(hdev->features_ex, VHOST_F_LOG_ALL)) { > > error_setg(&hdev->migration_blocker, > > "Migration disabled: vhost lacks VHOST_F_LOG_ALL > > feature."); > > } else if (vhost_dev_log_is_shared(hdev) && > > !qemu_memfd_alloc_check()) { > >@@ -1871,6 +1900,20 @@ uint64_t vhost_get_features(struct vhost_dev *hdev, > >const int *feature_bits, > > return features; > > } > > > >+void vhost_get_features_ex(struct vhost_dev *hdev, > >+ const int *feature_bits, > >+ uint64_t *features) > >+{ > >+ const int *bit = feature_bits; > >+ > >+ while (*bit != VHOST_INVALID_FEATURE_BIT) { > >+ if (!virtio_has_feature_ex(hdev->features_ex, *bit)) { > >+ virtio_clear_feature_ex(features, *bit); > >+ } > >+ bit++; > >+ } > >+} > >+ > > Can we do something similar of what we do in hw/virtio/virtio.c where > the old virtio_set_features() use the new virtio_set_features_ex()? > > > void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, > > uint64_t features) > > { > >@@ -1884,6 +1927,18 @@ void vhost_ack_features(struct vhost_dev *hdev, const > >int *feature_bits, > > } > > } > > > >+void vhost_ack_features_ex(struct vhost_dev *hdev, const int *feature_bits, > >+ const uint64_t *features) > >+{ > >+ const int *bit = feature_bits; > >+ while (*bit != VHOST_INVALID_FEATURE_BIT) { > >+ if (virtio_has_feature_ex(features, *bit)) { > >+ virtio_add_feature_ex(hdev->acked_features_ex, *bit); > >+ } > >+ bit++; > >+ } > >+} > >+ > > Ditto. > > Not a strong opinion, but just to reduce code duplication. > > Thanks, > Stefano > > > int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, > > uint32_t config_len, Error **errp) > > { > >diff --git a/include/hw/virtio/vhost-backend.h > >b/include/hw/virtio/vhost-backend.h > >index d6df209a2f..ff94fa1734 100644 > >--- a/include/hw/virtio/vhost-backend.h > >+++ b/include/hw/virtio/vhost-backend.h > >@@ -95,6 +95,10 @@ typedef int (*vhost_new_worker_op)(struct vhost_dev *dev, > > struct vhost_worker_state *worker); > > typedef int (*vhost_free_worker_op)(struct vhost_dev *dev, > > struct vhost_worker_state *worker); > >+typedef int (*vhost_set_features_ex_op)(struct vhost_dev *dev, > >+ const uint64_t *features); > >+typedef int (*vhost_get_features_ex_op)(struct vhost_dev *dev, > >+ uint64_t *features); > > typedef int (*vhost_set_features_op)(struct vhost_dev *dev, > > uint64_t features); > > typedef int (*vhost_get_features_op)(struct vhost_dev *dev, > >@@ -186,6 +190,8 @@ typedef struct VhostOps { > > vhost_free_worker_op vhost_free_worker; > > vhost_get_vring_worker_op vhost_get_vring_worker; > > vhost_attach_vring_worker_op vhost_attach_vring_worker; > >+ vhost_set_features_ex_op vhost_set_features_ex; > >+ vhost_get_features_ex_op vhost_get_features_ex; > > vhost_set_features_op vhost_set_features; > > vhost_get_features_op vhost_get_features; > > vhost_set_backend_cap_op vhost_set_backend_cap; > >diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h > >index 66be6afc88..39fbffc6bc 100644 > >--- a/include/hw/virtio/vhost.h > >+++ b/include/hw/virtio/vhost.h > >@@ -107,9 +107,9 @@ struct vhost_dev { > > * future use should be discouraged and the variable retired as > > * its easy to confuse with the VirtIO backend_features. > > */ > >- uint64_t features; > >- uint64_t acked_features; > >- uint64_t backend_features; > >+ VIRTIO_DECLARE_FEATURES(features); > >+ VIRTIO_DECLARE_FEATURES(acked_features); > >+ VIRTIO_DECLARE_FEATURES(backend_features); > > > > /** > > * @protocol_features: is the vhost-user only feature set by > >@@ -333,6 +333,21 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, > >VirtIODevice *vdev, int n, > > uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, > > uint64_t features); > > > >+/** > >+ * vhost_get_features_ex() - sanitize the extended features set > >+ * @hdev: common vhost_dev structure > >+ * @feature_bits: pointer to terminated table of feature bits > >+ * @features: original features set, filtered out on return > >+ * > >+ * This is the extended variant of vhost_get_features(), supporting the > >+ * the extended features set. Filter it with the intersection of what is > >+ * supported by the vhost backend (hdev->features) and the supported > >+ * feature_bits. > >+ */ > >+void vhost_get_features_ex(struct vhost_dev *hdev, > >+ const int *feature_bits, > >+ uint64_t *features); > >+ > > /** > > * vhost_ack_features() - set vhost acked_features > > * @hdev: common vhost_dev structure > >@@ -344,6 +359,18 @@ uint64_t vhost_get_features(struct vhost_dev *hdev, > >const int *feature_bits, > > */ > > void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, > > uint64_t features); > >+ > >+/** > >+ * vhost_ack_features_ex() - set vhost full set of acked_features > >+ * @hdev: common vhost_dev structure > >+ * @feature_bits: pointer to terminated table of feature bits > >+ * @features: requested feature set > >+ * > >+ * This sets the internal hdev->acked_features to the intersection of > >+ * the backends advertised features and the supported feature_bits. > >+ */ > >+void vhost_ack_features_ex(struct vhost_dev *hdev, const int *feature_bits, > >+ const uint64_t *features); > > unsigned int vhost_get_max_memslots(void); > > unsigned int vhost_get_free_memslots(void); > > > >-- > >2.50.0 > > > >