aboutsummaryrefslogtreecommitdiff
path: root/hw/virtio/vhost-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/virtio/vhost-backend.c')
-rw-r--r--hw/virtio/vhost-backend.c62
1 files changed, 51 insertions, 11 deletions
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 833804d..4367db0 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -20,6 +20,11 @@
#include <linux/vhost.h>
#include <sys/ioctl.h>
+struct vhost_features {
+ uint64_t count;
+ uint64_t features[VIRTIO_FEATURES_NU64S];
+};
+
static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
void *arg)
{
@@ -182,12 +187,6 @@ static int vhost_kernel_get_vring_worker(struct vhost_dev *dev,
return vhost_kernel_call(dev, VHOST_GET_VRING_WORKER, worker);
}
-static int vhost_kernel_set_features(struct vhost_dev *dev,
- uint64_t features)
-{
- return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
-}
-
static int vhost_kernel_set_backend_cap(struct vhost_dev *dev)
{
uint64_t features;
@@ -210,10 +209,51 @@ static int vhost_kernel_set_backend_cap(struct vhost_dev *dev)
return 0;
}
-static int vhost_kernel_get_features(struct vhost_dev *dev,
- uint64_t *features)
+static int vhost_kernel_set_features(struct vhost_dev *dev,
+ const uint64_t *features)
{
- return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
+ struct vhost_features farray;
+ bool extended_in_use;
+ int r;
+
+ farray.count = VIRTIO_FEATURES_NU64S;
+ virtio_features_copy(farray.features, features);
+ extended_in_use = virtio_features_use_ex(farray.features);
+
+ /*
+ * Can't check for ENOTTY: for unknown ioctls the kernel interprets
+ * the argument as a virtio queue id and most likely errors out validating
+ * such id, instead of reporting an unknown operation.
+ */
+ r = vhost_kernel_call(dev, VHOST_SET_FEATURES_ARRAY, &farray);
+ if (!r) {
+ return 0;
+ }
+
+ if (extended_in_use) {
+ error_report("Trying to set extended features without kernel support");
+ return -EINVAL;
+ }
+ return vhost_kernel_call(dev, VHOST_SET_FEATURES, &farray.features[0]);
+}
+
+static int vhost_kernel_get_features(struct vhost_dev *dev, uint64_t *features)
+{
+ struct vhost_features farray;
+ int r;
+
+ farray.count = VIRTIO_FEATURES_NU64S;
+ r = vhost_kernel_call(dev, VHOST_GET_FEATURES_ARRAY, &farray);
+ if (r) {
+ memset(&farray, 0, sizeof(farray));
+ r = vhost_kernel_call(dev, VHOST_GET_FEATURES, &farray.features[0]);
+ }
+ if (r) {
+ return r;
+ }
+
+ virtio_features_copy(features, farray.features);
+ return 0;
}
static int vhost_kernel_set_owner(struct vhost_dev *dev)
@@ -341,8 +381,8 @@ const VhostOps kernel_ops = {
.vhost_attach_vring_worker = vhost_kernel_attach_vring_worker,
.vhost_new_worker = vhost_kernel_new_worker,
.vhost_free_worker = vhost_kernel_free_worker,
- .vhost_set_features = vhost_kernel_set_features,
- .vhost_get_features = vhost_kernel_get_features,
+ .vhost_set_features_ex = vhost_kernel_set_features,
+ .vhost_get_features_ex = vhost_kernel_get_features,
.vhost_set_backend_cap = vhost_kernel_set_backend_cap,
.vhost_set_owner = vhost_kernel_set_owner,
.vhost_get_vq_index = vhost_kernel_get_vq_index,