vhost-backend: implement extended features support

Leverage the kernel extended features manipulation ioctls(), if
available, and fallback to old ops otherwise. Error out when setting
extended features but kernel support is not available.

Note that extended support for get/set backend features is not needed,
as the only feature that can be changed belongs to the 64 bit range.

Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Tested-by: Lei Yang <leiyang@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <150daade3d59e77629276920e014ee8e5fc12121.1758549625.git.pabeni@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Paolo Abeni 2025-09-22 16:18:24 +02:00 committed by Michael S. Tsirkin
parent a76f5b795c
commit f412c1f57a

View file

@ -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,