Commit c0b336ea authored by Paul Durrant's avatar Paul Durrant Committed by Anthony PERARD
Browse files

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: default avatarPaul Durrant <paul.durrant@citrix.com>
Reviewed-by: default avatarAnthony PERARD <anthony.perard@citrix.com>
Message-Id: <20190408151617.13025-2-paul.durrant@citrix.com>
Signed-off-by: default avatarAnthony PERARD <anthony.perard@citrix.com>
parent 5feeb718
Loading
Loading
Loading
Loading
+40 −39
Original line number Diff line number Diff line
@@ -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);

    qemu_set_fd_handler(xenevtchn_fd(channel->xeh), NULL, NULL, NULL);

    if (xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) {
    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);
+2 −4
Original line number Diff line number Diff line
@@ -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,