Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Sep 2014 17:14:12 +0000 (UTC)
From:      Roger Pau Monné <royger@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r272314 - in head/sys: conf dev/xen/xenstore xen/xenstore
Message-ID:  <201409301714.s8UHECCa007289@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: royger
Date: Tue Sep 30 17:14:11 2014
New Revision: 272314
URL: http://svnweb.freebsd.org/changeset/base/272314

Log:
  xen: move xenstore devices
  
  Move xenstore related devices (xenstore.c and xenstore_dev.c) from
  xen/xenstore to dev/xen/xenstore. This is just code motion, no
  functional changes.
  
  Sponsored by: Citrix Systems R&D

Added:
  head/sys/dev/xen/xenstore/
  head/sys/dev/xen/xenstore/xenstore.c
     - copied unchanged from r272308, head/sys/xen/xenstore/xenstore.c
  head/sys/dev/xen/xenstore/xenstore_dev.c
     - copied unchanged from r272308, head/sys/xen/xenstore/xenstore_dev.c
Deleted:
  head/sys/xen/xenstore/xenstore.c
  head/sys/xen/xenstore/xenstore_dev.c
Modified:
  head/sys/conf/files

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Sep 30 16:55:19 2014	(r272313)
+++ head/sys/conf/files	Tue Sep 30 17:14:11 2014	(r272314)
@@ -2638,6 +2638,8 @@ dev/xen/netfront/netfront.c	optional xen
 dev/xen/xenpci/xenpci.c		optional xenpci
 dev/xen/timer/timer.c		optional xen | xenhvm
 dev/xen/pvcpu/pvcpu.c		optional xen | xenhvm
+dev/xen/xenstore/xenstore.c	optional xen | xenhvm
+dev/xen/xenstore/xenstore_dev.c	optional xen | xenhvm
 dev/xl/if_xl.c			optional xl pci
 dev/xl/xlphy.c			optional xl pci
 fs/autofs/autofs.c		optional autofs
@@ -3976,8 +3978,6 @@ xen/xenbus/xenbusb_if.m		optional xen | 
 xen/xenbus/xenbusb.c		optional xen | xenhvm
 xen/xenbus/xenbusb_front.c	optional xen | xenhvm
 xen/xenbus/xenbusb_back.c	optional xen | xenhvm
-xen/xenstore/xenstore.c		optional xen | xenhvm
-xen/xenstore/xenstore_dev.c	optional xen | xenhvm
 xdr/xdr.c			optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
 xdr/xdr_array.c			optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
 xdr/xdr_mbuf.c			optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd

