bool discard_enable;
unsigned int max_ring_page_order;
BlockBackend *blk;
+ unsigned int nr_ring_ref;
+ uint32_t *ring_ref;
+ unsigned int protocol;
+ unsigned int max_requests;
+ xenevtchn_handle *xeh;
+ xenevtchn_port_or_error_t event_channel;
+ xengnttab_handle *xgth;
+ void *sring;
+ blkif_back_rings_t rings;
+
+ /* data path */
+ AioContext *ctx;
+ QEMUBH *bh;
+
} XenQdiskBackend;
static char *xen_qdisk_get_name(XenBackend *dev, Error **errp)
return g_strdup_printf("%u", number);
}
+static void xen_qdisk_bh(void *opaque)
+{
+}
+
static void xen_qdisk_realize(XenBackend *dev, Error **errp)
{
XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
d->conf.logical_block_size);
xenstore_backend_printf(dev, "sectors", "%lu",
size / d->conf.logical_block_size);
+
+ d->ctx = qemu_get_aio_context();
+ d->bh = aio_bh_new(d->ctx, xen_qdisk_bh, d);
+}
+
+static void xenevtchn_event_handler(void *opaque)
+{
+ XenQdiskBackend *d = opaque;
+ evtchn_port_t event_channel;
+
+ event_channel = xenevtchn_pending(d->xeh);
+ if (event_channel != d->event_channel)
+ return;
+
+ xenevtchn_unmask(d->xeh, event_channel);
+
+ qemu_bh_schedule(d->bh);
}
static void xen_qdisk_initialize(XenBackend *dev, Error **errp)
{
+ XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
+ unsigned int order, ring_ref, event_channel;
+ char *protocol;
+ unsigned int i;
+ unsigned int ring_size;
+ uint32_t *domids;
+
+ if (xenstore_frontend_scanf(dev, "ring-page-order", "%u",
+ &order) != 1) {
+ d->nr_ring_ref = 1u;
+ d->ring_ref = g_new(uint32_t, d->nr_ring_ref);
+
+ if (xenstore_frontend_scanf(dev, "ring-ref", "%u",
+ &ring_ref) != 1) {
+ error_setg(errp, "failed to read ring-ref");
+ return;
+ }
+
+ d->ring_ref[0] = ring_ref;
+ } else if (order <= d->max_ring_page_order) {
+ d->nr_ring_ref = 1u << order;
+ d->ring_ref = g_new(uint32_t, d->nr_ring_ref);
+
+ for (i = 0; i < d->nr_ring_ref; i++) {
+ const char *key = g_strdup_printf("ring-ref%u", i);
+
+ if (xenstore_frontend_scanf(dev, key, "%u", &ring_ref) != 1) {
+ error_setg(errp, "failed to read %s", key);
+ g_free((gpointer)key);
+ return;
+ }
+
+ d->ring_ref[i] = ring_ref;
+ g_free((gpointer)key);
+ }
+ } else {
+ error_setg(errp, "invalid ring-page-order (%d)", order);
+ return;
+ }
+
+ if (xenstore_frontend_scanf(dev, "event-channel", "%u",
+ &event_channel) != 1) {
+ error_setg(errp, "failed to read event-channel");
+ return;
+ }
+
+ if (xenstore_frontend_scanf(dev, "protocol", "%ms", &protocol) != 1) {
+ d->protocol = BLKIF_PROTOCOL_NATIVE;
+ } else {
+ if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+ d->protocol = BLKIF_PROTOCOL_X86_32;
+ } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+ d->protocol = BLKIF_PROTOCOL_X86_64;
+ } else {
+ d->protocol = BLKIF_PROTOCOL_NATIVE;
+ }
+
+ free(protocol);
+ }
+
+ ring_size = XC_PAGE_SIZE * d->nr_ring_ref;
+ switch (d->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ d->max_requests = __CONST_RING_SIZE(blkif, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ d->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ d->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
+ break;
+ }
+ }
+
+ d->xgth = xengnttab_open(NULL, 0);
+ if (!d->xgth) {
+ error_setg_errno(errp, errno, "failed xengnttab_open");
+ return;
+ }
+
+ if (xengnttab_set_max_grants(d->xgth, d->nr_ring_ref)) {
+ error_setg_errno(errp, errno, "failed xengnttab_set_max_grants");
+ return;
+ }
+
+ domids = (uint32_t *)g_new0(domid_t, d->nr_ring_ref);
+ for (i = 0; i < d->nr_ring_ref; i++) {
+ domids[i] = dev->frontend_id;
+ }
+
+ d->sring = xengnttab_map_grant_refs(d->xgth, d->nr_ring_ref, domids,
+ d->ring_ref,
+ PROT_READ | PROT_WRITE);
+
+ g_free(domids);
+
+ if (!d->sring) {
+ error_setg_errno(errp, errno, "failed xengnttab_map_grant_refs");
+ return;
+ }
+
+ switch (d->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ blkif_sring_t *sring_native = d->sring;
+ BACK_RING_INIT(&d->rings.native, sring_native, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ blkif_x86_32_sring_t *sring_x86_32 = d->sring;
+
+ BACK_RING_INIT(&d->rings.x86_32_part, sring_x86_32, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ blkif_x86_64_sring_t *sring_x86_64 = d->sring;
+
+ BACK_RING_INIT(&d->rings.x86_64_part, sring_x86_64, ring_size);
+ break;
+ }
+ }
+
+ d->xeh = xenevtchn_open(NULL, 0);
+ if (!d->xeh) {
+ error_setg_errno(errp, errno, "failed xenevtchn_open");
+ return;
+ }
+
+ qemu_set_fd_handler(xenevtchn_fd(d->xeh), xenevtchn_event_handler,
+ NULL, d);
+
+ d->event_channel = xenevtchn_bind_interdomain(d->xeh, dev->frontend_id,
+ event_channel);
+ if (d->event_channel == -1) {
+ error_setg_errno(errp, errno, "failed xenevtchn_bind_interdomain");
+ return;
+ }
+
+ blk_set_aio_context(d->blk, d->ctx);
}
static void xen_qdisk_disconnect(XenBackend *dev, Error **errp)
{
-}
+ XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
-static void xen_qdisk_event(XenBackend *dev)
-{
+ aio_context_acquire(d->ctx);
+
+ xenevtchn_unbind(d->xeh, d->event_channel);
+ qemu_set_fd_handler(xenevtchn_fd(d->xeh), NULL, NULL, NULL);
+
+ aio_context_release(d->ctx);
+
+ xenevtchn_close(d->xeh);
+
+ xengnttab_unmap(d->xgth, d->sring, d->nr_ring_ref);
+
+ xengnttab_close(d->xgth);
}
static void xen_qdisk_unrealize(XenBackend *dev, Error **errp)
{
XenQdiskBackend *d = XEN_QDISK_BACKEND(dev);
- blockdev_mark_auto_del(d->blk);
+ qemu_bh_delete(d->bh);
}
static void xen_vdev_get_type(Object *obj, Visitor *v, const char *name,
DeviceClass *dc = DEVICE_CLASS(klass);
XenBackendClass *k = XEN_BACKEND_CLASS(klass);
- k->device = "bar";
+ k->device = "vbd";
k->get_name = xen_qdisk_get_name;
k->realize = xen_qdisk_realize;
k->initialize = xen_qdisk_initialize;
k->disconnect = xen_qdisk_disconnect;
- k->event = xen_qdisk_event;
k->unrealize = xen_qdisk_unrealize;
dc->desc = "Xen Qdisk Backend";
dc->props = xen_qdisk_props;