Now we have detected and validated the protocol support lets do the probe. The empty state indicates no probe took place.
Signed-off-by: Alex Bennée <alex.ben...@linaro.org> --- include/hw/virtio/vhost.h | 12 +++++++ hw/virtio/vhost-user.c | 73 +++++++++++++++++++++++++++++++++++---- hw/virtio/vhost.c | 2 +- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 912706668a..1d8de1c558 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -68,6 +68,13 @@ typedef struct VhostDevConfigOps { struct vhost_memory; +typedef struct VhostUserBackendSpecs { + uint32_t device_id; + uint32_t config_size; + uint32_t min_vqs; + uint32_t max_vqs; +} VhostUserBackendSpecs; + /** * struct vhost_dev - common vhost_dev structure * @vhost_ops: backend specific ops @@ -107,11 +114,15 @@ struct vhost_dev { * VHOST_USER_SET_FEATURES or VHOST_NET_F_VIRTIO_NET_HDR. Its * future use should be discouraged and the variable retired as * its easy to confuse with the VirtIO backend_features. + * + * @specs: the results of a GET_BACKEND_SPECS probe. */ uint64_t features; uint64_t acked_features; uint64_t backend_features; + VhostUserBackendSpecs specs; + /** * @protocol_features: is the vhost-user only feature set by * VHOST_USER_SET_PROTOCOL_FEATURES. Protocol features are only @@ -134,6 +145,7 @@ struct vhost_dev { QLIST_HEAD(, vhost_iommu) iommu_list; IOMMUNotifier n; const VhostDevConfigOps *config_ops; + }; extern const VhostOps kernel_ops; diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 3116b3e46a..36aa4ec2d5 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -123,6 +123,7 @@ typedef enum VhostUserRequest { VHOST_USER_REM_MEM_REG = 38, VHOST_USER_SET_STATUS = 39, VHOST_USER_GET_STATUS = 40, + VHOST_USER_GET_BACKEND_SPECS = 41, VHOST_USER_MAX } VhostUserRequest; @@ -204,13 +205,6 @@ typedef struct VhostUserInflight { uint16_t queue_size; } VhostUserInflight; -typedef struct VhostUserBackendSpecs { - uint32_t device_id; - uint32_t config_size; - uint32_t min_vqs; - uint32_t max_vqs; -} VhostUserBackendSpecs; - typedef struct { VhostUserRequest request; @@ -1991,6 +1985,56 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, return 0; } +static bool vhost_user_get_backend_specs(struct vhost_dev *dev, Error **errp) +{ + int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GET_BACKEND_SPECS, + .hdr.flags = VHOST_USER_VERSION, + .hdr.size = VHOST_USER_HDR_SIZE, + }; + + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_STANDALONE)) { + error_setg(errp, "VHOST_USER_PROTOCOL_F_STANDALONE not supported"); + return -EINVAL; + } + + ret = vhost_user_write(dev, &msg, NULL, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "vhost_get_backend send failed"); + return ret; + } + + ret = vhost_user_read(dev, &msg); + if (ret < 0) { + error_setg_errno(errp, -ret, "vhost_get_backend recv failed"); + return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_BACKEND_SPECS) { + error_setg(errp, + "Received unexpected msg type. Expected %d received %d", + VHOST_USER_GET_BACKEND_SPECS, msg.hdr.request); + return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.specs)) { + error_setg(errp, "Received bad msg size."); + return -EPROTO; + } + + if (msg.payload.specs.config_size && !virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + error_setg(errp, "VHOST_USER_PROTOCOL_F_CONFIG not supported"); + return -EPROTO; + } + + dev->specs = msg.payload.specs; + + return 0; +} + static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, Error **errp) { @@ -2073,6 +2117,21 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, return -EPROTO; } + if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_STANDALONE)) { + err = vhost_user_get_backend_specs(dev, errp); + if (err < 0) { + error_setg_errno(errp, EPROTO, "vhost_get_backend_specs failed"); + return -EPROTO; + } + /* + * If this was never set by the user we can now fill it in + * so we can continue the initialisation + */ + if (!dev->nvqs) { + dev->nvqs = dev->specs.min_vqs; + } + } + /* query the max queues we support if backend supports Multiple Queue */ if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) { err = vhost_user_get_u64(dev, VHOST_USER_GET_QUEUE_NUM, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 4c73ced3b7..d14467aa1c 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1450,7 +1450,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, } /* Skip if we don't yet have number of vqs */ - if (hdev->vqs && hdev->nvqs) { + if (hdev->nvqs) { if (!vhost_init_virtqs(hdev, busyloop_timeout, errp)) { goto fail_busyloop; } -- 2.39.2