Copied: head/sys/dev/xen/xenstore/xenstore.c (from r272308, head/sys/xen/xenstore/xenstore.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/xen/xenstore/xenstore.c	Tue Sep 30 17:14:11 2014	(r272314, copy of r272308, head/sys/xen/xenstore/xenstore.c)
@@ -0,0 +1,1640 @@
+/******************************************************************************
+ * xenstore.c
+ *
+ * Low-level kernel interface to the XenStore.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009,2010 Spectra Logic Corporation
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+#include <sys/syslog.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+#include <sys/unistd.h>
+
+#include <machine/stdarg.h>
+
+#include <xen/xen-os.h>
+#include <xen/hypervisor.h>
+#include <xen/xen_intr.h>
+
+#include <xen/interface/hvm/params.h>
+#include <xen/hvm.h>
+
+#include <xen/xenstore/xenstorevar.h>
+#include <xen/xenstore/xenstore_internal.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+/**
+ * \file xenstore.c
+ * \brief XenStore interface
+ *
+ * The XenStore interface is a simple storage system that is a means of
+ * communicating state and configuration data between the Xen Domain 0
+ * and the various guest domains.  All configuration data other than
+ * a small amount of essential information required during the early
+ * boot process of launching a Xen aware guest, is managed using the
+ * XenStore.
+ *
+ * The XenStore is ASCII string based, and has a structure and semantics
+ * similar to a filesystem.  There are files and directories, the directories
+ * able to contain files or other directories.  The depth of the hierachy
+ * is only limited by the XenStore's maximum path length.
+ *
+ * The communication channel between the XenStore service and other
+ * domains is via two, guest specific, ring buffers in a shared memory
+ * area.  One ring buffer is used for communicating in each direction.
+ * The grant table references for this shared memory are given to the
+ * guest either via the xen_start_info structure for a fully para-
+ * virtualized guest, or via HVM hypercalls for a hardware virtualized
+ * guest.
+ *
+ * The XenStore communication relies on an event channel and thus
+ * interrupts.  For this reason, the attachment of the XenStore
+ * relies on an interrupt driven configuration hook to hold off
+ * boot processing until communication with the XenStore service
+ * can be established.
+ *
+ * Several Xen services depend on the XenStore, most notably the
+ * XenBus used to discover and manage Xen devices.  These services
+ * are implemented as NewBus child attachments to a bus exported
+ * by this XenStore driver.
+ */
+
+static struct xs_watch *find_watch(const char *token);
+
+MALLOC_DEFINE(M_XENSTORE, "xenstore", "XenStore data and results");
+
+/**
+ * Pointer to shared memory communication structures allowing us
+ * to communicate with the XenStore service.
+ *
+ * When operating in full PV mode, this pointer is set early in kernel
+ * startup from within xen_machdep.c.  In HVM mode, we use hypercalls
+ * to get the guest frame number for the shared page and then map it
+ * into kva.  See xs_init() for details.
+ */
+struct xenstore_domain_interface *xen_store;
+
+/*-------------------------- Private Data Structures ------------------------*/
+
+/**
+ * Structure capturing messages received from the XenStore service.
+ */
+struct xs_stored_msg {
+	TAILQ_ENTRY(xs_stored_msg) list;
+
+	struct xsd_sockmsg hdr;
+
+	union {
+		/* Queued replies. */
+		struct {
+			char *body;
+		} reply;
+
+		/* Queued watch events. */
+		struct {
+			struct xs_watch *handle;
+			const char **vec;
+			u_int vec_size;
+		} watch;
+	} u;
+};
+TAILQ_HEAD(xs_stored_msg_list, xs_stored_msg);
+
+/**
+ * Container for all XenStore related state.
+ */
+struct xs_softc {
+	/** Newbus device for the XenStore. */
+	device_t xs_dev;
+
+	/**
+	 * Lock serializing access to ring producer/consumer
+	 * indexes.  Use of this lock guarantees that wakeups
+	 * of blocking readers/writers are not missed due to
+	 * races with the XenStore service.
+	 */
+	struct mtx ring_lock;
+
+	/*
+	 * Mutex used to insure exclusive access to the outgoing
+	 * communication ring.  We use a lock type that can be
+	 * held while sleeping so that xs_write() can block waiting
+	 * for space in the ring to free up, without allowing another
+	 * writer to come in and corrupt a partial message write.
+	 */
+	struct sx request_mutex;
+
+	/**
+	 * A list of replies to our requests.
+	 *
+	 * The reply list is filled by xs_rcv_thread().  It
+	 * is consumed by the context that issued the request
+	 * to which a reply is made.  The requester blocks in
+	 * xs_read_reply().
+	 *
+	 * /note Only one requesting context can be active at a time.
+	 *       This is guaranteed by the request_mutex and insures
+	 *	 that the requester sees replies matching the order
+	 *	 of its requests.
+	 */
+	struct xs_stored_msg_list reply_list;
+
+	/** Lock protecting the reply list. */
+	struct mtx reply_lock;
+
+	/**
+	 * List of registered watches.
+	 */
+	struct xs_watch_list  registered_watches;
+
+	/** Lock protecting the registered watches list. */
+	struct mtx registered_watches_lock;
+
+	/**
+	 * List of pending watch callback events.
+	 */
+	struct xs_stored_msg_list watch_events;
+
+	/** Lock protecting the watch calback list. */
+	struct mtx watch_events_lock;
+
+	/**
+	 * Sleepable lock used to prevent VM suspension while a
+	 * xenstore transaction is outstanding.
+	 *
+	 * Each active transaction holds a shared lock on the
+	 * suspend mutex.  Our suspend method blocks waiting
+	 * to acquire an exclusive lock.  This guarantees that
+	 * suspend processing will only proceed once all active
+	 * transactions have been retired.
+	 */
+	struct sx suspend_mutex;
+
+	/**
+	 * The processid of the xenwatch thread.
+	 */
+	pid_t xenwatch_pid;
+
+	/**
+	 * Sleepable mutex used to gate the execution of XenStore
+	 * watch event callbacks.
+	 *
+	 * xenwatch_thread holds an exclusive lock on this mutex
+	 * while delivering event callbacks, and xenstore_unregister_watch()
+	 * uses an exclusive lock of this mutex to guarantee that no
+	 * callbacks of the just unregistered watch are pending
+	 * before returning to its caller.
+	 */
+	struct sx xenwatch_mutex;
+
+	/**
+	 * The HVM guest pseudo-physical frame number.  This is Xen's mapping
+	 * of the true machine frame number into our "physical address space".
+	 */
+	unsigned long gpfn;
+
+	/**
+	 * The event channel for communicating with the
+	 * XenStore service.
+	 */
+	int evtchn;
+
+	/** Handle for XenStore interrupts. */
+	xen_intr_handle_t xen_intr_handle;
+
+	/**
+	 * Interrupt driven config hook allowing us to defer
+	 * attaching children until interrupts (and thus communication
+	 * with the XenStore service) are available.
+	 */
+	struct intr_config_hook xs_attachcb;
+};
+
+/*-------------------------------- Global Data ------------------------------*/
+static struct xs_softc xs;
+
+/*------------------------- Private Utility Functions -----------------------*/
+
+/**
+ * Count and optionally record pointers to a number of NUL terminated
+ * strings in a buffer.
+ *
+ * \param strings  A pointer to a contiguous buffer of NUL terminated strings.
+ * \param dest	   An array to store pointers to each string found in strings.
+ * \param len	   The length of the buffer pointed to by strings.
+ *
+ * \return  A count of the number of strings found.
+ */
+static u_int
+extract_strings(const char *strings, const char **dest, u_int len)
+{
+	u_int num;
+	const char *p;
+
+	for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) {
+		if (dest != NULL)
+			*dest++ = p;
+		num++;
+	}
+
+	return (num);
+}
+
+/**
+ * Convert a contiguous buffer containing a series of NUL terminated
+ * strings into an array of pointers to strings.
+ *
+ * The returned pointer references the array of string pointers which
+ * is followed by the storage for the string data.  It is the client's
+ * responsibility to free this storage.
+ *
+ * The storage addressed by strings is free'd prior to split returning.
+ *
+ * \param strings  A pointer to a contiguous buffer of NUL terminated strings.
+ * \param len	   The length of the buffer pointed to by strings.
+ * \param num	   The number of strings found and returned in the strings
+ *                 array.
+ *
+ * \return  An array of pointers to the strings found in the input buffer.
+ */
+static const char **
+split(char *strings, u_int len, u_int *num)
+{
+	const char **ret;
+
+	/* Protect against unterminated buffers. */
+	if (len > 0)
+		strings[len - 1] = '\0';
+
+	/* Count the strings. */
+	*num = extract_strings(strings, /*dest*/NULL, len);
+
+	/* Transfer to one big alloc for easy freeing by the caller. */
+	ret = malloc(*num * sizeof(char *) + len, M_XENSTORE, M_WAITOK);
+	memcpy(&ret[*num], strings, len);
+	free(strings, M_XENSTORE);
+
+	/* Extract pointers to newly allocated array. */
+	strings = (char *)&ret[*num];
+	(void)extract_strings(strings, /*dest*/ret, len);
+
+	return (ret);
+}
+
+/*------------------------- Public Utility Functions -------------------------*/
+/*------- API comments for these methods can be found in xenstorevar.h -------*/
+struct sbuf *
+xs_join(const char *dir, const char *name)
+{
+	struct sbuf *sb;
+
+	sb = sbuf_new_auto();
+	sbuf_cat(sb, dir);
+	if (name[0] != '\0') {
+		sbuf_putc(sb, '/');
+		sbuf_cat(sb, name);
+	}
+	sbuf_finish(sb);
+
+	return (sb);
+}
+
+/*-------------------- Low Level Communication Management --------------------*/
+/**
+ * Interrupt handler for the XenStore event channel.
+ *
+ * XenStore reads and writes block on "xen_store" for buffer
+ * space.  Wakeup any blocking operations when the XenStore
+ * service has modified the queues.
+ */
+static void
+xs_intr(void * arg __unused /*__attribute__((unused))*/)
+{
+
+	/*
+	 * Hold ring lock across wakeup so that clients
+	 * cannot miss a wakeup.
+	 */
+	mtx_lock(&xs.ring_lock);
+	wakeup(xen_store);
+	mtx_unlock(&xs.ring_lock);
+}
+
+/**
+ * Verify that the indexes for a ring are valid.
+ *
+ * The difference between the producer and consumer cannot
+ * exceed the size of the ring.
+ *
+ * \param cons  The consumer index for the ring to test.
+ * \param prod  The producer index for the ring to test.
+ *
+ * \retval 1  If indexes are in range.
+ * \retval 0  If the indexes are out of range.
+ */
+static int
+xs_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+
+	return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+/**
+ * Return a pointer to, and the length of, the contiguous
+ * free region available for output in a ring buffer.
+ *
+ * \param cons  The consumer index for the ring.
+ * \param prod  The producer index for the ring.
+ * \param buf   The base address of the ring's storage.
+ * \param len   The amount of contiguous storage available.
+ *
+ * \return  A pointer to the start location of the free region.
+ */
+static void *
+xs_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
+    char *buf, uint32_t *len)
+{
+
+	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+		*len = XENSTORE_RING_SIZE - (prod - cons);
+	return (buf + MASK_XENSTORE_IDX(prod));
+}
+
+/**
+ * Return a pointer to, and the length of, the contiguous
+ * data available to read from a ring buffer.
+ *
+ * \param cons  The consumer index for the ring.
+ * \param prod  The producer index for the ring.
+ * \param buf   The base address of the ring's storage.
+ * \param len   The amount of contiguous data available to read.
+ *
+ * \return  A pointer to the start location of the available data.
+ */
+static const void *
+xs_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
+    const char *buf, uint32_t *len)
+{
+
+	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+	if ((prod - cons) < *len)
+		*len = prod - cons;
+	return (buf + MASK_XENSTORE_IDX(cons));
+}
+
+/**
+ * Transmit data to the XenStore service.
+ *
+ * \param tdata  A pointer to the contiguous data to send.
+ * \param len    The amount of data to send.
+ *
+ * \return  On success 0, otherwise an errno value indicating the
+ *          cause of failure.
+ *
+ * \invariant  Called from thread context.
+ * \invariant  The buffer pointed to by tdata is at least len bytes
+ *             in length.
+ * \invariant  xs.request_mutex exclusively locked.
+ */
+static int
+xs_write_store(const void *tdata, unsigned len)
+{
+	XENSTORE_RING_IDX cons, prod;
+	const char *data = (const char *)tdata;
+	int error;
+
+	sx_assert(&xs.request_mutex, SX_XLOCKED);
+	while (len != 0) {
+		void *dst;
+		u_int avail;
+
+		/* Hold lock so we can't miss wakeups should we block. */
+		mtx_lock(&xs.ring_lock);
+		cons = xen_store->req_cons;
+		prod = xen_store->req_prod;
+		if ((prod - cons) == XENSTORE_RING_SIZE) {
+			/*
+			 * Output ring is full. Wait for a ring event.
+			 *
+			 * Note that the events from both queues
+			 * are combined, so being woken does not
+			 * guarantee that data exist in the read
+			 * ring.
+			 *
+			 * To simplify error recovery and the retry,
+			 * we specify PDROP so our lock is *not* held
+			 * when msleep returns.
+			 */
+			error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP,
+			     "xbwrite", /*timeout*/0);
+			if (error && error != EWOULDBLOCK)
+				return (error);
+
+			/* Try again. */
+			continue;
+		}
+		mtx_unlock(&xs.ring_lock);
+
+		/* Verify queue sanity. */
+		if (!xs_check_indexes(cons, prod)) {
+			xen_store->req_cons = xen_store->req_prod = 0;
+			return (EIO);
+		}
+
+		dst = xs_get_output_chunk(cons, prod, xen_store->req, &avail);
+		if (avail > len)
+			avail = len;
+
+		memcpy(dst, data, avail);
+		data += avail;
+		len -= avail;
+
+		/*
+		 * The store to the producer index, which indicates
+		 * to the other side that new data has arrived, must
+		 * be visible only after our copy of the data into the
+		 * ring has completed.
+		 */
+		wmb();
+		xen_store->req_prod += avail;
+
+		/*
+		 * xen_intr_signal() implies mb(). The other side will see
+		 * the change to req_prod at the time of the interrupt.
+		 */
+		xen_intr_signal(xs.xen_intr_handle);
+	}
+
+	return (0);
+}
+
+/**
+ * Receive data from the XenStore service.
+ *
+ * \param tdata  A pointer to the contiguous buffer to receive the data.
+ * \param len    The amount of data to receive.
+ *
+ * \return  On success 0, otherwise an errno value indicating the
+ *          cause of failure.
+ *
+ * \invariant  Called from thread context.
+ * \invariant  The buffer pointed to by tdata is at least len bytes
+ *             in length.
+ *
+ * \note xs_read does not perform any internal locking to guarantee
+ *       serial access to the incoming ring buffer.  However, there
+ *	 is only one context processing reads: xs_rcv_thread().
+ */
+static int
+xs_read_store(void *tdata, unsigned len)
+{
+	XENSTORE_RING_IDX cons, prod;
+	char *data = (char *)tdata;
+	int error;
+
+	while (len != 0) {
+		u_int avail;
+		const char *src;
+
+		/* Hold lock so we can't miss wakeups should we block. */
+		mtx_lock(&xs.ring_lock);
+		cons = xen_store->rsp_cons;
+		prod = xen_store->rsp_prod;
+		if (cons == prod) {
+			/*
+			 * Nothing to read. Wait for a ring event.
+			 *
+			 * Note that the events from both queues
+			 * are combined, so being woken does not
+			 * guarantee that data exist in the read
+			 * ring.
+			 *
+			 * To simplify error recovery and the retry,
+			 * we specify PDROP so our lock is *not* held
+			 * when msleep returns.
+			 */
+			error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP,
+			    "xbread", /*timeout*/0);
+			if (error && error != EWOULDBLOCK)
+				return (error);
+			continue;
+		}
+		mtx_unlock(&xs.ring_lock);
+
+		/* Verify queue sanity. */
+		if (!xs_check_indexes(cons, prod)) {
+			xen_store->rsp_cons = xen_store->rsp_prod = 0;
+			return (EIO);
+		}
+
+		src = xs_get_input_chunk(cons, prod, xen_store->rsp, &avail);
+		if (avail > len)
+			avail = len;
+
+		/*
+		 * Insure the data we read is related to the indexes
+		 * we read above.
+		 */
+		rmb();
+
+		memcpy(data, src, avail);
+		data += avail;
+		len -= avail;
+
+		/*
+		 * Insure that the producer of this ring does not see
+		 * the ring space as free until after we have copied it
+		 * out.
+		 */
+		mb();
+		xen_store->rsp_cons += avail;
+
+		/*
+		 * xen_intr_signal() implies mb(). The producer will see
+		 * the updated consumer index when the event is delivered.
+		 */
+		xen_intr_signal(xs.xen_intr_handle);
+	}
+
+	return (0);
+}
+
+/*----------------------- Received Message Processing ------------------------*/
+/**
+ * Block reading the next message from the XenStore service and
+ * process the result.
+ *
+ * \param type  The returned type of the XenStore message received.
+ *
+ * \return  0 on success.  Otherwise an errno value indicating the
+ *          type of failure encountered.
+ */
+static int
+xs_process_msg(enum xsd_sockmsg_type *type)
+{
+	struct xs_stored_msg *msg;
+	char *body;
+	int error;
+
+	msg = malloc(sizeof(*msg), M_XENSTORE, M_WAITOK);
+	error = xs_read_store(&msg->hdr, sizeof(msg->hdr));
+	if (error) {
+		free(msg, M_XENSTORE);
+		return (error);
+	}
+
+	body = malloc(msg->hdr.len + 1, M_XENSTORE, M_WAITOK);
+	error = xs_read_store(body, msg->hdr.len);
+	if (error) {
+		free(body, M_XENSTORE);
+		free(msg, M_XENSTORE);
+		return (error);
+	}
+	body[msg->hdr.len] = '\0';
+
+	*type = msg->hdr.type;
+	if (msg->hdr.type == XS_WATCH_EVENT) {
+		msg->u.watch.vec = split(body, msg->hdr.len,
+		    &msg->u.watch.vec_size);
+
+		mtx_lock(&xs.registered_watches_lock);
+		msg->u.watch.handle = find_watch(
+		    msg->u.watch.vec[XS_WATCH_TOKEN]);
+		if (msg->u.watch.handle != NULL) {
+			mtx_lock(&xs.watch_events_lock);
+			TAILQ_INSERT_TAIL(&xs.watch_events, msg, list);
+			wakeup(&xs.watch_events);
+			mtx_unlock(&xs.watch_events_lock);
+		} else {
+			free(msg->u.watch.vec, M_XENSTORE);
+			free(msg, M_XENSTORE);
+		}
+		mtx_unlock(&xs.registered_watches_lock);
+	} else {
+		msg->u.reply.body = body;
+		mtx_lock(&xs.reply_lock);
+		TAILQ_INSERT_TAIL(&xs.reply_list, msg, list);
+		wakeup(&xs.reply_list);
+		mtx_unlock(&xs.reply_lock);
+	}
+
+	return (0);
+}
+
+/**
+ * Thread body of the XenStore receive thread.
+ *
+ * This thread blocks waiting for data from the XenStore service
+ * and processes and received messages.
+ */
+static void
+xs_rcv_thread(void *arg __unused)
+{
+	int error;
+	enum xsd_sockmsg_type type;
+
+	for (;;) {
+		error = xs_process_msg(&type);
+		if (error)
+			printf("XENSTORE error %d while reading message\n",
+			    error);
+	}
+}
+
+/*---------------- XenStore Message Request/Reply Processing -----------------*/
+/**
+ * Filter invoked before transmitting any message to the XenStore service.
+ *
+ * The role of the filter may expand, but currently serves to manage
+ * the interactions of messages with transaction state.
+ *
+ * \param request_msg_type  The message type for the request.
+ */
+static inline void
+xs_request_filter(uint32_t request_msg_type)
+{
+	if (request_msg_type == XS_TRANSACTION_START)
+		sx_slock(&xs.suspend_mutex);
+}
+
+/**
+ * Filter invoked after transmitting any message to the XenStore service.
+ *
+ * The role of the filter may expand, but currently serves to manage
+ * the interactions of messages with transaction state.
+ *
+ * \param request_msg_type     The message type for the original request.
+ * \param reply_msg_type       The message type for any received reply.
+ * \param request_reply_error  The error status from the attempt to send
+ *                             the request or retrieve the reply.
+ */
+static inline void
+xs_reply_filter(uint32_t request_msg_type,
+    uint32_t reply_msg_type, int request_reply_error)
+{
+	/*
+	 * The count of transactions drops if we attempted
+	 * to end a transaction (even if that attempt fails
+	 * in error), we receive a transaction end acknowledgement,
+	 * or if our attempt to begin a transaction fails.
+	 */
+	if (request_msg_type == XS_TRANSACTION_END
+	 || (request_reply_error == 0 && reply_msg_type == XS_TRANSACTION_END)
+	 || (request_msg_type == XS_TRANSACTION_START
+	  && (request_reply_error != 0 || reply_msg_type == XS_ERROR)))
+		sx_sunlock(&xs.suspend_mutex);
+
+}
+
+#define xsd_error_count	(sizeof(xsd_errors) / sizeof(xsd_errors[0]))
+
+/**
+ * Convert a XenStore error string into an errno number.
+ *
+ * \param errorstring  The error string to convert.
+ *
+ * \return  The errno best matching the input string.
+ *
+ * \note Unknown error strings are converted to EINVAL.
+ */
+static int
+xs_get_error(const char *errorstring)
+{
+	u_int i;
+
+	for (i = 0; i < xsd_error_count; i++) {
+		if (!strcmp(errorstring, xsd_errors[i].errstring))
+			return (xsd_errors[i].errnum);
+	}
+	log(LOG_WARNING, "XENSTORE xen store gave: unknown error %s",
+	    errorstring);
+	return (EINVAL);
+}
+
+/**
+ * Block waiting for a reply to a message request.
+ *
+ * \param type	  The returned type of the reply.
+ * \param len	  The returned body length of the reply.
+ * \param result  The returned body of the reply.
+ *
+ * \return  0 on success.  Otherwise an errno indicating the
+ *          cause of failure.
+ */
+static int
+xs_read_reply(enum xsd_sockmsg_type *type, u_int *len, void **result)
+{
+	struct xs_stored_msg *msg;
+	char *body;
+	int error;
+
+	mtx_lock(&xs.reply_lock);
+	while (TAILQ_EMPTY(&xs.reply_list)) {
+		error = mtx_sleep(&xs.reply_list, &xs.reply_lock,
+		    PCATCH, "xswait", hz/10);
+		if (error && error != EWOULDBLOCK) {
+			mtx_unlock(&xs.reply_lock);
+			return (error);
+		}
+	}
+	msg = TAILQ_FIRST(&xs.reply_list);
+	TAILQ_REMOVE(&xs.reply_list, msg, list);
+	mtx_unlock(&xs.reply_lock);
+
+	*type = msg->hdr.type;
+	if (len)
+		*len = msg->hdr.len;
+	body = msg->u.reply.body;
+
+	free(msg, M_XENSTORE);
+	*result = body;
+	return (0);
+}
+
+/**
+ * Pass-thru interface for XenStore access by userland processes
+ * via the XenStore device.
+ *
+ * Reply type and length data are returned by overwriting these
+ * fields in the passed in request message.
+ *
+ * \param msg	  A properly formatted message to transmit to
+ *		  the XenStore service.
+ * \param result  The returned body of the reply.
+ *
+ * \return  0 on success.  Otherwise an errno indicating the cause
+ *          of failure.
+ *
+ * \note The returned result is provided in malloced storage and thus
+ *       must be free'd by the caller with 'free(result, M_XENSTORE);
+ */
+int
+xs_dev_request_and_reply(struct xsd_sockmsg *msg, void **result)
+{
+	uint32_t request_type;
+	int error;
+
+	request_type = msg->type;
+	xs_request_filter(request_type);
+
+	sx_xlock(&xs.request_mutex);
+	if ((error = xs_write_store(msg, sizeof(*msg) + msg->len)) == 0)
+		error = xs_read_reply(&msg->type, &msg->len, result);
+	sx_xunlock(&xs.request_mutex);
+
+	xs_reply_filter(request_type, msg->type, error);
+
+	return (error);
+}
+
+/**
+ * Send a message with an optionally muti-part body to the XenStore service.
+ *
+ * \param t              The transaction to use for this request.
+ * \param request_type   The type of message to send.
+ * \param iovec          Pointers to the body sections of the request.
+ * \param num_vecs       The number of body sections in the request.
+ * \param len            The returned length of the reply.
+ * \param result         The returned body of the reply.
+ *
+ * \return  0 on success.  Otherwise an errno indicating
+ *          the cause of failure.
+ *
+ * \note The returned result is provided in malloced storage and thus
+ *       must be free'd by the caller with 'free(*result, M_XENSTORE);
+ */
+static int
+xs_talkv(struct xs_transaction t, enum xsd_sockmsg_type request_type,
+    const struct iovec *iovec, u_int num_vecs, u_int *len, void **result)
+{
+	struct xsd_sockmsg msg;
+	void *ret = NULL;
+	u_int i;
+	int error;
+
+	msg.tx_id = t.id;
+	msg.req_id = 0;
+	msg.type = request_type;
+	msg.len = 0;
+	for (i = 0; i < num_vecs; i++)
+		msg.len += iovec[i].iov_len;
+
+	xs_request_filter(request_type);
+
+	sx_xlock(&xs.request_mutex);
+	error = xs_write_store(&msg, sizeof(msg));
+	if (error) {
+		printf("xs_talkv failed %d\n", error);
+		goto error_lock_held;
+	}
+
+	for (i = 0; i < num_vecs; i++) {
+		error = xs_write_store(iovec[i].iov_base, iovec[i].iov_len);
+		if (error) {
+			printf("xs_talkv failed %d\n", error);
+			goto error_lock_held;
+		}
+	}
+
+	error = xs_read_reply(&msg.type, len, &ret);
+
+error_lock_held:
+	sx_xunlock(&xs.request_mutex);
+	xs_reply_filter(request_type, msg.type, error);
+	if (error)
+		return (error);
+
+	if (msg.type == XS_ERROR) {
+		error = xs_get_error(ret);
+		free(ret, M_XENSTORE);
+		return (error);
+	}
+
+	/* Reply is either error or an echo of our request message type. */
+	KASSERT(msg.type == request_type, ("bad xenstore message type"));
+
+	if (result)
+		*result = ret;
+	else
+		free(ret, M_XENSTORE);
+
+	return (0);
+}
+
+/**
+ * Wrapper for xs_talkv allowing easy transmission of a message with
+ * a single, contiguous, message body.
+ *
+ * \param t              The transaction to use for this request.
+ * \param request_type   The type of message to send.
+ * \param body           The body of the request.
+ * \param len            The returned length of the reply.
+ * \param result         The returned body of the reply.
+ *
+ * \return  0 on success.  Otherwise an errno indicating
+ *          the cause of failure.
+ *
+ * \note The returned result is provided in malloced storage and thus
+ *       must be free'd by the caller with 'free(*result, M_XENSTORE);
+ */
+static int
+xs_single(struct xs_transaction t, enum xsd_sockmsg_type request_type,
+    const char *body, u_int *len, void **result)
+{
+	struct iovec iovec;
+
+	iovec.iov_base = (void *)(uintptr_t)body;
+	iovec.iov_len = strlen(body) + 1;
+
+	return (xs_talkv(t, request_type, &iovec, 1, len, result));
+}
+
+/*------------------------- XenStore Watch Support ---------------------------*/
+/**
+ * Transmit a watch request to the XenStore service.
+ *
+ * \param path    The path in the XenStore to watch.
+ * \param tocken  A unique identifier for this watch.
+ *
+ * \return  0 on success.  Otherwise an errno indicating the
+ *          cause of failure.
+ */
+static int
+xs_watch(const char *path, const char *token)
+{
+	struct iovec iov[2];
+
+	iov[0].iov_base = (void *)(uintptr_t) path;
+	iov[0].iov_len = strlen(path) + 1;
+	iov[1].iov_base = (void *)(uintptr_t) token;
+	iov[1].iov_len = strlen(token) + 1;
+
+	return (xs_talkv(XST_NIL, XS_WATCH, iov, 2, NULL, NULL));
+}
+
+/**
+ * Transmit an uwatch request to the XenStore service.
+ *
+ * \param path    The path in the XenStore to watch.
+ * \param tocken  A unique identifier for this watch.
+ *
+ * \return  0 on success.  Otherwise an errno indicating the
+ *          cause of failure.
+ */
+static int
+xs_unwatch(const char *path, const char *token)
+{
+	struct iovec iov[2];
+
+	iov[0].iov_base = (void *)(uintptr_t) path;
+	iov[0].iov_len = strlen(path) + 1;
+	iov[1].iov_base = (void *)(uintptr_t) token;
+	iov[1].iov_len = strlen(token) + 1;
+
+	return (xs_talkv(XST_NIL, XS_UNWATCH, iov, 2, NULL, NULL));
+}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409301714.s8UHECCa007289>