mirror of https://github.com/xemu-project/xemu.git
Add vhost_ops to vhost_dev struct and replace all relevant ioctls
Decouple vhost from the Linux kernel by introducing vhost_ops. The intention is to provide different backends - a 'kernel' backend based on the ioctl interface, and an 'user' backend based on a UNIX domain socket and shared memory interface. Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com> Signed-off-by: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
81647a655f
commit
24d1eb33eb
|
@ -27,7 +27,6 @@
|
|||
#include <sys/socket.h>
|
||||
#include <linux/kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/virtio_ring.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h>
|
||||
|
@ -177,7 +176,8 @@ static int vhost_net_start_one(struct vhost_net *net,
|
|||
qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
|
||||
file.fd = net->backend;
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, &file);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
@ -187,7 +187,8 @@ static int vhost_net_start_one(struct vhost_net *net,
|
|||
fail:
|
||||
file.fd = -1;
|
||||
while (file.index-- > 0) {
|
||||
int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
if (net->nc->info->poll) {
|
||||
|
@ -210,7 +211,8 @@ static void vhost_net_stop_one(struct vhost_net *net,
|
|||
}
|
||||
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
if (net->nc->info->poll) {
|
||||
|
|
|
@ -36,12 +36,13 @@ static const int kernel_feature_bits[] = {
|
|||
static int vhost_scsi_set_endpoint(VHostSCSI *s)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
const VhostOps *vhost_ops = s->dev.vhost_ops;
|
||||
struct vhost_scsi_target backend;
|
||||
int ret;
|
||||
|
||||
memset(&backend, 0, sizeof(backend));
|
||||
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
|
||||
ret = ioctl(s->dev.control, VHOST_SCSI_SET_ENDPOINT, &backend);
|
||||
ret = vhost_ops->vhost_call(&s->dev, VHOST_SCSI_SET_ENDPOINT, &backend);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
@ -52,10 +53,11 @@ static void vhost_scsi_clear_endpoint(VHostSCSI *s)
|
|||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
struct vhost_scsi_target backend;
|
||||
const VhostOps *vhost_ops = s->dev.vhost_ops;
|
||||
|
||||
memset(&backend, 0, sizeof(backend));
|
||||
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
|
||||
ioctl(s->dev.control, VHOST_SCSI_CLEAR_ENDPOINT, &backend);
|
||||
vhost_ops->vhost_call(&s->dev, VHOST_SCSI_CLEAR_ENDPOINT, &backend);
|
||||
}
|
||||
|
||||
static int vhost_scsi_start(VHostSCSI *s)
|
||||
|
@ -64,13 +66,15 @@ static int vhost_scsi_start(VHostSCSI *s)
|
|||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
const VhostOps *vhost_ops = s->dev.vhost_ops;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = ioctl(s->dev.control, VHOST_SCSI_GET_ABI_VERSION, &abi_version);
|
||||
ret = vhost_ops->vhost_call(&s->dev,
|
||||
VHOST_SCSI_GET_ABI_VERSION, &abi_version);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/atomic.h"
|
||||
|
@ -289,7 +288,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
|
|||
|
||||
log = g_malloc0(size * sizeof *log);
|
||||
log_base = (uint64_t)(unsigned long)log;
|
||||
r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_LOG_BASE, &log_base);
|
||||
assert(r >= 0);
|
||||
/* Sync only the range covered by the old log */
|
||||
if (dev->log_size) {
|
||||
|
@ -456,7 +455,7 @@ static void vhost_commit(MemoryListener *listener)
|
|||
}
|
||||
|
||||
if (!dev->log_enabled) {
|
||||
r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
assert(r >= 0);
|
||||
dev->memory_changed = false;
|
||||
return;
|
||||
|
@ -469,7 +468,7 @@ static void vhost_commit(MemoryListener *listener)
|
|||
if (dev->log_size < log_size) {
|
||||
vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
|
||||
}
|
||||
r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
assert(r >= 0);
|
||||
/* To log less, can only decrease log size after table update. */
|
||||
if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
|
||||
|
@ -537,7 +536,7 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
|
|||
.log_guest_addr = vq->used_phys,
|
||||
.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
|
||||
};
|
||||
int r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
|
||||
int r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ADDR, &addr);
|
||||
if (r < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
@ -551,7 +550,7 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
|
|||
if (enable_log) {
|
||||
features |= 0x1 << VHOST_F_LOG_ALL;
|
||||
}
|
||||
r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_FEATURES, &features);
|
||||
return r < 0 ? -errno : 0;
|
||||
}
|
||||
|
||||
|
@ -664,13 +663,13 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
|
||||
|
||||
vq->num = state.num = virtio_queue_get_num(vdev, idx);
|
||||
r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_NUM, &state);
|
||||
if (r) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
state.num = virtio_queue_get_last_avail_idx(vdev, idx);
|
||||
r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_BASE, &state);
|
||||
if (r) {
|
||||
return -errno;
|
||||
}
|
||||
|
@ -712,7 +711,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
}
|
||||
|
||||
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
|
||||
r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_KICK, &file);
|
||||
if (r) {
|
||||
r = -errno;
|
||||
goto fail_kick;
|
||||
|
@ -750,7 +749,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
|||
};
|
||||
int r;
|
||||
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
|
||||
r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_GET_VRING_BASE, &state);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
|
||||
fflush(stderr);
|
||||
|
@ -792,7 +791,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
|
|||
}
|
||||
|
||||
file.fd = event_notifier_get_fd(&vq->masked_notifier);
|
||||
r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_CALL, &file);
|
||||
if (r) {
|
||||
r = -errno;
|
||||
goto fail_call;
|
||||
|
@ -813,14 +812,17 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
|||
{
|
||||
uint64_t features;
|
||||
int i, r;
|
||||
hdev->control = (uintptr_t) opaque;;
|
||||
|
||||
r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);
|
||||
if (hdev->vhost_ops->vhost_backend_init(hdev, opaque) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_OWNER, NULL);
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_GET_FEATURES, &features);
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -865,7 +867,7 @@ fail_vq:
|
|||
}
|
||||
fail:
|
||||
r = -errno;
|
||||
close(hdev->control);
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -878,7 +880,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
|
|||
memory_listener_unregister(&hdev->memory_listener);
|
||||
g_free(hdev->mem);
|
||||
g_free(hdev->mem_sections);
|
||||
close(hdev->control);
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
}
|
||||
|
||||
bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
|
@ -980,7 +982,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
|
|||
} else {
|
||||
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
|
||||
}
|
||||
r = ioctl(hdev->control, VHOST_SET_VRING_CALL, &file);
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_VRING_CALL, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
|
||||
|
@ -1022,7 +1024,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
if (r < 0) {
|
||||
goto fail_features;
|
||||
}
|
||||
r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_MEM_TABLE, hdev->mem);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail_mem;
|
||||
|
@ -1041,8 +1043,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
hdev->log_size = vhost_get_log_size(hdev);
|
||||
hdev->log = hdev->log_size ?
|
||||
g_malloc0(hdev->log_size * sizeof *hdev->log) : NULL;
|
||||
r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
|
||||
(uint64_t)(unsigned long)hdev->log);
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_LOG_BASE, hdev->log);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail_log;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* vhost-backend
|
||||
*
|
||||
* Copyright (c) 2013 Virtual Open Systems Sarl.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VHOST_BACKEND_H_
|
||||
#define VHOST_BACKEND_H_
|
||||
|
||||
struct vhost_dev;
|
||||
|
||||
typedef int (*vhost_call)(struct vhost_dev *dev, unsigned long int request,
|
||||
void *arg);
|
||||
typedef int (*vhost_backend_init)(struct vhost_dev *dev, void *opaque);
|
||||
typedef int (*vhost_backend_cleanup)(struct vhost_dev *dev);
|
||||
|
||||
typedef struct VhostOps {
|
||||
vhost_call vhost_call;
|
||||
vhost_backend_init vhost_backend_init;
|
||||
vhost_backend_cleanup vhost_backend_cleanup;
|
||||
} VhostOps;
|
||||
|
||||
#endif /* VHOST_BACKEND_H_ */
|
|
@ -2,6 +2,7 @@
|
|||
#define VHOST_H
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/virtio/vhost-backend.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "exec/memory.h"
|
||||
|
||||
|
@ -49,6 +50,7 @@ struct vhost_dev {
|
|||
bool memory_changed;
|
||||
hwaddr mem_changed_start_addr;
|
||||
hwaddr mem_changed_end_addr;
|
||||
const VhostOps *vhost_ops;
|
||||
};
|
||||
|
||||
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
|
|
Loading…
Reference in New Issue