Overall looks good. Just a nit. Acked-by: Raphael Norwitz <[email protected]>
On Thu, Oct 16, 2025 at 7:44 AM Vladimir Sementsov-Ogievskiy <[email protected]> wrote: > > Introduce vhost_dev.backend_transfer field, > > Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> > --- > hw/virtio/vhost.c | 121 +++++++++++++++++++++++++++++++++----- > include/hw/virtio/vhost.h | 7 +++ > 2 files changed, 113 insertions(+), 15 deletions(-) > > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c > index 63036f8214..c46203eb9c 100644 > --- a/hw/virtio/vhost.c > +++ b/hw/virtio/vhost.c > @@ -1325,6 +1325,8 @@ out: > return ret; > } > > +static void vhost_virtqueue_error_notifier(EventNotifier *n); > + > int vhost_virtqueue_start(struct vhost_dev *dev, > struct VirtIODevice *vdev, > struct vhost_virtqueue *vq, > @@ -1350,7 +1352,13 @@ int vhost_virtqueue_start(struct vhost_dev *dev, > return r; > } > > - vq->num = state.num = virtio_queue_get_num(vdev, idx); > + vq->num = virtio_queue_get_num(vdev, idx); > + > + if (dev->backend_transfer) { > + return 0; > + } > + > + state.num = vq->num; > r = dev->vhost_ops->vhost_set_vring_num(dev, &state); > if (r) { > VHOST_OPS_DEBUG(r, "vhost_set_vring_num failed"); > @@ -1428,6 +1436,10 @@ static int do_vhost_virtqueue_stop(struct vhost_dev > *dev, > > trace_vhost_virtque_stop_in(dev, vdev->name, idx); > > + if (dev->backend_transfer) { > + return 0; > + } > + > if (virtio_queue_get_desc_addr(vdev, idx) == 0) { > /* Don't stop the virtqueue which might have not been started */ > return 0; > @@ -1565,10 +1577,14 @@ fail_call: > > static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) > { > - event_notifier_cleanup(&vq->masked_notifier); > + if (!vq->dev->backend_transfer) { > + event_notifier_cleanup(&vq->masked_notifier); > + } > if (vq->dev->vhost_ops->vhost_set_vring_err) { > event_notifier_set_handler(&vq->error_notifier, NULL); > - event_notifier_cleanup(&vq->error_notifier); > + if (!vq->dev->backend_transfer) { > + event_notifier_cleanup(&vq->error_notifier); > + } > } > } > > @@ -1635,6 +1651,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, > > hdev->vdev = NULL; > hdev->migration_blocker = NULL; > + hdev->_features_wait_incoming = true; > hdev->busyloop_timeout = busyloop_timeout; > > for (i = 0; i < hdev->nvqs; ++i) { > @@ -1717,6 +1734,8 @@ int vhost_dev_connect(struct vhost_dev *hdev, Error > **errp) > goto fail; > } > > + hdev->_features_wait_incoming = false; > + > for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) { > r = vhost_virtqueue_connect(hdev->vqs + i, hdev->vq_index + i); > if (r < 0) { > @@ -1808,8 +1827,11 @@ void vhost_dev_disable_notifiers_nvqs(struct vhost_dev > *hdev, > */ > memory_region_transaction_commit(); > > - for (i = 0; i < nvqs; ++i) { > - virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + > i); > + if (!hdev->backend_transfer) { > + for (i = 0; i < nvqs; ++i) { > + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), > + hdev->vq_index + i); > + } > } > virtio_device_release_ioeventfd(vdev); > } > @@ -1967,6 +1989,11 @@ void vhost_get_features_ex(struct vhost_dev *hdev, > { > const int *bit = feature_bits; > > + if (hdev->_features_wait_incoming) { > + /* Excessive set is enough for early initialization. */ > + return; > + } > + > while (*bit != VHOST_INVALID_FEATURE_BIT) { > if (!vhost_dev_has_feature_ex(hdev, *bit)) { > virtio_clear_feature_ex(features, *bit); > @@ -2001,6 +2028,54 @@ const VMStateDescription > vmstate_backend_transfer_vhost_inflight = { > } > }; > > +const VMStateDescription vmstate_vhost_virtqueue = { > + .name = "vhost-virtqueue", > + .fields = (const VMStateField[]) { > + VMSTATE_EVENT_NOTIFIER(error_notifier, struct vhost_virtqueue), > + VMSTATE_EVENT_NOTIFIER(masked_notifier, struct vhost_virtqueue), > + VMSTATE_END_OF_LIST() > + }, > +}; > + > +static int vhost_dev_post_load(void *opaque, int version_id) > +{ > + struct vhost_dev *hdev = opaque; > + Error *err = NULL; > + int i; > + > + if (!check_memslots(hdev, &err)) { > + error_report_err(err); > + return -EINVAL; > + } > + > + hdev->_features_wait_incoming = false; > + > + if (hdev->vhost_ops->vhost_set_vring_err) { > + for (i = 0; i < hdev->nvqs; ++i) { > + event_notifier_set_handler(&hdev->vqs[i].error_notifier, > + vhost_virtqueue_error_notifier); > + } > + } > + nit: spurious newline > + > + return 0; > +} > + > +const VMStateDescription vmstate_vhost_dev = { > + .name = "vhost-dev", > + .post_load = vhost_dev_post_load, > + .fields = (const VMStateField[]) { > + VMSTATE_UINT64(_features, struct vhost_dev), > + VMSTATE_UINT64(max_queues, struct vhost_dev), > + VMSTATE_UINT32_EQUAL(nvqs, struct vhost_dev, NULL), > + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(vqs, struct vhost_dev, > + nvqs, > + vmstate_vhost_virtqueue, > + struct vhost_virtqueue), > + VMSTATE_END_OF_LIST() > + }, > +}; > + > void vhost_ack_features_ex(struct vhost_dev *hdev, const int *feature_bits, > const uint64_t *features) > { > @@ -2127,19 +2202,24 @@ int vhost_dev_start(struct vhost_dev *hdev, > VirtIODevice *vdev, bool vrings) > hdev->started = true; > hdev->vdev = vdev; > > - r = vhost_dev_set_features(hdev, hdev->log_enabled); > - if (r < 0) { > - goto fail_features; > + if (!hdev->backend_transfer) { > + r = vhost_dev_set_features(hdev, hdev->log_enabled); > + if (r < 0) { > + warn_report("%s %d", __func__, __LINE__); > + goto fail_features; > + } > } > > if (vhost_dev_has_iommu(hdev)) { > memory_listener_register(&hdev->iommu_listener, vdev->dma_as); > } > > - r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); > - if (r < 0) { > - VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); > - goto fail_mem; > + if (!hdev->backend_transfer) { > + r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); > + if (r < 0) { > + VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); > + goto fail_mem; > + } > } > for (i = 0; i < hdev->nvqs; ++i) { > r = vhost_virtqueue_start(hdev, > @@ -2179,13 +2259,13 @@ int vhost_dev_start(struct vhost_dev *hdev, > VirtIODevice *vdev, bool vrings) > } > vhost_dev_elect_mem_logger(hdev, true); > } > - if (vrings) { > + if (vrings && !hdev->backend_transfer) { > r = vhost_dev_set_vring_enable(hdev, true); > if (r) { > goto fail_log; > } > } > - if (hdev->vhost_ops->vhost_dev_start) { > + if (hdev->vhost_ops->vhost_dev_start && !hdev->backend_transfer) { > r = hdev->vhost_ops->vhost_dev_start(hdev, true); > if (r) { > goto fail_start; > @@ -2207,6 +2287,8 @@ int vhost_dev_start(struct vhost_dev *hdev, > VirtIODevice *vdev, bool vrings) > } > vhost_start_config_intr(hdev); > > + hdev->backend_transfer = false; > + > trace_vhost_dev_start_out(hdev, vdev->name); > return 0; > fail_iotlb: > @@ -2262,9 +2344,18 @@ static int do_vhost_dev_stop(struct vhost_dev *hdev, > VirtIODevice *vdev, > if (hdev->vhost_ops->vhost_dev_start) { > hdev->vhost_ops->vhost_dev_start(hdev, false); > } > - if (vrings) { > + if (vrings && !hdev->backend_transfer) { > vhost_dev_set_vring_enable(hdev, false); > } > + > + if (hdev->backend_transfer) { > + for (i = 0; i < hdev->nvqs; ++i) { > + struct vhost_virtqueue *vq = hdev->vqs + i; > + > + event_notifier_set_handler(&vq->error_notifier, NULL); > + } > + } > + > for (i = 0; i < hdev->nvqs; ++i) { > rc |= do_vhost_virtqueue_stop(hdev, > vdev, > diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h > index 94a0c75fc8..55ad822848 100644 > --- a/include/hw/virtio/vhost.h > +++ b/include/hw/virtio/vhost.h > @@ -105,6 +105,9 @@ struct vhost_dev { > VIRTIO_DECLARE_FEATURES(_features); > VIRTIO_DECLARE_FEATURES(acked_features); > > + bool _features_wait_incoming; > + bool backend_transfer; > + > uint32_t busyloop_timeout; > uint64_t max_queues; > uint64_t backend_cap; > @@ -592,4 +595,8 @@ extern const VMStateDescription > vmstate_backend_transfer_vhost_inflight; > VMSTATE_STRUCT_POINTER(_field, _state, vmstate_inflight, \ > struct vhost_inflight) > > +extern const VMStateDescription vmstate_vhost_dev; > +#define VMSTATE_BACKEND_TRANSFER_VHOST(_field, _state) \ > + VMSTATE_STRUCT(_field, _state, 0, vmstate_vhost_dev, struct vhost_dev) > + > #endif > -- > 2.48.1 > >
