static void ioreq_unmap(struct ioreq *ioreq) { int gnt = ioreq->blkdev->xendev.gnttabdev; int i; if (ioreq->v.niov == 0) return; if (batch_maps) { if (!ioreq->pages) return; if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", strerror(errno)); ioreq->blkdev->cnt_map -= ioreq->v.niov; ioreq->pages = NULL; } else { for (i = 0; i < ioreq->v.niov; i++) { if (!ioreq->page[i]) continue; if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", strerror(errno)); ioreq->blkdev->cnt_map--; ioreq->page[i] = NULL; } } }
static void net_disconnect(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); xen_be_unbind_evtchn(&netdev->xendev); if (netdev->txs) { xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1); netdev->txs = NULL; } if (netdev->rxs) { xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1); netdev->rxs = NULL; } }
void libxenvchan_close(struct libxenvchan *ctrl) { if (!ctrl) return; if (ctrl->read.order >= PAGE_SHIFT) munmap(ctrl->read.buffer, 1 << ctrl->read.order); if (ctrl->write.order >= PAGE_SHIFT) munmap(ctrl->write.buffer, 1 << ctrl->write.order); if (ctrl->ring) { if (ctrl->is_server) { ctrl->ring->srv_live = 0; xc_gntshr_munmap(ctrl->gntshr, ctrl->ring, PAGE_SIZE); } else { ctrl->ring->cli_live = 0; xc_gnttab_munmap(ctrl->gnttab, ctrl->ring, PAGE_SIZE); } } if (ctrl->event) { if (ctrl->event_port >= 0 && ctrl->ring) xc_evtchn_notify(ctrl->event, ctrl->event_port); xc_evtchn_close(ctrl->event); } if (ctrl->is_server) { if (ctrl->gntshr) xc_gntshr_close(ctrl->gntshr); } else { if (ctrl->gnttab) xc_gnttab_close(ctrl->gnttab); } free(ctrl); }
static int net_connect(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); int rx_copy; if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref", &netdev->tx_ring_ref) == -1) { return -1; } if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref", &netdev->rx_ring_ref) == -1) { return 1; } if (xenstore_read_fe_int(&netdev->xendev, "event-channel", &netdev->xendev.remote_port) == -1) { return -1; } if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) { rx_copy = 0; } if (rx_copy == 0) { xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n"); return -1; } netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, netdev->xendev.dom, netdev->tx_ring_ref, PROT_READ | PROT_WRITE); if (!netdev->txs) { return -1; } netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, netdev->xendev.dom, netdev->rx_ring_ref, PROT_READ | PROT_WRITE); if (!netdev->rxs) { xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1); netdev->txs = NULL; return -1; } BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE); BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE); xen_be_bind_evtchn(&netdev->xendev); xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, " "remote port %d, local port %d\n", netdev->tx_ring_ref, netdev->rx_ring_ref, netdev->xendev.remote_port, netdev->xendev.local_port); net_tx_packets(netdev); return 0; }
CAMLprim value stub_gnttab_unmap(value xgh, value array) { CAMLparam2(xgh, array); int size = Caml_ba_array_val(array)->dim[0]; int pages = size >> XC_PAGE_SHIFT; int result = xc_gnttab_munmap(_G(xgh), Caml_ba_data_val(array), pages); if(result!=0) { caml_failwith("Failed to unmap grant"); } CAMLreturn(Val_unit); }
int tapdisk_xenblkif_destroy(struct td_xenblkif * blkif) { int err; ASSERT(blkif); if (tapdisk_xenblkif_chkrng_event_id(blkif) >= 0) { tapdisk_server_unregister_event( tapdisk_xenblkif_chkrng_event_id(blkif)); blkif->chkrng_event = -1; } tapdisk_xenblkif_reqs_free(blkif); if (blkif->ctx) { if (blkif->port >= 0) xc_evtchn_unbind(blkif->ctx->xce_handle, blkif->port); if (blkif->rings.common.sring) { err = xc_gnttab_munmap(blkif->ctx->xcg_handle, blkif->rings.common.sring, blkif->ring_n_pages); if (unlikely(err)) { err = errno; EPRINTF("failed to unmap ring page %p (%d pages): %s " "(error ignored)\n", blkif->rings.common.sring, blkif->ring_n_pages, strerror(err)); err = 0; } } list_del(&blkif->entry_ctx); list_del(&blkif->entry); tapdisk_xenio_ctx_put(blkif->ctx); } err = td_metrics_vbd_stop(&blkif->vbd_stats); if (unlikely(err)) EPRINTF("failed to destroy blkfront stats file: %s\n", strerror(-err)); err = tapdisk_xenblkif_stats_destroy(blkif); if (unlikely(err)) { EPRINTF("failed to clean up ring stats file: %s (error ignored)\n", strerror(-err)); err = 0; } free(blkif); return err; }
static void con_disconnect(struct XenDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); if (con->chr) qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL); xen_be_unbind_evtchn(&con->xendev); if (con->sring) { if (!xendev->gnttabdev) munmap(con->sring, XC_PAGE_SIZE); else xc_gnttab_munmap(xendev->gnttabdev, con->sring, 1); con->sring = NULL; } }
static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t size) { struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque; netif_rx_request_t rxreq; RING_IDX rc, rp; void *page; if (netdev->xendev.be_state != XenbusStateConnected) { return -1; } rc = netdev->rx_ring.req_cons; rp = netdev->rx_ring.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n"); return -1; } if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)", (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN); return -1; } memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq)); netdev->rx_ring.req_cons = ++rc; page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, netdev->xendev.dom, rxreq.gref, PROT_WRITE); if (page == NULL) { xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n", rxreq.gref); net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0); return -1; } memcpy(page + NET_IP_ALIGN, buf, size); xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0); return size; }
static void blk_disconnect(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); if (blkdev->bs) { if (!blkdev->dinfo) { /* close/delete only if we created it ourself */ bdrv_close(blkdev->bs); bdrv_delete(blkdev->bs); } blkdev->bs = NULL; } xen_be_unbind_evtchn(&blkdev->xendev); if (blkdev->sring) { xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1); blkdev->cnt_map--; blkdev->sring = NULL; } }
void closeConnection(libIVC_t *iface, ivc_connection_t *con) { void *ptr = con->inbuf ? con->inbuf : con->outbuf; uint32_t size; switch(con->type) { case ivcInputChannel: size = con->insize + sizeof(struct bufstate); break; case ivcOutputChannel: size = con->outsize + sizeof(struct bufstate); break; case ivcInputOutputChannel: size = con->insize + con->outsize + (2 * sizeof(struct bufstate)); break; default: assert(0); } xc_gnttab_munmap(iface->gt, ptr, (size + 4095) / 4096); free(con); }
static void net_tx_packets(struct XenNetDev *netdev) { netif_tx_request_t txreq; RING_IDX rc, rp; void *page; void *tmpbuf = NULL; for (;;) { rc = netdev->tx_ring.req_cons; rp = netdev->tx_ring.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ while ((rc != rp)) { if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) { break; } memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq)); netdev->tx_ring.req_cons = ++rc; #if 1 /* should not happen in theory, we don't announce the * * feature-{sg,gso,whatelse} flags in xenstore (yet?) */ if (txreq.flags & NETTXF_extra_info) { xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n"); net_tx_error(netdev, &txreq, rc); continue; } if (txreq.flags & NETTXF_more_data) { xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n"); net_tx_error(netdev, &txreq, rc); continue; } #endif if (txreq.size < 14) { xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size); net_tx_error(netdev, &txreq, rc); continue; } if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) { xen_be_printf(&netdev->xendev, 0, "error: page crossing\n"); net_tx_error(netdev, &txreq, rc); continue; } xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n", txreq.gref, txreq.offset, txreq.size, txreq.flags, (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "", (txreq.flags & NETTXF_data_validated) ? " data_validated" : "", (txreq.flags & NETTXF_more_data) ? " more_data" : "", (txreq.flags & NETTXF_extra_info) ? " extra_info" : ""); page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, netdev->xendev.dom, txreq.gref, PROT_READ); if (page == NULL) { xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n", txreq.gref); net_tx_error(netdev, &txreq, rc); continue; } if (txreq.flags & NETTXF_csum_blank) { /* have read-only mapping -> can't fill checksum in-place */ if (!tmpbuf) { tmpbuf = g_malloc(XC_PAGE_SIZE); } memcpy(tmpbuf, page + txreq.offset, txreq.size); net_checksum_calculate(tmpbuf, txreq.size); qemu_send_packet(&netdev->nic->nc, tmpbuf, txreq.size); } else { qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size); } xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); } if (!netdev->tx_work) { break; } netdev->tx_work = 0; } g_free(tmpbuf); }
static int init_gnt_cli(struct libxenvchan *ctrl, int domain, uint32_t ring_ref) { int rv = -1; uint32_t *grants; ctrl->ring = xc_gnttab_map_grant_ref_notify(ctrl->gnttab, domain, ring_ref, PROT_READ|PROT_WRITE, offsetof(struct vchan_interface, cli_live), ctrl->event_port); if (!ctrl->ring) goto out; ctrl->write.order = ctrl->ring->left_order; ctrl->read.order = ctrl->ring->right_order; ctrl->write.shr = &ctrl->ring->left; ctrl->read.shr = &ctrl->ring->right; if (ctrl->write.order < SMALL_RING_SHIFT || ctrl->write.order > MAX_RING_SHIFT) goto out_unmap_ring; if (ctrl->read.order < SMALL_RING_SHIFT || ctrl->read.order > MAX_RING_SHIFT) goto out_unmap_ring; if (ctrl->read.order == ctrl->write.order && ctrl->read.order < PAGE_SHIFT) goto out_unmap_ring; grants = ctrl->ring->grants; switch (ctrl->write.order) { case SMALL_RING_SHIFT: ctrl->write.buffer = ((void*)ctrl->ring) + SMALL_RING_OFFSET; break; case LARGE_RING_SHIFT: ctrl->write.buffer = ((void*)ctrl->ring) + LARGE_RING_OFFSET; break; default: { int pages_left = 1 << (ctrl->write.order - PAGE_SHIFT); ctrl->write.buffer = xc_gnttab_map_domain_grant_refs(ctrl->gnttab, pages_left, domain, grants, PROT_READ|PROT_WRITE); if (!ctrl->write.buffer) goto out_unmap_ring; grants += pages_left; } } switch (ctrl->read.order) { case SMALL_RING_SHIFT: ctrl->read.buffer = ((void*)ctrl->ring) + SMALL_RING_OFFSET; break; case LARGE_RING_SHIFT: ctrl->read.buffer = ((void*)ctrl->ring) + LARGE_RING_OFFSET; break; default: { int pages_right = 1 << (ctrl->read.order - PAGE_SHIFT); ctrl->read.buffer = xc_gnttab_map_domain_grant_refs(ctrl->gnttab, pages_right, domain, grants, PROT_READ); if (!ctrl->read.buffer) goto out_unmap_left; } } rv = 0; out: return rv; out_unmap_left: if (ctrl->write.order >= PAGE_SHIFT) xc_gnttab_munmap(ctrl->gnttab, ctrl->write.buffer, 1 << (ctrl->write.order - PAGE_SHIFT)); out_unmap_ring: xc_gnttab_munmap(ctrl->gnttab, ctrl->ring, 1); ctrl->ring = 0; ctrl->write.order = ctrl->read.order = 0; rv = -1; goto out; }
/* Open an interface to gntshr or gnttab each time it is needed. */ int test_open_multiple() { xc_gntshr *gntshr_if; xc_gnttab *gnttab_if; uint32_t refs[PAGE_COUNT]; uint32_t domids[PAGE_COUNT]; void* local_share; void* remote_share; int i; int err; gntshr_if = xc_gntshr_open(NULL, 0); if(!gntshr_if) { printf("Failed to open gntshr interface.\n"); return 1; } gnttab_if = xc_gnttab_open(NULL, 0); if(!gnttab_if) { printf("Failed to open gnttab interface.\n"); return 1; } local_share = xc_gntshr_share_pages(gntshr_if, DOMID, PAGE_COUNT, refs, 0); if(!local_share) { printf("Failed to share memory.\n"); return 1; } for(i = 0; i < PAGE_COUNT; i++) { printf("Sharing page with ref %d.\n", refs[i]); } for(i = 0; i < PAGE_COUNT; i++) { domids[i] = DOMID; } remote_share = xc_gnttab_map_grant_refs( gnttab_if, PAGE_COUNT, domids, refs, PROT_READ); if(!remote_share) { printf("Failed to map memory.\n"); return 1; } if(xc_gntshr_close(gntshr_if)) { printf("Failed to close gntshr interface.\n"); return 1; } if(xc_gnttab_close(gnttab_if)) { printf("Failed to close gnttab interface.\n"); return 1; } gntshr_if = xc_gntshr_open(NULL, 0); if(!gntshr_if) { printf("Failed to open gntshr interface.\n"); return 1; } gnttab_if = xc_gnttab_open(NULL, 0); if(!gnttab_if) { printf("Failed to open gnttab interface.\n"); return 1; } err = xc_gnttab_munmap(gnttab_if, remote_share, 1); if(err) { printf("Failed to unmap memory - got error code %d.\n", err); return 1; } err = xc_gntshr_munmap(gntshr_if, local_share, 1); if(err) { printf("Failed to unshare memory - got error code %d.\n", err); return 1; } if(xc_gntshr_close(gntshr_if)) { printf("Failed to close gntshr interface.\n"); return 1; } if(xc_gnttab_close(gnttab_if)) { printf("Failed to close gnttab interface.\n"); return 1; } return 0; }
static void *handle_mount(void *data) { int more, notify; struct fs_mount *mount = (struct fs_mount *)data; printf("Starting a thread for mount: %d\n", mount->mount_id); allocate_request_array(mount); for(;;) { int nr_consumed=0; RING_IDX cons, rp; struct fsif_request *req; handle_aio_events(mount); moretodo: rp = mount->ring.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ while ((cons = mount->ring.req_cons) != rp) { int i; struct fs_op *op; printf("Got a request at %d (of %d)\n", cons, RING_SIZE(&mount->ring)); req = RING_GET_REQUEST(&mount->ring, cons); printf("Request type=%d\n", req->type); for(i=0;;i++) { op = fsops[i]; if(op == NULL) { /* We've reached the end of the array, no appropirate * handler found. Warn, ignore and continue. */ printf("WARN: Unknown request type: %d\n", req->type); mount->ring.req_cons++; break; } if(op->type == req->type) { /* There needs to be a dispatch handler */ assert(op->dispatch_handler != NULL); op->dispatch_handler(mount, req); break; } } nr_consumed++; } printf("Backend consumed: %d requests\n", nr_consumed); RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more); if(more) goto moretodo; RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify); printf("Pushed responces and notify=%d\n", notify); if(notify) xc_evtchn_notify(mount->evth, mount->local_evtchn); } printf("Destroying thread for mount: %d\n", mount->mount_id); xc_gnttab_munmap(mount->gnth, mount->ring.sring, 1); xc_gnttab_close(mount->gnth); xc_evtchn_unbind(mount->evth, mount->local_evtchn); xc_evtchn_close(mount->evth); free(mount->frontend); pthread_exit(NULL); }