xen-bus: use a separate fd for each event channel

To better support use of IOThread-s it will be necessary to be able to set
the AioContext for each XenEventChannel and hence it is necessary to open a
separate handle to libxenevtchan for each channel.

This patch stops using NotifierList for event channel callbacks, replacing
that construct by a list of complete XenEventChannel structures. Each of
these now has a xenevtchn_handle pointer in place of the single pointer
previously held in the XenDevice structure. The individual handles are
opened/closed in xen_device_bind/unbind_event_channel(), replacing the
single open/close in xen_device_realize/unrealize().

NOTE: This patch does not add an AioContext parameter to
      xen_device_bind_event_channel(). That will be done in a subsequent
      patch.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
Message-Id: <20190408151617.13025-2-paul.durrant@citrix.com>
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
This commit is contained in:
Paul Durrant 2019-04-08 16:16:15 +01:00 committed by Anthony PERARD
parent 5feeb718d7
commit c0b336ea19
2 changed files with 42 additions and 43 deletions

View File

@ -924,19 +924,22 @@ done:
}
struct XenEventChannel {
QLIST_ENTRY(XenEventChannel) list;
xenevtchn_handle *xeh;
evtchn_port_t local_port;
XenEventHandler handler;
void *opaque;
Notifier notifier;
};
static void event_notify(Notifier *n, void *data)
static void xen_device_event(void *opaque)
{
XenEventChannel *channel = container_of(n, XenEventChannel, notifier);
unsigned long port = (unsigned long)data;
XenEventChannel *channel = opaque;
unsigned long port = xenevtchn_pending(channel->xeh);
if (port == channel->local_port) {
channel->handler(channel->opaque);
xenevtchn_unmask(channel->xeh, port);
}
}
@ -948,24 +951,39 @@ XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
XenEventChannel *channel = g_new0(XenEventChannel, 1);
xenevtchn_port_or_error_t local_port;
local_port = xenevtchn_bind_interdomain(xendev->xeh,
channel->xeh = xenevtchn_open(NULL, 0);
if (!channel->xeh) {
error_setg_errno(errp, errno, "failed xenevtchn_open");
goto fail;
}
local_port = xenevtchn_bind_interdomain(channel->xeh,
xendev->frontend_id,
port);
if (local_port < 0) {
error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
g_free(channel);
return NULL;
goto fail;
}
channel->local_port = local_port;
channel->handler = handler;
channel->opaque = opaque;
channel->notifier.notify = event_notify;
notifier_list_add(&xendev->event_notifiers, &channel->notifier);
qemu_set_fd_handler(xenevtchn_fd(channel->xeh), xen_device_event, NULL,
channel);
QLIST_INSERT_HEAD(&xendev->event_channels, channel, list);
return channel;
fail:
if (channel->xeh) {
xenevtchn_close(channel->xeh);
}
g_free(channel);
return NULL;
}
void xen_device_notify_event_channel(XenDevice *xendev,
@ -977,7 +995,7 @@ void xen_device_notify_event_channel(XenDevice *xendev,
return;
}
if (xenevtchn_notify(xendev->xeh, channel->local_port) < 0) {
if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) {
error_setg_errno(errp, errno, "xenevtchn_notify failed");
}
}
@ -991,12 +1009,15 @@ void xen_device_unbind_event_channel(XenDevice *xendev,
return;
}
notifier_remove(&channel->notifier);
QLIST_REMOVE(channel, list);
if (xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) {
qemu_set_fd_handler(xenevtchn_fd(channel->xeh), NULL, NULL, NULL);
if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) {
error_setg_errno(errp, errno, "xenevtchn_unbind failed");
}
xenevtchn_close(channel->xeh);
g_free(channel);
}
@ -1005,6 +1026,7 @@ static void xen_device_unrealize(DeviceState *dev, Error **errp)
XenDevice *xendev = XEN_DEVICE(dev);
XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
const char *type = object_get_typename(OBJECT(xendev));
XenEventChannel *channel, *next;
if (!xendev->name) {
return;
@ -1021,15 +1043,14 @@ static void xen_device_unrealize(DeviceState *dev, Error **errp)
xendev_class->unrealize(xendev, errp);
}
/* Make sure all event channels are cleaned up */
QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) {
xen_device_unbind_event_channel(xendev, channel, NULL);
}
xen_device_frontend_destroy(xendev);
xen_device_backend_destroy(xendev);
if (xendev->xeh) {
qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), NULL, NULL, NULL);
xenevtchn_close(xendev->xeh);
xendev->xeh = NULL;
}
if (xendev->xgth) {
xengnttab_close(xendev->xgth);
xendev->xgth = NULL;
@ -1046,16 +1067,6 @@ static void xen_device_exit(Notifier *n, void *data)
xen_device_unrealize(DEVICE(xendev), &error_abort);
}
static void xen_device_event(void *opaque)
{
XenDevice *xendev = opaque;
unsigned long port = xenevtchn_pending(xendev->xeh);
notifier_list_notify(&xendev->event_notifiers, (void *)port);
xenevtchn_unmask(xendev->xeh, port);
}
static void xen_device_realize(DeviceState *dev, Error **errp)
{
XenDevice *xendev = XEN_DEVICE(dev);
@ -1096,16 +1107,6 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
xendev->feature_grant_copy =
(xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
xendev->xeh = xenevtchn_open(NULL, 0);
if (!xendev->xeh) {
error_setg_errno(errp, errno, "failed xenevtchn_open");
goto unrealize;
}
notifier_list_init(&xendev->event_notifiers);
qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), xen_device_event, NULL,
xendev);
xen_device_backend_create(xendev, &local_err);
if (local_err) {
error_propagate(errp, local_err);

View File

@ -15,6 +15,7 @@
typedef void (*XenWatchHandler)(void *opaque);
typedef struct XenWatch XenWatch;
typedef struct XenEventChannel XenEventChannel;
typedef struct XenDevice {
DeviceState qdev;
@ -28,8 +29,7 @@ typedef struct XenDevice {
XenWatch *backend_online_watch;
xengnttab_handle *xgth;
bool feature_grant_copy;
xenevtchn_handle *xeh;
NotifierList event_notifiers;
QLIST_HEAD(, XenEventChannel) event_channels;
} XenDevice;
typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp);
@ -119,8 +119,6 @@ void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
XenDeviceGrantCopySegment segs[],
unsigned int nr_segs, Error **errp);
typedef struct XenEventChannel XenEventChannel;
typedef void (*XenEventHandler)(void *opaque);
XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,