mirror of
https://github.com/qemu/qemu.git
synced 2024-11-28 06:13:46 +08:00
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:
parent
5feeb718d7
commit
c0b336ea19
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user