[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] tools: split libxenvchan into new tools/libs/vchan directory
commit 8ab2429f1221ebae9fc8e72d8af205f3db93cde2 Author: Juergen Gross <jgross@xxxxxxxx> AuthorDate: Fri Aug 28 17:07:37 2020 +0200 Commit: Wei Liu <wl@xxxxxxx> CommitDate: Wed Sep 9 10:57:25 2020 +0000 tools: split libxenvchan into new tools/libs/vchan directory There is no reason why libvchan is not placed in the tools/libs directory. At the same time move libxenvchan.h to a dedicated include directory in tools/libs/vchan in order to follow the same pattern as the other libraries in tools/libs. As tools/libvchan now contains no library any longer rename it to tools/vchan. Signed-off-by: Juergen Gross <jgross@xxxxxxxx> Acked-by: Wei Liu <wl@xxxxxxx> --- .gitignore | 8 +- tools/Makefile | 2 +- tools/Rules.mk | 6 - tools/libs/Makefile | 1 + tools/libs/uselibs.mk | 2 + tools/libs/vchan/Makefile | 20 ++ tools/libs/vchan/include/libxenvchan.h | 176 +++++++++++ tools/libs/vchan/init.c | 461 ++++++++++++++++++++++++++++ tools/libs/vchan/io.c | 388 ++++++++++++++++++++++++ tools/libvchan/Makefile | 100 ------- tools/libvchan/init.c | 461 ---------------------------- tools/libvchan/io.c | 388 ------------------------ tools/libvchan/libxenvchan.h | 176 ----------- tools/libvchan/node-select.c | 186 ------------ tools/libvchan/node.c | 168 ----------- tools/libvchan/vchan-socket-proxy.c | 533 --------------------------------- tools/vchan/Makefile | 37 +++ tools/vchan/node-select.c | 186 ++++++++++++ tools/vchan/node.c | 168 +++++++++++ tools/vchan/vchan-socket-proxy.c | 533 +++++++++++++++++++++++++++++++++ 20 files changed, 1978 insertions(+), 2022 deletions(-) diff --git a/.gitignore b/.gitignore index 1335034fd3..364b09506b 100644 --- a/.gitignore +++ b/.gitignore @@ -134,6 +134,9 @@ tools/libs/store/utils.h tools/libs/store/xenstore.pc tools/libs/store/xs_lib.c tools/libs/store/include/xenstore_lib.h +tools/libs/vchan/headers.chk +tools/libs/vchan/libxenvchan.map +tools/libs/vchan/xenvchan.pc tools/console/xenconsole tools/console/xenconsoled tools/console/client/_paths.h @@ -209,7 +212,6 @@ tools/include/xen/* tools/include/xen-xsm/* tools/include/xen-foreign/*.(c|h|size) tools/include/xen-foreign/checker -tools/libvchan/xenvchan.pc tools/libxl/_libxl.api-for-check tools/libxl/*.api-ok tools/libxl/*.pc @@ -389,8 +391,8 @@ tools/misc/xenhypfs tools/misc/xenwatchdogd tools/misc/xen-hvmcrash tools/misc/xen-lowmemd -tools/libvchan/vchan-node[12] -tools/libvchan/vchan-socket-proxy +tools/vchan/vchan-node[12] +tools/vchan/vchan-socket-proxy tools/ocaml/*/.ocamldep.make tools/ocaml/*/*.cm[ixao] tools/ocaml/*/*.cmxa diff --git a/tools/Makefile b/tools/Makefile index 4a3646871c..0db01707a4 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -20,7 +20,7 @@ SUBDIRS-y += xenmon SUBDIRS-y += xenstat SUBDIRS-$(CONFIG_NetBSD) += xenbackendd SUBDIRS-y += libfsimage -SUBDIRS-$(CONFIG_Linux) += libvchan +SUBDIRS-$(CONFIG_Linux) += vchan # do not recurse in to a dir we are about to delete ifneq "$(MAKECMDGOALS)" "distclean" diff --git a/tools/Rules.mk b/tools/Rules.mk index 21aa8ea844..5f17492a68 100644 --- a/tools/Rules.mk +++ b/tools/Rules.mk @@ -19,7 +19,6 @@ XEN_libxenlight = $(XEN_ROOT)/tools/libxl # Currently libxlutil lives in the same directory as libxenlight XEN_libxlutil = $(XEN_libxenlight) XEN_libxenstat = $(XEN_ROOT)/tools/xenstat/libxenstat/src -XEN_libxenvchan = $(XEN_ROOT)/tools/libvchan CFLAGS_xeninclude = -I$(XEN_INCLUDE) @@ -114,11 +113,6 @@ SHDEPS_libxenstat = $(SHLIB_libxenctrl) $(SHLIB_libxenstore) LDLIBS_libxenstat = $(SHDEPS_libxenstat) $(XEN_libxenstat)/libxenstat$(libextension) SHLIB_libxenstat = $(SHDEPS_libxenstat) -Wl,-rpath-link=$(XEN_libxenstat) -CFLAGS_libxenvchan = -I$(XEN_libxenvchan) $(CFLAGS_libxengnttab) $(CFLAGS_libxenevtchn) -SHDEPS_libxenvchan = $(SHLIB_libxentoollog) $(SHLIB_libxenstore) $(SHLIB_libxenevtchn) $(SHLIB_libxengnttab) -LDLIBS_libxenvchan = $(SHDEPS_libxenvchan) $(XEN_libxenvchan)/libxenvchan$(libextension) -SHLIB_libxenvchan = $(SHDEPS_libxenvchan) -Wl,-rpath-link=$(XEN_libxenvchan) - ifeq ($(debug),y) # Disable optimizations CFLAGS += -O0 -fno-omit-frame-pointer diff --git a/tools/libs/Makefile b/tools/libs/Makefile index 62bd8f5292..756d059ee7 100644 --- a/tools/libs/Makefile +++ b/tools/libs/Makefile @@ -13,6 +13,7 @@ SUBDIRS-y += ctrl SUBDIRS-y += guest SUBDIRS-y += hypfs SUBDIRS-y += store +SUBDIRS-$(CONFIG_Linux) += vchan ifeq ($(CONFIG_RUMP),y) SUBDIRS-y := toolcore diff --git a/tools/libs/uselibs.mk b/tools/libs/uselibs.mk index a0fe0402ff..edb4b34256 100644 --- a/tools/libs/uselibs.mk +++ b/tools/libs/uselibs.mk @@ -22,3 +22,5 @@ LIBS_LIBS += guest USELIBS_guest := evtchn ctrl LIBS_LIBS += store USELIBS_store := toolcore +LIBS_LIBS += vchan +USELIBS_vchan := toollog store gnttab evtchn diff --git a/tools/libs/vchan/Makefile b/tools/libs/vchan/Makefile new file mode 100644 index 0000000000..87ff608f45 --- /dev/null +++ b/tools/libs/vchan/Makefile @@ -0,0 +1,20 @@ +XEN_ROOT = $(CURDIR)/../../.. +include $(XEN_ROOT)/tools/Rules.mk + +CFLAGS += $(CFLAGS_libxenctrl) + +LIBHEADER := libxenvchan.h + +SRCS-y += init.c +SRCS-y += io.c + +include $(XEN_ROOT)/tools/libs/libs.mk + +$(PKG_CONFIG_LOCAL): PKG_CONFIG_INCDIR = $(XEN_libxenvchan)/include +$(PKG_CONFIG_LOCAL): PKG_CONFIG_CFLAGS_LOCAL = $(CFLAGS_xeninclude) + +clean: cleanlocal + +.PHONY: cleanlocal +cleanlocal: + rm -f libxenvchan.map diff --git a/tools/libs/vchan/include/libxenvchan.h b/tools/libs/vchan/include/libxenvchan.h new file mode 100644 index 0000000000..d6010b145d --- /dev/null +++ b/tools/libs/vchan/include/libxenvchan.h @@ -0,0 +1,176 @@ +/** + * @file + * @section AUTHORS + * + * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> + * + * Authors: + * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> + * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> + * + * @section LICENSE + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see <http://www.gnu.org/licenses/>. + * + * @section DESCRIPTION + * + * Originally borrowed from the Qubes OS Project, http://www.qubes-os.org, + * this code has been substantially rewritten to use the gntdev and gntalloc + * devices instead of raw MFNs and map_foreign_range. + * + * This is a library for inter-domain communication. A standard Xen ring + * buffer is used, with a datagram-based interface built on top. The grant + * reference and event channels are shared in XenStore under the path + * /local/domain/<srv-id>/data/vchan/<cli-id>/<port>/{ring-ref,event-channel} + * + * The ring.h macros define an asymmetric interface to a shared data structure + * that assumes all rings reside in a single contiguous memory space. This is + * not suitable for vchan because the interface to the ring is symmetric except + * for the setup. Unlike the producer-consumer rings defined in ring.h, the + * size of the rings used in vchan are determined at execution time instead of + * compile time, so the macros in ring.h cannot be used to access the rings. + */ + +#include <xen/io/libxenvchan.h> +#include <xen/xen.h> +#include <xen/sys/evtchn.h> +#include <xenevtchn.h> +#include <xengnttab.h> + +/* Callers who don't care don't need to #include <xentoollog.h> */ +struct xentoollog_logger; + +struct libxenvchan_ring { + /* Pointer into the shared page. Offsets into buffer. */ + struct ring_shared* shr; + /* ring data; may be its own shared page(s) depending on order */ + void* buffer; + /** + * The size of the ring is (1 << order); offsets wrap around when they + * exceed this. This copy is required because we can't trust the order + * in the shared page to remain constant. + */ + int order; +}; + +/** + * struct libxenvchan: control structure passed to all library calls + */ +struct libxenvchan { + /* Mapping handle for shared ring page */ + union { + xengntshr_handle *gntshr; /* for server */ + xengnttab_handle *gnttab; /* for client */ + }; + /* Pointer to shared ring page */ + struct vchan_interface *ring; + /* event channel interface */ + xenevtchn_handle *event; + uint32_t event_port; + /* informative flags: are we acting as server? */ + int is_server:1; + /* true if server remains active when client closes (allows reconnection) */ + int server_persist:1; + /* true if operations should block instead of returning 0 */ + int blocking:1; + /* communication rings */ + struct libxenvchan_ring read, write; +}; + +/** + * Set up a vchan, including granting pages + * @param logger Logger for libxc errors + * @param domain The peer domain that will be connecting + * @param xs_path Base xenstore path for storing ring/event data + * @param send_min The minimum size (in bytes) of the send ring (left) + * @param recv_min The minimum size (in bytes) of the receive ring (right) + * @return The structure, or NULL in case of an error + */ +struct libxenvchan *libxenvchan_server_init(struct xentoollog_logger *logger, + int domain, const char* xs_path, + size_t read_min, size_t write_min); +/** + * Connect to an existing vchan. Note: you can reconnect to an existing vchan + * safely, however no locking is performed, so you must prevent multiple clients + * from connecting to a single server. + * + * @param logger Logger for libxc errors + * @param domain The peer domain to connect to + * @param xs_path Base xenstore path for storing ring/event data + * @return The structure, or NULL in case of an error + */ +struct libxenvchan *libxenvchan_client_init(struct xentoollog_logger *logger, + int domain, const char* xs_path); +/** + * Close a vchan. This deallocates the vchan and attempts to free its + * resources. The other side is notified of the close, but can still read any + * data pending prior to the close. + */ +void libxenvchan_close(struct libxenvchan *ctrl); + +/** + * Packet-based receive: always reads exactly $size bytes. + * @param ctrl The vchan control structure + * @param data Buffer for data that was read + * @param size Size of the buffer and amount of data to read + * @return -1 on error, 0 if nonblocking and insufficient data is available, or $size + */ +int libxenvchan_recv(struct libxenvchan *ctrl, void *data, size_t size); +/** + * Stream-based receive: reads as much data as possible. + * @param ctrl The vchan control structure + * @param data Buffer for data that was read + * @param size Size of the buffer + * @return -1 on error, otherwise the amount of data read (which may be zero if + * the vchan is nonblocking) + */ +int libxenvchan_read(struct libxenvchan *ctrl, void *data, size_t size); +/** + * Packet-based send: send entire buffer if possible + * @param ctrl The vchan control structure + * @param data Buffer for data to send + * @param size Size of the buffer and amount of data to send + * @return -1 on error, 0 if nonblocking and insufficient space is available, or $size + */ +int libxenvchan_send(struct libxenvchan *ctrl, const void *data, size_t size); +/** + * Stream-based send: send as much data as possible. + * @param ctrl The vchan control structure + * @param data Buffer for data to send + * @param size Size of the buffer + * @return -1 on error, otherwise the amount of data sent (which may be zero if + * the vchan is nonblocking) + */ +int libxenvchan_write(struct libxenvchan *ctrl, const void *data, size_t size); +/** + * Waits for reads or writes to unblock, or for a close + */ +int libxenvchan_wait(struct libxenvchan *ctrl); +/** + * Returns the event file descriptor for this vchan. When this FD is readable, + * libxenvchan_wait() will not block, and the state of the vchan has changed since + * the last invocation of libxenvchan_wait(). + */ +int libxenvchan_fd_for_select(struct libxenvchan *ctrl); +/** + * Query the state of the vchan shared page: + * return 0 when one side has called libxenvchan_close() or crashed + * return 1 when both sides are open + * return 2 [server only] when no client has yet connected + */ +int libxenvchan_is_open(struct libxenvchan* ctrl); +/** Amount of data ready to read, in bytes */ +int libxenvchan_data_ready(struct libxenvchan *ctrl); +/** Amount of data it is possible to send without blocking */ +int libxenvchan_buffer_space(struct libxenvchan *ctrl); diff --git a/tools/libs/vchan/init.c b/tools/libs/vchan/init.c new file mode 100644 index 0000000000..ad4b64fbe3 --- /dev/null +++ b/tools/libs/vchan/init.c @@ -0,0 +1,461 @@ +/** + * @file + * @section AUTHORS + * + * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> + * + * Authors: + * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> + * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> + * + * @section LICENSE + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see <http://www.gnu.org/licenses/>. + * + * @section DESCRIPTION + * + * This file contains the setup code used to establish the ring buffer. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/user.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include <xenstore.h> +#include <xen/xen.h> +#include <xen/sys/evtchn.h> +#include <xen/sys/gntalloc.h> +#include <xen/sys/gntdev.h> +#include <libxenvchan.h> + +#ifndef PAGE_SHIFT +#define PAGE_SHIFT 12 +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +#define SMALL_RING_SHIFT 10 +#define LARGE_RING_SHIFT 11 + +#define MAX_SMALL_RING (1 << SMALL_RING_SHIFT) +#define SMALL_RING_OFFSET 1024 +#define MAX_LARGE_RING (1 << LARGE_RING_SHIFT) +#define LARGE_RING_OFFSET 2048 + +// if you go over this size, you'll have too many grants to fit in the shared page. +#define MAX_RING_SHIFT 20 +#define MAX_RING_SIZE (1 << MAX_RING_SHIFT) + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define max(a,b) ((a > b) ? a : b) + +static int init_gnt_srv(struct libxenvchan *ctrl, int domain) +{ + int pages_left = ctrl->read.order >= PAGE_SHIFT ? 1 << (ctrl->read.order - PAGE_SHIFT) : 0; + int pages_right = ctrl->write.order >= PAGE_SHIFT ? 1 << (ctrl->write.order - PAGE_SHIFT) : 0; + uint32_t ring_ref = -1; + void *ring; + + ring = xengntshr_share_page_notify(ctrl->gntshr, domain, + &ring_ref, 1, offsetof(struct vchan_interface, srv_live), + ctrl->event_port); + + if (!ring) + goto out; + + memset(ring, 0, PAGE_SIZE); + + ctrl->ring = ring; + ctrl->read.shr = &ctrl->ring->left; + ctrl->write.shr = &ctrl->ring->right; + ctrl->ring->left_order = ctrl->read.order; + ctrl->ring->right_order = ctrl->write.order; + ctrl->ring->cli_live = 2; + ctrl->ring->srv_live = 1; + ctrl->ring->cli_notify = VCHAN_NOTIFY_WRITE; + + 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: + ctrl->read.buffer = xengntshr_share_pages(ctrl->gntshr, domain, + pages_left, ctrl->ring->grants, 1); + if (!ctrl->read.buffer) + goto out_ring; + } + + 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: + ctrl->write.buffer = xengntshr_share_pages(ctrl->gntshr, domain, + pages_right, ctrl->ring->grants + pages_left, 1); + if (!ctrl->write.buffer) + goto out_unmap_left; + } + +out: + return ring_ref; +out_unmap_left: + if (pages_left) + xengntshr_unshare(ctrl->gntshr, ctrl->read.buffer, pages_left); +out_ring: + xengntshr_unshare(ctrl->gntshr, ring, 1); + ring_ref = -1; + ctrl->ring = NULL; + ctrl->write.order = ctrl->read.order = 0; + goto out; +} + +static int init_gnt_cli(struct libxenvchan *ctrl, int domain, uint32_t ring_ref) +{ + int rv = -1; + uint32_t *grants; + + ctrl->ring = xengnttab_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 = xengnttab_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 = xengnttab_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) + xengnttab_unmap(ctrl->gnttab, ctrl->write.buffer, + 1 << (ctrl->write.order - PAGE_SHIFT)); + out_unmap_ring: + xengnttab_unmap(ctrl->gnttab, ctrl->ring, 1); + ctrl->ring = 0; + ctrl->write.order = ctrl->read.order = 0; + rv = -1; + goto out; +} + +static int init_evt_srv(struct libxenvchan *ctrl, int domain, + struct xentoollog_logger *logger) +{ + xenevtchn_port_or_error_t port; + + ctrl->event = xenevtchn_open(logger, 0); + if (!ctrl->event) + return -1; + + port = xenevtchn_bind_unbound_port(ctrl->event, domain); + if (port < 0) + goto fail; + ctrl->event_port = port; + + if (xenevtchn_unmask(ctrl->event, ctrl->event_port)) + goto fail; + + return 0; + +fail: + if (port >= 0) + xenevtchn_unbind(ctrl->event, port); + + xenevtchn_close(ctrl->event); + ctrl->event = NULL; + + return -1; +} + +static int init_xs_srv(struct libxenvchan *ctrl, int domain, const char* xs_base, int ring_ref) +{ + int ret = -1; + struct xs_handle *xs; + struct xs_permissions perms[2]; + char buf[64]; + char ref[16]; + char* domid_str = NULL; + xs_transaction_t xs_trans = XBT_NULL; + xs = xs_domain_open(); + if (!xs) + goto fail; + domid_str = xs_read(xs, 0, "domid", NULL); + if (!domid_str) + goto fail_xs_open; + + // owner domain is us + perms[0].id = atoi(domid_str); + // permissions for domains not listed = none + perms[0].perms = XS_PERM_NONE; + // other domains + perms[1].id = domain; + perms[1].perms = XS_PERM_READ; + +retry_transaction: + xs_trans = xs_transaction_start(xs); + if (!xs_trans) + goto fail_xs_open; + + snprintf(ref, sizeof ref, "%d", ring_ref); + snprintf(buf, sizeof buf, "%s/ring-ref", xs_base); + if (!xs_write(xs, xs_trans, buf, ref, strlen(ref))) + goto fail_xs_open; + if (!xs_set_permissions(xs, xs_trans, buf, perms, 2)) + goto fail_xs_open; + + snprintf(ref, sizeof ref, "%d", ctrl->event_port); + snprintf(buf, sizeof buf, "%s/event-channel", xs_base); + if (!xs_write(xs, xs_trans, buf, ref, strlen(ref))) + goto fail_xs_open; + if (!xs_set_permissions(xs, xs_trans, buf, perms, 2)) + goto fail_xs_open; + + if (!xs_transaction_end(xs, xs_trans, 0)) { + if (errno == EAGAIN) + goto retry_transaction; + } else { + ret = 0; + } + fail_xs_open: + free(domid_str); + xs_daemon_close(xs); + fail: + return ret; +} + +static int min_order(size_t siz) +{ + int rv = PAGE_SHIFT; + while (siz > (1 << rv)) + rv++; + return rv; +} + +struct libxenvchan *libxenvchan_server_init(struct xentoollog_logger *logger, + int domain, const char* xs_path, + size_t left_min, size_t right_min) +{ + struct libxenvchan *ctrl; + int ring_ref; + if (left_min > MAX_RING_SIZE || right_min > MAX_RING_SIZE) + return 0; + + ctrl = malloc(sizeof(*ctrl)); + if (!ctrl) + return 0; + + ctrl->ring = NULL; + ctrl->event = NULL; + ctrl->is_server = 1; + ctrl->server_persist = 0; + + ctrl->read.order = min_order(left_min); + ctrl->write.order = min_order(right_min); + + // if we can avoid allocating extra pages by using in-page rings, do so + if (left_min <= MAX_SMALL_RING && right_min <= MAX_LARGE_RING) { + ctrl->read.order = SMALL_RING_SHIFT; + ctrl->write.order = LARGE_RING_SHIFT; + } else if (left_min <= MAX_LARGE_RING && right_min <= MAX_SMALL_RING) { + ctrl->read.order = LARGE_RING_SHIFT; + ctrl->write.order = SMALL_RING_SHIFT; + } else if (left_min <= MAX_LARGE_RING) { + ctrl->read.order = LARGE_RING_SHIFT; + } else if (right_min <= MAX_LARGE_RING) { + ctrl->write.order = LARGE_RING_SHIFT; + } + + ctrl->gntshr = xengntshr_open(logger, 0); + if (!ctrl->gntshr) { + free(ctrl); + return 0; + } + + if (init_evt_srv(ctrl, domain, logger)) + goto out; + ring_ref = init_gnt_srv(ctrl, domain); + if (ring_ref < 0) + goto out; + if (init_xs_srv(ctrl, domain, xs_path, ring_ref)) + goto out; + return ctrl; +out: + libxenvchan_close(ctrl); + return 0; +} + +static int init_evt_cli(struct libxenvchan *ctrl, int domain, + struct xentoollog_logger *logger) +{ + xenevtchn_port_or_error_t port; + + ctrl->event = xenevtchn_open(logger, 0); + if (!ctrl->event) + return -1; + + port = xenevtchn_bind_interdomain(ctrl->event, + domain, ctrl->event_port); + if (port < 0) + goto fail; + ctrl->event_port = port; + + if (xenevtchn_unmask(ctrl->event, ctrl->event_port)) + goto fail; + + return 0; + +fail: + if (port >= 0) + xenevtchn_unbind(ctrl->event, port); + + xenevtchn_close(ctrl->event); + ctrl->event = NULL; + + return -1; +} + + +struct libxenvchan *libxenvchan_client_init(struct xentoollog_logger *logger, + int domain, const char* xs_path) +{ + struct libxenvchan *ctrl = malloc(sizeof(struct libxenvchan)); + struct xs_handle *xs = NULL; + char buf[64]; + char *ref; + int ring_ref; + unsigned int len; + + if (!ctrl) + return 0; + ctrl->ring = NULL; + ctrl->event = NULL; + ctrl->gnttab = NULL; + ctrl->write.order = ctrl->read.order = 0; + ctrl->is_server = 0; + + xs = xs_daemon_open(); + if (!xs) + xs = xs_domain_open(); + if (!xs) + goto fail; + +// find xenstore entry + snprintf(buf, sizeof buf, "%s/ring-ref", xs_path); + ref = xs_read(xs, 0, buf, &len); + if (!ref) + goto fail; + ring_ref = atoi(ref); + free(ref); + if (!ring_ref) + goto fail; + snprintf(buf, sizeof buf, "%s/event-channel", xs_path); + ref = xs_read(xs, 0, buf, &len); + if (!ref) + goto fail; + ctrl->event_port = atoi(ref); + free(ref); + if (!ctrl->event_port) + goto fail; + + ctrl->gnttab = xengnttab_open(logger, 0); + if (!ctrl->gnttab) + goto fail; + +// set up event channel + if (init_evt_cli(ctrl, domain, logger)) + goto fail; + +// set up shared page(s) + if (init_gnt_cli(ctrl, domain, ring_ref)) + goto fail; + + ctrl->ring->cli_live = 1; + ctrl->ring->srv_notify = VCHAN_NOTIFY_WRITE; + + /* wake up the server */ + xenevtchn_notify(ctrl->event, ctrl->event_port); + + out: + if (xs) + xs_daemon_close(xs); + return ctrl; + fail: + libxenvchan_close(ctrl); + ctrl = NULL; + goto out; +} diff --git a/tools/libs/vchan/io.c b/tools/libs/vchan/io.c new file mode 100644 index 0000000000..da303fbc01 --- /dev/null +++ b/tools/libs/vchan/io.c @@ -0,0 +1,388 @@ +/** + * @file + * @section AUTHORS + * + * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> + * + * Authors: + * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> + * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> + * + * @section LICENSE + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see <http://www.gnu.org/licenses/>. + * + * @section DESCRIPTION + * + * This file contains the communications interface built on the ring buffer. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include <xenctrl.h> +#include <libxenvchan.h> + +#ifndef PAGE_SHIFT +#define PAGE_SHIFT 12 +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + + +static inline uint32_t rd_prod(struct libxenvchan *ctrl) +{ + return ctrl->read.shr->prod; +} + +static inline uint32_t* _rd_cons(struct libxenvchan *ctrl) +{ + return &ctrl->read.shr->cons; +} +#define rd_cons(x) (*_rd_cons(x)) + +static inline uint32_t* _wr_prod(struct libxenvchan *ctrl) +{ + return &ctrl->write.shr->prod; +} +#define wr_prod(x) (*_wr_prod(x)) + +static inline uint32_t wr_cons(struct libxenvchan *ctrl) +{ + return ctrl->write.shr->cons; +} + +static inline const void* rd_ring(struct libxenvchan *ctrl) +{ + return ctrl->read.buffer; +} + +static inline void* wr_ring(struct libxenvchan *ctrl) +{ + return ctrl->write.buffer; +} + +static inline uint32_t wr_ring_size(struct libxenvchan *ctrl) +{ + return (1 << ctrl->write.order); +} + +static inline uint32_t rd_ring_size(struct libxenvchan *ctrl) +{ + return (1 << ctrl->read.order); +} + +static inline void request_notify(struct libxenvchan *ctrl, uint8_t bit) +{ + uint8_t *notify = ctrl->is_server ? &ctrl->ring->cli_notify : &ctrl->ring->srv_notify; + __sync_or_and_fetch(notify, bit); + xen_mb(); /* post the request /before/ caller re-reads any indexes */ +} + +static inline int send_notify(struct libxenvchan *ctrl, uint8_t bit) +{ + uint8_t *notify, prev; + xen_mb(); /* caller updates indexes /before/ we decode to notify */ + notify = ctrl->is_server ? &ctrl->ring->srv_notify : &ctrl->ring->cli_notify; + prev = __sync_fetch_and_and(notify, ~bit); + if (prev & bit) + return xenevtchn_notify(ctrl->event, ctrl->event_port); + else + return 0; +} + +/* + * Get the amount of buffer space available, and do nothing about + * notifications. + */ +static inline int raw_get_data_ready(struct libxenvchan *ctrl) +{ + uint32_t ready = rd_prod(ctrl) - rd_cons(ctrl); + xen_mb(); /* Ensure 'ready' is read only once. */ + if (ready > rd_ring_size(ctrl)) + /* We have no way to return errors. Locking up the ring is + * better than the alternatives. */ + return 0; + return ready; +} + +/** + * Get the amount of buffer space available and enable notifications if needed. + */ +static inline int fast_get_data_ready(struct libxenvchan *ctrl, size_t request) +{ + int ready = raw_get_data_ready(ctrl); + if (ready >= request) + return ready; + /* We plan to consume all data; please tell us if you send more */ + request_notify(ctrl, VCHAN_NOTIFY_WRITE); + /* + * If the writer moved rd_prod after our read but before request, we + * will not get notified even though the actual amount of data ready is + * above request. Reread rd_prod to cover this case. + */ + return raw_get_data_ready(ctrl); +} + +int libxenvchan_data_ready(struct libxenvchan *ctrl) +{ + /* Since this value is being used outside libxenvchan, request notification + * when it changes + */ + request_notify(ctrl, VCHAN_NOTIFY_WRITE); + return raw_get_data_ready(ctrl); +} + +/** + * Get the amount of buffer space available, and do nothing + * about notifications + */ +static inline int raw_get_buffer_space(struct libxenvchan *ctrl) +{ + uint32_t ready = wr_ring_size(ctrl) - (wr_prod(ctrl) - wr_cons(ctrl)); + xen_mb(); /* Ensure 'ready' is read only once. */ + if (ready > wr_ring_size(ctrl)) + /* We have no way to return errors. Locking up the ring is + * better than the alternatives. */ + return 0; + return ready; +} + +/** + * Get the amount of buffer space available and enable notifications if needed. + */ +static inline int fast_get_buffer_space(struct libxenvchan *ctrl, size_t request) +{ + int ready = raw_get_buffer_space(ctrl); + if (ready >= request) + return ready; + /* We plan to fill the buffer; please tell us when you've read it */ + request_notify(ctrl, VCHAN_NOTIFY_READ); + /* + * If the reader moved wr_cons after our read but before request, we + * will not get notified even though the actual amount of buffer space + * is above request. Reread wr_cons to cover this case. + */ + return raw_get_buffer_space(ctrl); +} + +int libxenvchan_buffer_space(struct libxenvchan *ctrl) +{ + /* Since this value is being used outside libxenvchan, request notification + * when it changes + */ + request_notify(ctrl, VCHAN_NOTIFY_READ); + return raw_get_buffer_space(ctrl); +} + +int libxenvchan_wait(struct libxenvchan *ctrl) +{ + int ret = xenevtchn_pending(ctrl->event); + if (ret < 0) + return -1; + xenevtchn_unmask(ctrl->event, ret); + return 0; +} + +/** + * returns -1 on error, or size on success + * + * caller must have checked that enough space is available + */ +static int do_send(struct libxenvchan *ctrl, const void *data, size_t size) +{ + int real_idx = wr_prod(ctrl) & (wr_ring_size(ctrl) - 1); + int avail_contig = wr_ring_size(ctrl) - real_idx; + if (avail_contig > size) + avail_contig = size; + xen_mb(); /* read indexes /then/ write data */ + memcpy(wr_ring(ctrl) + real_idx, data, avail_contig); + if (avail_contig < size) + { + // we rolled across the end of the ring + memcpy(wr_ring(ctrl), data + avail_contig, size - avail_contig); + } + xen_wmb(); /* write data /then/ notify */ + wr_prod(ctrl) += size; + if (send_notify(ctrl, VCHAN_NOTIFY_WRITE)) + return -1; + return size; +} + +/** + * returns 0 if no buffer space is available, -1 on error, or size on success + */ +int libxenvchan_send(struct libxenvchan *ctrl, const void *data, size_t size) +{ + int avail; + while (1) { + if (!libxenvchan_is_open(ctrl)) + return -1; + avail = fast_get_buffer_space(ctrl, size); + if (size <= avail) + return do_send(ctrl, data, size); + if (!ctrl->blocking) + return 0; + if (size > wr_ring_size(ctrl)) + return -1; + if (libxenvchan_wait(ctrl)) + return -1; + } +} + +int libxenvchan_write(struct libxenvchan *ctrl, const void *data, size_t size) +{ + int avail; + if (!libxenvchan_is_open(ctrl)) + return -1; + if (ctrl->blocking) { + size_t pos = 0; + while (1) { + avail = fast_get_buffer_space(ctrl, size - pos); + if (pos + avail > size) + avail = size - pos; + if (avail) + pos += do_send(ctrl, data + pos, avail); + if (pos == size) + return pos; + if (libxenvchan_wait(ctrl)) + return -1; + if (!libxenvchan_is_open(ctrl)) + return -1; + } + } else { + avail = fast_get_buffer_space(ctrl, size); + if (size > avail) + size = avail; + if (size == 0) + return 0; + return do_send(ctrl, data, size); + } +} + +/** + * returns -1 on error, or size on success + * + * caller must have checked that enough data is available + */ +static int do_recv(struct libxenvchan *ctrl, void *data, size_t size) +{ + int real_idx = rd_cons(ctrl) & (rd_ring_size(ctrl) - 1); + int avail_contig = rd_ring_size(ctrl) - real_idx; + if (avail_contig > size) + avail_contig = size; + xen_rmb(); /* data read must happen /after/ rd_cons read */ + memcpy(data, rd_ring(ctrl) + real_idx, avail_contig); + if (avail_contig < size) + { + // we rolled across the end of the ring + memcpy(data + avail_contig, rd_ring(ctrl), size - avail_contig); + } + xen_mb(); /* consume /then/ notify */ + rd_cons(ctrl) += size; + if (send_notify(ctrl, VCHAN_NOTIFY_READ)) + return -1; + return size; +} + +/** + * reads exactly size bytes from the vchan. + * returns 0 if insufficient data is available, -1 on error, or size on success + */ +int libxenvchan_recv(struct libxenvchan *ctrl, void *data, size_t size) +{ + while (1) { + int avail = fast_get_data_ready(ctrl, size); + if (size <= avail) + return do_recv(ctrl, data, size); + if (!libxenvchan_is_open(ctrl)) + return -1; + if (!ctrl->blocking) + return 0; + if (size > rd_ring_size(ctrl)) + return -1; + if (libxenvchan_wait(ctrl)) + return -1; + } +} + +int libxenvchan_read(struct libxenvchan *ctrl, void *data, size_t size) +{ + while (1) { + int avail = fast_get_data_ready(ctrl, size); + if (avail && size > avail) + size = avail; + if (avail) + return do_recv(ctrl, data, size); + if (!libxenvchan_is_open(ctrl)) + return -1; + if (!ctrl->blocking) + return 0; + if (libxenvchan_wait(ctrl)) + return -1; + } +} + +int libxenvchan_is_open(struct libxenvchan* ctrl) +{ + if (ctrl->is_server) + return ctrl->server_persist ? 1 : ctrl->ring->cli_live; + else + return ctrl->ring->srv_live; +} + +int libxenvchan_fd_for_select(struct libxenvchan *ctrl) +{ + return xenevtchn_fd(ctrl->event); +} + +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; + xengntshr_unshare(ctrl->gntshr, ctrl->ring, 1); + } else { + ctrl->ring->cli_live = 0; + xengnttab_unmap(ctrl->gnttab, ctrl->ring, 1); + } + } + if (ctrl->event) { + if (ctrl->ring) + xenevtchn_notify(ctrl->event, ctrl->event_port); + xenevtchn_close(ctrl->event); + } + if (ctrl->is_server) { + if (ctrl->gntshr) + xengntshr_close(ctrl->gntshr); + } else { + if (ctrl->gnttab) + xengnttab_close(ctrl->gnttab); + } + free(ctrl); +} diff --git a/tools/libvchan/Makefile b/tools/libvchan/Makefile deleted file mode 100644 index e718447977..0000000000 --- a/tools/libvchan/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -# -# tools/libvchan/Makefile -# - -XEN_ROOT = $(CURDIR)/../.. -include $(XEN_ROOT)/tools/Rules.mk - -LIBVCHAN_OBJS = init.o io.o -NODE_OBJS = node.o -NODE2_OBJS = node-select.o - -LIBVCHAN_PIC_OBJS = $(patsubst %.o,%.opic,$(LIBVCHAN_OBJS)) -LIBVCHAN_LIBS = $(LDLIBS_libxenstore) $(LDLIBS_libxengnttab) $(LDLIBS_libxenevtchn) -$(LIBVCHAN_OBJS) $(LIBVCHAN_PIC_OBJS): CFLAGS += $(CFLAGS_libxenstore) $(CFLAGS_libxengnttab) $(CFLAGS_libxenevtchn) -$(NODE_OBJS) $(NODE2_OBJS): CFLAGS += $(CFLAGS_libxengnttab) $(CFLAGS_libxenevtchn) -vchan-socket-proxy.o: CFLAGS += $(CFLAGS_libxenstore) $(CFLAGS_libxenctrl) $(CFLAGS_libxengnttab) $(CFLAGS_libxenevtchn) - -MAJOR = 4.15 -MINOR = 0 - -CFLAGS += -I../include -I. - -io.o io.opic: CFLAGS += $(CFLAGS_libxenctrl) # for xen_mb et al - -PKG_CONFIG := xenvchan.pc -PKG_CONFIG_NAME := Xenvchan -PKG_CONFIG_DESC := The Xenvchan library for Xen hypervisor -PKG_CONFIG_VERSION := $(MAJOR).$(MINOR) -PKG_CONFIG_USELIBS := $(SHLIB_libxenvchan) -PKG_CONFIG_LIB := xenvchan -PKG_CONFIG_REQPRIV := xentoollog,xenstore,xenevtchn,xengnttab - -ifneq ($(CONFIG_LIBXC_MINIOS),y) -PKG_CONFIG_INST := $(PKG_CONFIG) -$(PKG_CONFIG_INST): PKG_CONFIG_PREFIX = $(prefix) -$(PKG_CONFIG_INST): PKG_CONFIG_INCDIR = $(includedir) -$(PKG_CONFIG_INST): PKG_CONFIG_LIBDIR = $(libdir) -endif - -PKG_CONFIG_LOCAL := $(foreach pc,$(PKG_CONFIG),$(PKG_CONFIG_DIR)/$(pc)) - -$(PKG_CONFIG_LOCAL): PKG_CONFIG_PREFIX = $(XEN_ROOT) -$(PKG_CONFIG_LOCAL): PKG_CONFIG_INCDIR = $(XEN_libxenvchan) -$(PKG_CONFIG_LOCAL): PKG_CONFIG_LIBDIR = $(CURDIR) -$(PKG_CONFIG_LOCAL): PKG_CONFIG_CFLAGS_LOCAL = $(CFLAGS_xeninclude) - -.PHONY: all -all: libxenvchan.so vchan-node1 vchan-node2 vchan-socket-proxy libxenvchan.a $(PKG_CONFIG_INST) $(PKG_CONFIG_LOCAL) - -libxenvchan.so: libxenvchan.so.$(MAJOR) - ln -sf $< $@ - -libxenvchan.so.$(MAJOR): libxenvchan.so.$(MAJOR).$(MINOR) - ln -sf $< $@ - -libxenvchan.so.$(MAJOR).$(MINOR): $(LIBVCHAN_PIC_OBJS) - $(CC) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenvchan.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(LIBVCHAN_LIBS) $(APPEND_LDFLAGS) - -libxenvchan.a: $(LIBVCHAN_OBJS) - $(AR) rcs libxenvchan.a $^ - -vchan-node1: $(NODE_OBJS) libxenvchan.so - $(CC) $(LDFLAGS) -o $@ $(NODE_OBJS) $(LDLIBS_libxenvchan) $(APPEND_LDFLAGS) - -vchan-node2: $(NODE2_OBJS) libxenvchan.so - $(CC) $(LDFLAGS) -o $@ $(NODE2_OBJS) $(LDLIBS_libxenvchan) $(APPEND_LDFLAGS) - -vchan-socket-proxy: vchan-socket-proxy.o libxenvchan.so - $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenvchan) $(LDLIBS_libxenstore) $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) - -.PHONY: install -install: all - $(INSTALL_DIR) $(DESTDIR)$(libdir) - $(INSTALL_DIR) $(DESTDIR)$(includedir) - $(INSTALL_DIR) $(DESTDIR)$(bindir) - $(INSTALL_PROG) libxenvchan.so.$(MAJOR).$(MINOR) $(DESTDIR)$(libdir) - ln -sf libxenvchan.so.$(MAJOR).$(MINOR) $(DESTDIR)$(libdir)/libxenvchan.so.$(MAJOR) - ln -sf libxenvchan.so.$(MAJOR) $(DESTDIR)$(libdir)/libxenvchan.so - $(INSTALL_PROG) vchan-socket-proxy $(DESTDIR)$(bindir) - $(INSTALL_DATA) libxenvchan.h $(DESTDIR)$(includedir) - $(INSTALL_DATA) libxenvchan.a $(DESTDIR)$(libdir) - $(INSTALL_DATA) xenvchan.pc $(DESTDIR)$(PKG_INSTALLDIR) - -.PHONY: uninstall -uninstall: - rm -f $(DESTDIR)$(PKG_INSTALLDIR)/xenvchan.pc - rm -f $(DESTDIR)$(libdir)/libxenvchan.a - rm -f $(DESTDIR)$(includedir)/libxenvchan.h - rm -f $(DESTDIR)$(libdir)/libxenvchan.so - rm -f $(DESTDIR)$(libdir)/libxenvchan.so.$(MAJOR) - rm -f $(DESTDIR)$(libdir)/libxenvchan.so.$(MAJOR).$(MINOR) - -.PHONY: clean -clean: - $(RM) -f *.o *.opic *.so* *.a vchan-node1 vchan-node2 $(DEPS_RM) - $(RM) -f xenvchan.pc - -distclean: clean - --include $(DEPS_INCLUDE) diff --git a/tools/libvchan/init.c b/tools/libvchan/init.c deleted file mode 100644 index ad4b64fbe3..0000000000 --- a/tools/libvchan/init.c +++ /dev/null @@ -1,461 +0,0 @@ -/** - * @file - * @section AUTHORS - * - * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * - * Authors: - * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> - * - * @section LICENSE - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; If not, see <http://www.gnu.org/licenses/>. - * - * @section DESCRIPTION - * - * This file contains the setup code used to establish the ring buffer. - */ - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/ioctl.h> -#include <sys/user.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> - -#include <xenstore.h> -#include <xen/xen.h> -#include <xen/sys/evtchn.h> -#include <xen/sys/gntalloc.h> -#include <xen/sys/gntdev.h> -#include <libxenvchan.h> - -#ifndef PAGE_SHIFT -#define PAGE_SHIFT 12 -#endif - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - -#define SMALL_RING_SHIFT 10 -#define LARGE_RING_SHIFT 11 - -#define MAX_SMALL_RING (1 << SMALL_RING_SHIFT) -#define SMALL_RING_OFFSET 1024 -#define MAX_LARGE_RING (1 << LARGE_RING_SHIFT) -#define LARGE_RING_OFFSET 2048 - -// if you go over this size, you'll have too many grants to fit in the shared page. -#define MAX_RING_SHIFT 20 -#define MAX_RING_SIZE (1 << MAX_RING_SHIFT) - -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - -#define max(a,b) ((a > b) ? a : b) - -static int init_gnt_srv(struct libxenvchan *ctrl, int domain) -{ - int pages_left = ctrl->read.order >= PAGE_SHIFT ? 1 << (ctrl->read.order - PAGE_SHIFT) : 0; - int pages_right = ctrl->write.order >= PAGE_SHIFT ? 1 << (ctrl->write.order - PAGE_SHIFT) : 0; - uint32_t ring_ref = -1; - void *ring; - - ring = xengntshr_share_page_notify(ctrl->gntshr, domain, - &ring_ref, 1, offsetof(struct vchan_interface, srv_live), - ctrl->event_port); - - if (!ring) - goto out; - - memset(ring, 0, PAGE_SIZE); - - ctrl->ring = ring; - ctrl->read.shr = &ctrl->ring->left; - ctrl->write.shr = &ctrl->ring->right; - ctrl->ring->left_order = ctrl->read.order; - ctrl->ring->right_order = ctrl->write.order; - ctrl->ring->cli_live = 2; - ctrl->ring->srv_live = 1; - ctrl->ring->cli_notify = VCHAN_NOTIFY_WRITE; - - 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: - ctrl->read.buffer = xengntshr_share_pages(ctrl->gntshr, domain, - pages_left, ctrl->ring->grants, 1); - if (!ctrl->read.buffer) - goto out_ring; - } - - 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: - ctrl->write.buffer = xengntshr_share_pages(ctrl->gntshr, domain, - pages_right, ctrl->ring->grants + pages_left, 1); - if (!ctrl->write.buffer) - goto out_unmap_left; - } - -out: - return ring_ref; -out_unmap_left: - if (pages_left) - xengntshr_unshare(ctrl->gntshr, ctrl->read.buffer, pages_left); -out_ring: - xengntshr_unshare(ctrl->gntshr, ring, 1); - ring_ref = -1; - ctrl->ring = NULL; - ctrl->write.order = ctrl->read.order = 0; - goto out; -} - -static int init_gnt_cli(struct libxenvchan *ctrl, int domain, uint32_t ring_ref) -{ - int rv = -1; - uint32_t *grants; - - ctrl->ring = xengnttab_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 = xengnttab_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 = xengnttab_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) - xengnttab_unmap(ctrl->gnttab, ctrl->write.buffer, - 1 << (ctrl->write.order - PAGE_SHIFT)); - out_unmap_ring: - xengnttab_unmap(ctrl->gnttab, ctrl->ring, 1); - ctrl->ring = 0; - ctrl->write.order = ctrl->read.order = 0; - rv = -1; - goto out; -} - -static int init_evt_srv(struct libxenvchan *ctrl, int domain, - struct xentoollog_logger *logger) -{ - xenevtchn_port_or_error_t port; - - ctrl->event = xenevtchn_open(logger, 0); - if (!ctrl->event) - return -1; - - port = xenevtchn_bind_unbound_port(ctrl->event, domain); - if (port < 0) - goto fail; - ctrl->event_port = port; - - if (xenevtchn_unmask(ctrl->event, ctrl->event_port)) - goto fail; - - return 0; - -fail: - if (port >= 0) - xenevtchn_unbind(ctrl->event, port); - - xenevtchn_close(ctrl->event); - ctrl->event = NULL; - - return -1; -} - -static int init_xs_srv(struct libxenvchan *ctrl, int domain, const char* xs_base, int ring_ref) -{ - int ret = -1; - struct xs_handle *xs; - struct xs_permissions perms[2]; - char buf[64]; - char ref[16]; - char* domid_str = NULL; - xs_transaction_t xs_trans = XBT_NULL; - xs = xs_domain_open(); - if (!xs) - goto fail; - domid_str = xs_read(xs, 0, "domid", NULL); - if (!domid_str) - goto fail_xs_open; - - // owner domain is us - perms[0].id = atoi(domid_str); - // permissions for domains not listed = none - perms[0].perms = XS_PERM_NONE; - // other domains - perms[1].id = domain; - perms[1].perms = XS_PERM_READ; - -retry_transaction: - xs_trans = xs_transaction_start(xs); - if (!xs_trans) - goto fail_xs_open; - - snprintf(ref, sizeof ref, "%d", ring_ref); - snprintf(buf, sizeof buf, "%s/ring-ref", xs_base); - if (!xs_write(xs, xs_trans, buf, ref, strlen(ref))) - goto fail_xs_open; - if (!xs_set_permissions(xs, xs_trans, buf, perms, 2)) - goto fail_xs_open; - - snprintf(ref, sizeof ref, "%d", ctrl->event_port); - snprintf(buf, sizeof buf, "%s/event-channel", xs_base); - if (!xs_write(xs, xs_trans, buf, ref, strlen(ref))) - goto fail_xs_open; - if (!xs_set_permissions(xs, xs_trans, buf, perms, 2)) - goto fail_xs_open; - - if (!xs_transaction_end(xs, xs_trans, 0)) { - if (errno == EAGAIN) - goto retry_transaction; - } else { - ret = 0; - } - fail_xs_open: - free(domid_str); - xs_daemon_close(xs); - fail: - return ret; -} - -static int min_order(size_t siz) -{ - int rv = PAGE_SHIFT; - while (siz > (1 << rv)) - rv++; - return rv; -} - -struct libxenvchan *libxenvchan_server_init(struct xentoollog_logger *logger, - int domain, const char* xs_path, - size_t left_min, size_t right_min) -{ - struct libxenvchan *ctrl; - int ring_ref; - if (left_min > MAX_RING_SIZE || right_min > MAX_RING_SIZE) - return 0; - - ctrl = malloc(sizeof(*ctrl)); - if (!ctrl) - return 0; - - ctrl->ring = NULL; - ctrl->event = NULL; - ctrl->is_server = 1; - ctrl->server_persist = 0; - - ctrl->read.order = min_order(left_min); - ctrl->write.order = min_order(right_min); - - // if we can avoid allocating extra pages by using in-page rings, do so - if (left_min <= MAX_SMALL_RING && right_min <= MAX_LARGE_RING) { - ctrl->read.order = SMALL_RING_SHIFT; - ctrl->write.order = LARGE_RING_SHIFT; - } else if (left_min <= MAX_LARGE_RING && right_min <= MAX_SMALL_RING) { - ctrl->read.order = LARGE_RING_SHIFT; - ctrl->write.order = SMALL_RING_SHIFT; - } else if (left_min <= MAX_LARGE_RING) { - ctrl->read.order = LARGE_RING_SHIFT; - } else if (right_min <= MAX_LARGE_RING) { - ctrl->write.order = LARGE_RING_SHIFT; - } - - ctrl->gntshr = xengntshr_open(logger, 0); - if (!ctrl->gntshr) { - free(ctrl); - return 0; - } - - if (init_evt_srv(ctrl, domain, logger)) - goto out; - ring_ref = init_gnt_srv(ctrl, domain); - if (ring_ref < 0) - goto out; - if (init_xs_srv(ctrl, domain, xs_path, ring_ref)) - goto out; - return ctrl; -out: - libxenvchan_close(ctrl); - return 0; -} - -static int init_evt_cli(struct libxenvchan *ctrl, int domain, - struct xentoollog_logger *logger) -{ - xenevtchn_port_or_error_t port; - - ctrl->event = xenevtchn_open(logger, 0); - if (!ctrl->event) - return -1; - - port = xenevtchn_bind_interdomain(ctrl->event, - domain, ctrl->event_port); - if (port < 0) - goto fail; - ctrl->event_port = port; - - if (xenevtchn_unmask(ctrl->event, ctrl->event_port)) - goto fail; - - return 0; - -fail: - if (port >= 0) - xenevtchn_unbind(ctrl->event, port); - - xenevtchn_close(ctrl->event); - ctrl->event = NULL; - - return -1; -} - - -struct libxenvchan *libxenvchan_client_init(struct xentoollog_logger *logger, - int domain, const char* xs_path) -{ - struct libxenvchan *ctrl = malloc(sizeof(struct libxenvchan)); - struct xs_handle *xs = NULL; - char buf[64]; - char *ref; - int ring_ref; - unsigned int len; - - if (!ctrl) - return 0; - ctrl->ring = NULL; - ctrl->event = NULL; - ctrl->gnttab = NULL; - ctrl->write.order = ctrl->read.order = 0; - ctrl->is_server = 0; - - xs = xs_daemon_open(); - if (!xs) - xs = xs_domain_open(); - if (!xs) - goto fail; - -// find xenstore entry - snprintf(buf, sizeof buf, "%s/ring-ref", xs_path); - ref = xs_read(xs, 0, buf, &len); - if (!ref) - goto fail; - ring_ref = atoi(ref); - free(ref); - if (!ring_ref) - goto fail; - snprintf(buf, sizeof buf, "%s/event-channel", xs_path); - ref = xs_read(xs, 0, buf, &len); - if (!ref) - goto fail; - ctrl->event_port = atoi(ref); - free(ref); - if (!ctrl->event_port) - goto fail; - - ctrl->gnttab = xengnttab_open(logger, 0); - if (!ctrl->gnttab) - goto fail; - -// set up event channel - if (init_evt_cli(ctrl, domain, logger)) - goto fail; - -// set up shared page(s) - if (init_gnt_cli(ctrl, domain, ring_ref)) - goto fail; - - ctrl->ring->cli_live = 1; - ctrl->ring->srv_notify = VCHAN_NOTIFY_WRITE; - - /* wake up the server */ - xenevtchn_notify(ctrl->event, ctrl->event_port); - - out: - if (xs) - xs_daemon_close(xs); - return ctrl; - fail: - libxenvchan_close(ctrl); - ctrl = NULL; - goto out; -} diff --git a/tools/libvchan/io.c b/tools/libvchan/io.c deleted file mode 100644 index da303fbc01..0000000000 --- a/tools/libvchan/io.c +++ /dev/null @@ -1,388 +0,0 @@ -/** - * @file - * @section AUTHORS - * - * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * - * Authors: - * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> - * - * @section LICENSE - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; If not, see <http://www.gnu.org/licenses/>. - * - * @section DESCRIPTION - * - * This file contains the communications interface built on the ring buffer. - */ - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/ioctl.h> -#include <sys/uio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -#include <xenctrl.h> -#include <libxenvchan.h> - -#ifndef PAGE_SHIFT -#define PAGE_SHIFT 12 -#endif - -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - - -static inline uint32_t rd_prod(struct libxenvchan *ctrl) -{ - return ctrl->read.shr->prod; -} - -static inline uint32_t* _rd_cons(struct libxenvchan *ctrl) -{ - return &ctrl->read.shr->cons; -} -#define rd_cons(x) (*_rd_cons(x)) - -static inline uint32_t* _wr_prod(struct libxenvchan *ctrl) -{ - return &ctrl->write.shr->prod; -} -#define wr_prod(x) (*_wr_prod(x)) - -static inline uint32_t wr_cons(struct libxenvchan *ctrl) -{ - return ctrl->write.shr->cons; -} - -static inline const void* rd_ring(struct libxenvchan *ctrl) -{ - return ctrl->read.buffer; -} - -static inline void* wr_ring(struct libxenvchan *ctrl) -{ - return ctrl->write.buffer; -} - -static inline uint32_t wr_ring_size(struct libxenvchan *ctrl) -{ - return (1 << ctrl->write.order); -} - -static inline uint32_t rd_ring_size(struct libxenvchan *ctrl) -{ - return (1 << ctrl->read.order); -} - -static inline void request_notify(struct libxenvchan *ctrl, uint8_t bit) -{ - uint8_t *notify = ctrl->is_server ? &ctrl->ring->cli_notify : &ctrl->ring->srv_notify; - __sync_or_and_fetch(notify, bit); - xen_mb(); /* post the request /before/ caller re-reads any indexes */ -} - -static inline int send_notify(struct libxenvchan *ctrl, uint8_t bit) -{ - uint8_t *notify, prev; - xen_mb(); /* caller updates indexes /before/ we decode to notify */ - notify = ctrl->is_server ? &ctrl->ring->srv_notify : &ctrl->ring->cli_notify; - prev = __sync_fetch_and_and(notify, ~bit); - if (prev & bit) - return xenevtchn_notify(ctrl->event, ctrl->event_port); - else - return 0; -} - -/* - * Get the amount of buffer space available, and do nothing about - * notifications. - */ -static inline int raw_get_data_ready(struct libxenvchan *ctrl) -{ - uint32_t ready = rd_prod(ctrl) - rd_cons(ctrl); - xen_mb(); /* Ensure 'ready' is read only once. */ - if (ready > rd_ring_size(ctrl)) - /* We have no way to return errors. Locking up the ring is - * better than the alternatives. */ - return 0; - return ready; -} - -/** - * Get the amount of buffer space available and enable notifications if needed. - */ -static inline int fast_get_data_ready(struct libxenvchan *ctrl, size_t request) -{ - int ready = raw_get_data_ready(ctrl); - if (ready >= request) - return ready; - /* We plan to consume all data; please tell us if you send more */ - request_notify(ctrl, VCHAN_NOTIFY_WRITE); - /* - * If the writer moved rd_prod after our read but before request, we - * will not get notified even though the actual amount of data ready is - * above request. Reread rd_prod to cover this case. - */ - return raw_get_data_ready(ctrl); -} - -int libxenvchan_data_ready(struct libxenvchan *ctrl) -{ - /* Since this value is being used outside libxenvchan, request notification - * when it changes - */ - request_notify(ctrl, VCHAN_NOTIFY_WRITE); - return raw_get_data_ready(ctrl); -} - -/** - * Get the amount of buffer space available, and do nothing - * about notifications - */ -static inline int raw_get_buffer_space(struct libxenvchan *ctrl) -{ - uint32_t ready = wr_ring_size(ctrl) - (wr_prod(ctrl) - wr_cons(ctrl)); - xen_mb(); /* Ensure 'ready' is read only once. */ - if (ready > wr_ring_size(ctrl)) - /* We have no way to return errors. Locking up the ring is - * better than the alternatives. */ - return 0; - return ready; -} - -/** - * Get the amount of buffer space available and enable notifications if needed. - */ -static inline int fast_get_buffer_space(struct libxenvchan *ctrl, size_t request) -{ - int ready = raw_get_buffer_space(ctrl); - if (ready >= request) - return ready; - /* We plan to fill the buffer; please tell us when you've read it */ - request_notify(ctrl, VCHAN_NOTIFY_READ); - /* - * If the reader moved wr_cons after our read but before request, we - * will not get notified even though the actual amount of buffer space - * is above request. Reread wr_cons to cover this case. - */ - return raw_get_buffer_space(ctrl); -} - -int libxenvchan_buffer_space(struct libxenvchan *ctrl) -{ - /* Since this value is being used outside libxenvchan, request notification - * when it changes - */ - request_notify(ctrl, VCHAN_NOTIFY_READ); - return raw_get_buffer_space(ctrl); -} - -int libxenvchan_wait(struct libxenvchan *ctrl) -{ - int ret = xenevtchn_pending(ctrl->event); - if (ret < 0) - return -1; - xenevtchn_unmask(ctrl->event, ret); - return 0; -} - -/** - * returns -1 on error, or size on success - * - * caller must have checked that enough space is available - */ -static int do_send(struct libxenvchan *ctrl, const void *data, size_t size) -{ - int real_idx = wr_prod(ctrl) & (wr_ring_size(ctrl) - 1); - int avail_contig = wr_ring_size(ctrl) - real_idx; - if (avail_contig > size) - avail_contig = size; - xen_mb(); /* read indexes /then/ write data */ - memcpy(wr_ring(ctrl) + real_idx, data, avail_contig); - if (avail_contig < size) - { - // we rolled across the end of the ring - memcpy(wr_ring(ctrl), data + avail_contig, size - avail_contig); - } - xen_wmb(); /* write data /then/ notify */ - wr_prod(ctrl) += size; - if (send_notify(ctrl, VCHAN_NOTIFY_WRITE)) - return -1; - return size; -} - -/** - * returns 0 if no buffer space is available, -1 on error, or size on success - */ -int libxenvchan_send(struct libxenvchan *ctrl, const void *data, size_t size) -{ - int avail; - while (1) { - if (!libxenvchan_is_open(ctrl)) - return -1; - avail = fast_get_buffer_space(ctrl, size); - if (size <= avail) - return do_send(ctrl, data, size); - if (!ctrl->blocking) - return 0; - if (size > wr_ring_size(ctrl)) - return -1; - if (libxenvchan_wait(ctrl)) - return -1; - } -} - -int libxenvchan_write(struct libxenvchan *ctrl, const void *data, size_t size) -{ - int avail; - if (!libxenvchan_is_open(ctrl)) - return -1; - if (ctrl->blocking) { - size_t pos = 0; - while (1) { - avail = fast_get_buffer_space(ctrl, size - pos); - if (pos + avail > size) - avail = size - pos; - if (avail) - pos += do_send(ctrl, data + pos, avail); - if (pos == size) - return pos; - if (libxenvchan_wait(ctrl)) - return -1; - if (!libxenvchan_is_open(ctrl)) - return -1; - } - } else { - avail = fast_get_buffer_space(ctrl, size); - if (size > avail) - size = avail; - if (size == 0) - return 0; - return do_send(ctrl, data, size); - } -} - -/** - * returns -1 on error, or size on success - * - * caller must have checked that enough data is available - */ -static int do_recv(struct libxenvchan *ctrl, void *data, size_t size) -{ - int real_idx = rd_cons(ctrl) & (rd_ring_size(ctrl) - 1); - int avail_contig = rd_ring_size(ctrl) - real_idx; - if (avail_contig > size) - avail_contig = size; - xen_rmb(); /* data read must happen /after/ rd_cons read */ - memcpy(data, rd_ring(ctrl) + real_idx, avail_contig); - if (avail_contig < size) - { - // we rolled across the end of the ring - memcpy(data + avail_contig, rd_ring(ctrl), size - avail_contig); - } - xen_mb(); /* consume /then/ notify */ - rd_cons(ctrl) += size; - if (send_notify(ctrl, VCHAN_NOTIFY_READ)) - return -1; - return size; -} - -/** - * reads exactly size bytes from the vchan. - * returns 0 if insufficient data is available, -1 on error, or size on success - */ -int libxenvchan_recv(struct libxenvchan *ctrl, void *data, size_t size) -{ - while (1) { - int avail = fast_get_data_ready(ctrl, size); - if (size <= avail) - return do_recv(ctrl, data, size); - if (!libxenvchan_is_open(ctrl)) - return -1; - if (!ctrl->blocking) - return 0; - if (size > rd_ring_size(ctrl)) - return -1; - if (libxenvchan_wait(ctrl)) - return -1; - } -} - -int libxenvchan_read(struct libxenvchan *ctrl, void *data, size_t size) -{ - while (1) { - int avail = fast_get_data_ready(ctrl, size); - if (avail && size > avail) - size = avail; - if (avail) - return do_recv(ctrl, data, size); - if (!libxenvchan_is_open(ctrl)) - return -1; - if (!ctrl->blocking) - return 0; - if (libxenvchan_wait(ctrl)) - return -1; - } -} - -int libxenvchan_is_open(struct libxenvchan* ctrl) -{ - if (ctrl->is_server) - return ctrl->server_persist ? 1 : ctrl->ring->cli_live; - else - return ctrl->ring->srv_live; -} - -int libxenvchan_fd_for_select(struct libxenvchan *ctrl) -{ - return xenevtchn_fd(ctrl->event); -} - -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; - xengntshr_unshare(ctrl->gntshr, ctrl->ring, 1); - } else { - ctrl->ring->cli_live = 0; - xengnttab_unmap(ctrl->gnttab, ctrl->ring, 1); - } - } - if (ctrl->event) { - if (ctrl->ring) - xenevtchn_notify(ctrl->event, ctrl->event_port); - xenevtchn_close(ctrl->event); - } - if (ctrl->is_server) { - if (ctrl->gntshr) - xengntshr_close(ctrl->gntshr); - } else { - if (ctrl->gnttab) - xengnttab_close(ctrl->gnttab); - } - free(ctrl); -} diff --git a/tools/libvchan/libxenvchan.h b/tools/libvchan/libxenvchan.h deleted file mode 100644 index d6010b145d..0000000000 --- a/tools/libvchan/libxenvchan.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file - * @section AUTHORS - * - * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * - * Authors: - * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> - * - * @section LICENSE - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; If not, see <http://www.gnu.org/licenses/>. - * - * @section DESCRIPTION - * - * Originally borrowed from the Qubes OS Project, http://www.qubes-os.org, - * this code has been substantially rewritten to use the gntdev and gntalloc - * devices instead of raw MFNs and map_foreign_range. - * - * This is a library for inter-domain communication. A standard Xen ring - * buffer is used, with a datagram-based interface built on top. The grant - * reference and event channels are shared in XenStore under the path - * /local/domain/<srv-id>/data/vchan/<cli-id>/<port>/{ring-ref,event-channel} - * - * The ring.h macros define an asymmetric interface to a shared data structure - * that assumes all rings reside in a single contiguous memory space. This is - * not suitable for vchan because the interface to the ring is symmetric except - * for the setup. Unlike the producer-consumer rings defined in ring.h, the - * size of the rings used in vchan are determined at execution time instead of - * compile time, so the macros in ring.h cannot be used to access the rings. - */ - -#include <xen/io/libxenvchan.h> -#include <xen/xen.h> -#include <xen/sys/evtchn.h> -#include <xenevtchn.h> -#include <xengnttab.h> - -/* Callers who don't care don't need to #include <xentoollog.h> */ -struct xentoollog_logger; - -struct libxenvchan_ring { - /* Pointer into the shared page. Offsets into buffer. */ - struct ring_shared* shr; - /* ring data; may be its own shared page(s) depending on order */ - void* buffer; - /** - * The size of the ring is (1 << order); offsets wrap around when they - * exceed this. This copy is required because we can't trust the order - * in the shared page to remain constant. - */ - int order; -}; - -/** - * struct libxenvchan: control structure passed to all library calls - */ -struct libxenvchan { - /* Mapping handle for shared ring page */ - union { - xengntshr_handle *gntshr; /* for server */ - xengnttab_handle *gnttab; /* for client */ - }; - /* Pointer to shared ring page */ - struct vchan_interface *ring; - /* event channel interface */ - xenevtchn_handle *event; - uint32_t event_port; - /* informative flags: are we acting as server? */ - int is_server:1; - /* true if server remains active when client closes (allows reconnection) */ - int server_persist:1; - /* true if operations should block instead of returning 0 */ - int blocking:1; - /* communication rings */ - struct libxenvchan_ring read, write; -}; - -/** - * Set up a vchan, including granting pages - * @param logger Logger for libxc errors - * @param domain The peer domain that will be connecting - * @param xs_path Base xenstore path for storing ring/event data - * @param send_min The minimum size (in bytes) of the send ring (left) - * @param recv_min The minimum size (in bytes) of the receive ring (right) - * @return The structure, or NULL in case of an error - */ -struct libxenvchan *libxenvchan_server_init(struct xentoollog_logger *logger, - int domain, const char* xs_path, - size_t read_min, size_t write_min); -/** - * Connect to an existing vchan. Note: you can reconnect to an existing vchan - * safely, however no locking is performed, so you must prevent multiple clients - * from connecting to a single server. - * - * @param logger Logger for libxc errors - * @param domain The peer domain to connect to - * @param xs_path Base xenstore path for storing ring/event data - * @return The structure, or NULL in case of an error - */ -struct libxenvchan *libxenvchan_client_init(struct xentoollog_logger *logger, - int domain, const char* xs_path); -/** - * Close a vchan. This deallocates the vchan and attempts to free its - * resources. The other side is notified of the close, but can still read any - * data pending prior to the close. - */ -void libxenvchan_close(struct libxenvchan *ctrl); - -/** - * Packet-based receive: always reads exactly $size bytes. - * @param ctrl The vchan control structure - * @param data Buffer for data that was read - * @param size Size of the buffer and amount of data to read - * @return -1 on error, 0 if nonblocking and insufficient data is available, or $size - */ -int libxenvchan_recv(struct libxenvchan *ctrl, void *data, size_t size); -/** - * Stream-based receive: reads as much data as possible. - * @param ctrl The vchan control structure - * @param data Buffer for data that was read - * @param size Size of the buffer - * @return -1 on error, otherwise the amount of data read (which may be zero if - * the vchan is nonblocking) - */ -int libxenvchan_read(struct libxenvchan *ctrl, void *data, size_t size); -/** - * Packet-based send: send entire buffer if possible - * @param ctrl The vchan control structure - * @param data Buffer for data to send - * @param size Size of the buffer and amount of data to send - * @return -1 on error, 0 if nonblocking and insufficient space is available, or $size - */ -int libxenvchan_send(struct libxenvchan *ctrl, const void *data, size_t size); -/** - * Stream-based send: send as much data as possible. - * @param ctrl The vchan control structure - * @param data Buffer for data to send - * @param size Size of the buffer - * @return -1 on error, otherwise the amount of data sent (which may be zero if - * the vchan is nonblocking) - */ -int libxenvchan_write(struct libxenvchan *ctrl, const void *data, size_t size); -/** - * Waits for reads or writes to unblock, or for a close - */ -int libxenvchan_wait(struct libxenvchan *ctrl); -/** - * Returns the event file descriptor for this vchan. When this FD is readable, - * libxenvchan_wait() will not block, and the state of the vchan has changed since - * the last invocation of libxenvchan_wait(). - */ -int libxenvchan_fd_for_select(struct libxenvchan *ctrl); -/** - * Query the state of the vchan shared page: - * return 0 when one side has called libxenvchan_close() or crashed - * return 1 when both sides are open - * return 2 [server only] when no client has yet connected - */ -int libxenvchan_is_open(struct libxenvchan* ctrl); -/** Amount of data ready to read, in bytes */ -int libxenvchan_data_ready(struct libxenvchan *ctrl); -/** Amount of data it is possible to send without blocking */ -int libxenvchan_buffer_space(struct libxenvchan *ctrl); diff --git a/tools/libvchan/node-select.c b/tools/libvchan/node-select.c deleted file mode 100644 index 039464427a..0000000000 --- a/tools/libvchan/node-select.c +++ /dev/null @@ -1,186 +0,0 @@ -/** - * @file - * @section AUTHORS - * - * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * - * Authors: - * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; If not, see <http://www.gnu.org/licenses/>. - * - * @section DESCRIPTION - * - * This is a test program for libxenvchan. Communications are bidirectional, - * with either server (grant offeror) or client able to read and write. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> - -#include <libxenvchan.h> - -static void usage(char** argv) -{ - fprintf(stderr, "usage:\n" - "\t%s [client|server] domainid nodepath [rbufsiz wbufsiz]\n", - argv[0]); - exit(1); -} - -#define BUFSIZE 5000 -char inbuf[BUFSIZE]; -char outbuf[BUFSIZE]; -int insiz = 0; -int outsiz = 0; -struct libxenvchan *ctrl = 0; - -static void vchan_wr(void) { - int ret; - - if (!insiz) - return; - ret = libxenvchan_write(ctrl, inbuf, insiz); - if (ret < 0) { - fprintf(stderr, "vchan write failed\n"); - exit(1); - } - if (ret > 0) { - insiz -= ret; - memmove(inbuf, inbuf + ret, insiz); - } -} - -static void stdout_wr(void) { - int ret; - - if (!outsiz) - return; - ret = write(1, outbuf, outsiz); - if (ret < 0 && errno != EAGAIN) - exit(1); - if (ret > 0) { - outsiz -= ret; - memmove(outbuf, outbuf + ret, outsiz); - } -} - -static int set_nonblocking(int fd, int nonblocking) { - int flags = fcntl(fd, F_GETFL); - if (flags == -1) - return -1; - - if (nonblocking) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) == -1) - return -1; - - return 0; -} - -/** - Simple libxenvchan application, both client and server. - Both sides may write and read, both from the libxenvchan and from - stdin/stdout (just like netcat). -*/ - -int main(int argc, char **argv) -{ - int ret; - int libxenvchan_fd; - if (argc < 4 || argv[3][0] != '/') - usage(argv); - if (!strcmp(argv[1], "server")) { - int rsiz = argc > 4 ? atoi(argv[4]) : 0; - int wsiz = argc > 5 ? atoi(argv[5]) : 0; - ctrl = libxenvchan_server_init(NULL, atoi(argv[2]), argv[3], rsiz, wsiz); - } else if (!strcmp(argv[1], "client")) - ctrl = libxenvchan_client_init(NULL, atoi(argv[2]), argv[3]); - else - usage(argv); - if (!ctrl) { - perror("libxenvchan_*_init"); - exit(1); - } - - if (set_nonblocking(0, 1) || set_nonblocking(1, 1)) { - perror("set_nonblocking"); - exit(1); - } - - libxenvchan_fd = libxenvchan_fd_for_select(ctrl); - for (;;) { - fd_set rfds; - fd_set wfds; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - if (insiz != BUFSIZE) - FD_SET(0, &rfds); - if (outsiz) - FD_SET(1, &wfds); - FD_SET(libxenvchan_fd, &rfds); - ret = select(libxenvchan_fd + 1, &rfds, &wfds, NULL, NULL); - if (ret < 0) { - perror("select"); - exit(1); - } - if (FD_ISSET(0, &rfds)) { - ret = read(0, inbuf + insiz, BUFSIZE - insiz); - if (ret < 0 && errno != EAGAIN) - exit(1); - if (ret == 0) { - while (insiz) { - vchan_wr(); - libxenvchan_wait(ctrl); - } - return 0; - } - if (ret) - insiz += ret; - vchan_wr(); - } - if (FD_ISSET(libxenvchan_fd, &rfds)) { - libxenvchan_wait(ctrl); - vchan_wr(); - } - if (FD_ISSET(1, &wfds)) - stdout_wr(); - while (libxenvchan_data_ready(ctrl) && outsiz < BUFSIZE) { - ret = libxenvchan_read(ctrl, outbuf + outsiz, BUFSIZE - outsiz); - if (ret < 0) - exit(1); - outsiz += ret; - stdout_wr(); - } - if (!libxenvchan_is_open(ctrl)) { - if (set_nonblocking(1, 0)) { - perror("set_nonblocking"); - exit(1); - } - while (outsiz) - stdout_wr(); - return 0; - } - } -} diff --git a/tools/libvchan/node.c b/tools/libvchan/node.c deleted file mode 100644 index f1638f013d..0000000000 --- a/tools/libvchan/node.c +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @file - * @section AUTHORS - * - * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * - * Authors: - * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; If not, see <http://www.gnu.org/licenses/>. - * - * @section DESCRIPTION - * - * This is a test program for libxenvchan. Communications are in one direction, - * either server (grant offeror) to client or vice versa. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <time.h> - -#include <libxenvchan.h> - -int libxenvchan_write_all(struct libxenvchan *ctrl, char *buf, int size) -{ - int written = 0; - int ret; - while (written < size) { - ret = libxenvchan_write(ctrl, buf + written, size - written); - if (ret <= 0) { - perror("write"); - exit(1); - } - written += ret; - } - return size; -} - -int write_all(int fd, char *buf, int size) -{ - int written = 0; - int ret; - while (written < size) { - ret = write(fd, buf + written, size - written); - if (ret <= 0) { - perror("write"); - exit(1); - } - written += ret; - } - return size; -} - -void usage(char** argv) -{ - fprintf(stderr, "usage:\n" - "%s [client|server] [read|write] domid nodepath\n", argv[0]); - exit(1); -} - -#define BUFSIZE 5000 -char buf[BUFSIZE]; -void reader(struct libxenvchan *ctrl) -{ - int size; - for (;;) { - size = rand() % (BUFSIZE - 1) + 1; - size = libxenvchan_read(ctrl, buf, size); - fprintf(stderr, "#"); - if (size < 0) { - perror("read vchan"); - libxenvchan_close(ctrl); - exit(1); - } - size = write_all(1, buf, size); - if (size < 0) { - perror("stdout write"); - exit(1); - } - if (size == 0) { - perror("write size=0?\n"); - exit(1); - } - } -} - -void writer(struct libxenvchan *ctrl) -{ - int size; - for (;;) { - size = rand() % (BUFSIZE - 1) + 1; - size = read(0, buf, size); - if (size < 0) { - perror("read stdin"); - libxenvchan_close(ctrl); - exit(1); - } - if (size == 0) - break; - size = libxenvchan_write_all(ctrl, buf, size); - fprintf(stderr, "#"); - if (size < 0) { - perror("vchan write"); - exit(1); - } - if (size == 0) { - perror("write size=0?\n"); - exit(1); - } - } -} - - -/** - Simple libxenvchan application, both client and server. - One side does writing, the other side does reading; both from - standard input/output fds. -*/ -int main(int argc, char **argv) -{ - int seed = time(0); - struct libxenvchan *ctrl = 0; - int wr = 0; - if (argc < 4) - usage(argv); - if (!strcmp(argv[2], "read")) - wr = 0; - else if (!strcmp(argv[2], "write")) - wr = 1; - else - usage(argv); - if (!strcmp(argv[1], "server")) - ctrl = libxenvchan_server_init(NULL, atoi(argv[3]), argv[4], 0, 0); - else if (!strcmp(argv[1], "client")) - ctrl = libxenvchan_client_init(NULL, atoi(argv[3]), argv[4]); - else - usage(argv); - if (!ctrl) { - perror("libxenvchan_*_init"); - exit(1); - } - ctrl->blocking = 1; - - srand(seed); - fprintf(stderr, "seed=%d\n", seed); - if (wr) - writer(ctrl); - else - reader(ctrl); - libxenvchan_close(ctrl); - return 0; -} diff --git a/tools/libvchan/vchan-socket-proxy.c b/tools/libvchan/vchan-socket-proxy.c deleted file mode 100644 index e1d959c6d1..0000000000 --- a/tools/libvchan/vchan-socket-proxy.c +++ /dev/null @@ -1,533 +0,0 @@ -/** - * @file - * @section AUTHORS - * - * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * - * Authors: - * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> - * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> - * Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx> - * - * @section LICENSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; If not, see <http://www.gnu.org/licenses/>. - * - * @section DESCRIPTION - * - * This is a vchan to unix socket proxy. Vchan server is set, and on client - * connection, local socket connection is established. Communication is bidirectional. - * One client is served at a time, clients needs to coordinate this themselves. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <getopt.h> - -#include <xenstore.h> -#include <xenctrl.h> -#include <libxenvchan.h> - -static void usage(char** argv) -{ - fprintf(stderr, "usage:\n" - "\t%s [options] domainid nodepath [socket-path|file-no|-]\n" - "\n" - "options:\n" - "\t-m, --mode=client|server - vchan connection mode (client by default)\n" - "\t-s, --state-path=path - xenstore path where write \"running\" to \n" - "\t at startup\n" - "\t-v, --verbose - verbose logging\n" - "\n" - "client: client of a vchan connection, fourth parameter can be:\n" - "\tsocket-path: listen on a UNIX socket at this path and connect to vchan\n" - "\t whenever new connection is accepted;\n" - "\t handle multiple _subsequent_ connections, until terminated\n" - "\n" - "\tfile-no: except open FD of a socket in listen mode;\n" - "\t otherwise similar to socket-path\n" - "\n" - "\t-: open vchan connection immediately and pass the data\n" - "\t from stdin/stdout; terminate when vchan connection\n" - "\t is closed\n" - "\n" - "server: server of a vchan connection, fourth parameter can be:\n" - "\tsocket-path: connect to this UNIX socket when new vchan connection\n" - "\t is accepted;\n" - "\t handle multiple _subsequent_ connections, until terminated\n" - "\n" - "\tfile-no: pass data to/from this FD; terminate when vchan connection\n" - "\t is closed\n" - "\n" - "\t-: pass data to/from stdin/stdout; terminate when vchan\n" - "\t connection is closed\n", - argv[0]); - exit(1); -} - -#define BUFSIZE 8192 -char inbuf[BUFSIZE]; -char outbuf[BUFSIZE]; -int insiz = 0; -int outsiz = 0; -int verbose = 0; - -struct vchan_proxy_state { - struct libxenvchan *ctrl; - int output_fd; - int input_fd; -}; - -static void vchan_wr(struct libxenvchan *ctrl) { - int ret; - - if (!insiz) - return; - ret = libxenvchan_write(ctrl, inbuf, insiz); - if (ret < 0) { - fprintf(stderr, "vchan write failed\n"); - exit(1); - } - if (verbose) - fprintf(stderr, "wrote %d bytes to vchan\n", ret); - if (ret > 0) { - insiz -= ret; - memmove(inbuf, inbuf + ret, insiz); - } -} - -static void socket_wr(int output_fd) { - int ret; - - if (!outsiz) - return; - ret = write(output_fd, outbuf, outsiz); - if (ret < 0 && errno != EAGAIN) - exit(1); - if (ret > 0) { - outsiz -= ret; - memmove(outbuf, outbuf + ret, outsiz); - } -} - -static int set_nonblocking(int fd, int nonblocking) { - int flags = fcntl(fd, F_GETFL); - if (flags == -1) - return -1; - - if (nonblocking) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) == -1) - return -1; - - return 0; -} - -static int connect_socket(const char *path_or_fd) { - int fd; - char *endptr; - struct sockaddr_un addr; - - fd = strtoll(path_or_fd, &endptr, 0); - if (*endptr == '\0') { - set_nonblocking(fd, 1); - return fd; - } - - if (strlen(path_or_fd) >= sizeof(addr.sun_path)) { - fprintf(stderr, "UNIX socket path \"%s\" too long (%zd >= %zd)\n", - path_or_fd, strlen(path_or_fd), sizeof(addr.sun_path)); - return -1; - } - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - perror("socket"); - return -1; - } - - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, path_or_fd); - if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { - perror("connect"); - close(fd); - return -1; - } - - set_nonblocking(fd, 1); - - return fd; -} - -static int listen_socket(const char *path_or_fd) { - int fd; - char *endptr; - struct sockaddr_un addr; - - fd = strtoll(path_or_fd, &endptr, 0); - if (*endptr == '\0') { - return fd; - } - - if (strlen(path_or_fd) >= sizeof(addr.sun_path)) { - fprintf(stderr, "UNIX socket path \"%s\" too long (%zd >= %zd)\n", - path_or_fd, strlen(path_or_fd), sizeof(addr.sun_path)); - return -1; - } - - /* if not a number, assume a socket path */ - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - perror("socket"); - return -1; - } - - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, path_or_fd); - if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { - perror("bind"); - close(fd); - return -1; - } - if (listen(fd, 5) != 0) { - perror("listen"); - close(fd); - return -1; - } - - return fd; -} - -static struct libxenvchan *connect_vchan(int domid, const char *path) { - struct libxenvchan *ctrl = NULL; - struct xs_handle *xs = NULL; - xc_interface *xc = NULL; - xc_dominfo_t dominfo; - char **watch_ret; - unsigned int watch_num; - int ret; - - xs = xs_open(XS_OPEN_READONLY); - if (!xs) { - perror("xs_open"); - goto out; - } - xc = xc_interface_open(NULL, NULL, XC_OPENFLAG_NON_REENTRANT); - if (!xc) { - perror("xc_interface_open"); - goto out; - } - /* wait for vchan server to create *path* */ - if (!xs_watch(xs, path, "path")) { - fprintf(stderr, "xs_watch(%s) failed.\n", path); - goto out; - } - if (!xs_watch(xs, "@releaseDomain", "release")) { - fprintf(stderr, "xs_watch(@releaseDomain failed.\n"); - goto out; - } - - while ((watch_ret = xs_read_watch(xs, &watch_num))) { - /* don't care about exact which fired the watch */ - free(watch_ret); - ctrl = libxenvchan_client_init(NULL, domid, path); - if (ctrl) - break; - - ret = xc_domain_getinfo(xc, domid, 1, &dominfo); - /* break the loop if domain is definitely not there anymore, but - * continue if it is or the call failed (like EPERM) */ - if (ret == -1 && errno == ESRCH) - break; - if (ret == 1 && (dominfo.domid != (uint32_t)domid || dominfo.dying)) - break; - } - -out: - if (xc) - xc_interface_close(xc); - if (xs) - xs_close(xs);
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |