virtio: add start_ioeventfd and stop_ioeventfd to VirtioDeviceClass

Allow customization of the start and stop of ioeventfd.  This will
allow direct start of dataplane without passing through the default
ioeventfd handlers, which in turn allows using the dataplane logic
instead of virtio_add_queue_aio.  It will also enable some code
simplification, because the sole entry point to ioeventfd setup
will be virtio_bus_set_host_notifier.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Paolo Bonzini 2016-10-21 22:48:07 +02:00 committed by Michael S. Tsirkin
parent b13d396227
commit ff4c07df67
4 changed files with 91 additions and 38 deletions

View File

@ -153,8 +153,8 @@ void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
* assign: register/deregister ioeventfd with the kernel * assign: register/deregister ioeventfd with the kernel
* set_handler: use the generic ioeventfd handler * set_handler: use the generic ioeventfd handler
*/ */
static int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus, int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus,
int n, bool assign, bool set_handler) int n, bool assign, bool set_handler)
{ {
VirtIODevice *vdev = virtio_bus_get_device(bus); VirtIODevice *vdev = virtio_bus_get_device(bus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
@ -185,61 +185,41 @@ static int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus,
return r; return r;
} }
void virtio_bus_start_ioeventfd(VirtioBusState *bus) int virtio_bus_start_ioeventfd(VirtioBusState *bus)
{ {
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
DeviceState *proxy = DEVICE(BUS(bus)->parent); DeviceState *proxy = DEVICE(BUS(bus)->parent);
VirtIODevice *vdev; VirtIODevice *vdev = virtio_bus_get_device(bus);
int n, r; VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
int r;
if (!k->ioeventfd_assign || k->ioeventfd_disabled(proxy)) { if (!k->ioeventfd_assign || k->ioeventfd_disabled(proxy)) {
return; return -ENOSYS;
} }
if (bus->ioeventfd_started || bus->ioeventfd_disabled) { if (bus->ioeventfd_started || bus->ioeventfd_disabled) {
return; return 0;
} }
vdev = virtio_bus_get_device(bus); r = vdc->start_ioeventfd(vdev);
for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { if (r < 0) {
if (!virtio_queue_get_num(vdev, n)) { error_report("%s: failed. Fallback to userspace (slower).", __func__);
continue; return r;
}
r = set_host_notifier_internal(proxy, bus, n, true, true);
if (r < 0) {
goto assign_error;
}
} }
bus->ioeventfd_started = true; bus->ioeventfd_started = true;
return; return 0;
assign_error:
while (--n >= 0) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
r = set_host_notifier_internal(proxy, bus, n, false, false);
assert(r >= 0);
}
error_report("%s: failed. Fallback to userspace (slower).", __func__);
} }
void virtio_bus_stop_ioeventfd(VirtioBusState *bus) void virtio_bus_stop_ioeventfd(VirtioBusState *bus)
{ {
DeviceState *proxy = DEVICE(BUS(bus)->parent);
VirtIODevice *vdev; VirtIODevice *vdev;
int n, r; VirtioDeviceClass *vdc;
if (!bus->ioeventfd_started) { if (!bus->ioeventfd_started) {
return; return;
} }
vdev = virtio_bus_get_device(bus); vdev = virtio_bus_get_device(bus);
for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
if (!virtio_queue_get_num(vdev, n)) { vdc->stop_ioeventfd(vdev);
continue;
}
r = set_host_notifier_internal(proxy, bus, n, false, false);
assert(r >= 0);
}
bus->ioeventfd_started = false; bus->ioeventfd_started = false;
} }

View File

@ -2172,15 +2172,79 @@ static Property virtio_properties[] = {
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
static int virtio_device_start_ioeventfd_impl(VirtIODevice *vdev)
{
VirtioBusState *qbus = VIRTIO_BUS(qdev_get_parent_bus(DEVICE(vdev)));
DeviceState *proxy = DEVICE(BUS(qbus)->parent);
int n, r, err;
for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
r = set_host_notifier_internal(proxy, qbus, n, true, true);
if (r < 0) {
err = r;
goto assign_error;
}
}
return 0;
assign_error:
while (--n >= 0) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
r = set_host_notifier_internal(proxy, qbus, n, false, false);
assert(r >= 0);
}
return err;
}
int virtio_device_start_ioeventfd(VirtIODevice *vdev)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
return virtio_bus_start_ioeventfd(vbus);
}
static void virtio_device_stop_ioeventfd_impl(VirtIODevice *vdev)
{
VirtioBusState *qbus = VIRTIO_BUS(qdev_get_parent_bus(DEVICE(vdev)));
DeviceState *proxy = DEVICE(BUS(qbus)->parent);
int n, r;
for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
r = set_host_notifier_internal(proxy, qbus, n, false, false);
assert(r >= 0);
}
}
void virtio_device_stop_ioeventfd(VirtIODevice *vdev)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
virtio_bus_stop_ioeventfd(vbus);
}
static void virtio_device_class_init(ObjectClass *klass, void *data) static void virtio_device_class_init(ObjectClass *klass, void *data)
{ {
/* Set the default value here. */ /* Set the default value here. */
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = virtio_device_realize; dc->realize = virtio_device_realize;
dc->unrealize = virtio_device_unrealize; dc->unrealize = virtio_device_unrealize;
dc->bus_type = TYPE_VIRTIO_BUS; dc->bus_type = TYPE_VIRTIO_BUS;
dc->props = virtio_properties; dc->props = virtio_properties;
vdc->start_ioeventfd = virtio_device_start_ioeventfd_impl;
vdc->stop_ioeventfd = virtio_device_stop_ioeventfd_impl;
} }
static const TypeInfo virtio_device_info = { static const TypeInfo virtio_device_info = {

View File

@ -132,10 +132,15 @@ static inline VirtIODevice *virtio_bus_get_device(VirtioBusState *bus)
} }
/* Start the ioeventfd. */ /* Start the ioeventfd. */
void virtio_bus_start_ioeventfd(VirtioBusState *bus); int virtio_bus_start_ioeventfd(VirtioBusState *bus);
/* Stop the ioeventfd. */ /* Stop the ioeventfd. */
void virtio_bus_stop_ioeventfd(VirtioBusState *bus); void virtio_bus_stop_ioeventfd(VirtioBusState *bus);
/* Switch from/to the generic ioeventfd handler */ /* Switch from/to the generic ioeventfd handler */
int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign); int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign);
/* This is temporary. It is only needed because virtio_bus_set_host_notifier
* sets ioeventfd_disabled but we will shortly get rid of it. */
int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus,
int n, bool assign, bool set_handler);
#endif /* VIRTIO_BUS_H */ #endif /* VIRTIO_BUS_H */

View File

@ -125,6 +125,8 @@ typedef struct VirtioDeviceClass {
* must mask in frontend instead. * must mask in frontend instead.
*/ */
void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
int (*start_ioeventfd)(VirtIODevice *vdev);
void (*stop_ioeventfd)(VirtIODevice *vdev);
/* Saving and loading of a device; trying to deprecate save/load /* Saving and loading of a device; trying to deprecate save/load
* use vmsd for new devices. * use vmsd for new devices.
*/ */
@ -269,6 +271,8 @@ uint16_t virtio_get_queue_index(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
bool with_irqfd); bool with_irqfd);
int virtio_device_start_ioeventfd(VirtIODevice *vdev);
void virtio_device_stop_ioeventfd(VirtIODevice *vdev);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
bool set_handler); bool set_handler);