diff options
author | royger <royger@FreeBSD.org> | 2014-09-30 17:14:11 +0000 |
---|---|---|
committer | royger <royger@FreeBSD.org> | 2014-09-30 17:14:11 +0000 |
commit | 3083772f7f1859248cdadd3ca0cf89b7a7a3ed37 (patch) | |
tree | 57b418e0a7d85e5802b3bd7f72e864df3eb1a377 /sys/xen | |
parent | 195a2023ff22d315b4966d321acb76d0d3c1972a (diff) | |
download | FreeBSD-src-3083772f7f1859248cdadd3ca0cf89b7a7a3ed37.zip FreeBSD-src-3083772f7f1859248cdadd3ca0cf89b7a7a3ed37.tar.gz |
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
Diffstat (limited to 'sys/xen')
-rw-r--r-- | sys/xen/xenstore/xenstore.c | 1640 | ||||
-rw-r--r-- | sys/xen/xenstore/xenstore_dev.c | 224 |
2 files changed, 0 insertions, 1864 deletions
diff --git a/sys/xen/xenstore/xenstore.c b/sys/xen/xenstore/xenstore.c deleted file mode 100644 index f7425da..0000000 --- a/sys/xen/xenstore/xenstore.c +++ /dev/null @@ -1,1640 +0,0 @@ -/****************************************************************************** - * 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)); -} - -/** - * Convert from watch token (unique identifier) to the associated - * internal tracking structure for this watch. - * - * \param tocken The unique identifier for the watch to find. - * - * \return A pointer to the found watch structure or NULL. - */ -static struct xs_watch * -find_watch(const char *token) -{ - struct xs_watch *i, *cmp; - - cmp = (void *)strtoul(token, NULL, 16); - - LIST_FOREACH(i, &xs.registered_watches, list) - if (i == cmp) - return (i); - - return (NULL); -} - -/** - * Thread body of the XenStore watch event dispatch thread. - */ -static void -xenwatch_thread(void *unused) -{ - struct xs_stored_msg *msg; - - for (;;) { - - mtx_lock(&xs.watch_events_lock); - while (TAILQ_EMPTY(&xs.watch_events)) - mtx_sleep(&xs.watch_events, - &xs.watch_events_lock, - PWAIT | PCATCH, "waitev", hz/10); - - mtx_unlock(&xs.watch_events_lock); - sx_xlock(&xs.xenwatch_mutex); - - mtx_lock(&xs.watch_events_lock); - msg = TAILQ_FIRST(&xs.watch_events); - if (msg) - TAILQ_REMOVE(&xs.watch_events, msg, list); - mtx_unlock(&xs.watch_events_lock); - - if (msg != NULL) { - /* - * XXX There are messages coming in with a NULL - * XXX callback. This deserves further investigation; - * XXX the workaround here simply prevents the kernel - * XXX from panic'ing on startup. - */ - if (msg->u.watch.handle->callback != NULL) - msg->u.watch.handle->callback( - msg->u.watch.handle, - (const char **)msg->u.watch.vec, - msg->u.watch.vec_size); - free(msg->u.watch.vec, M_XENSTORE); - free(msg, M_XENSTORE); - } - - sx_xunlock(&xs.xenwatch_mutex); - } -} - -/*----------- XenStore Configuration, Initialization, and Control ------------*/ -/** - * Setup communication channels with the XenStore service. - * - * \return On success, 0. Otherwise an errno value indicating the - * type of failure. - */ -static int -xs_init_comms(void) -{ - int error; - - if (xen_store->rsp_prod != xen_store->rsp_cons) { - log(LOG_WARNING, "XENSTORE response ring is not quiescent " - "(%08x:%08x): fixing up\n", - xen_store->rsp_cons, xen_store->rsp_prod); - xen_store->rsp_cons = xen_store->rsp_prod; - } - - xen_intr_unbind(&xs.xen_intr_handle); - - error = xen_intr_bind_local_port(xs.xs_dev, xs.evtchn, - /*filter*/NULL, xs_intr, /*arg*/NULL, INTR_TYPE_NET|INTR_MPSAFE, - &xs.xen_intr_handle); - if (error) { - log(LOG_WARNING, "XENSTORE request irq failed %i\n", error); - return (error); - } - - return (0); -} - -/*------------------ Private Device Attachment Functions --------------------*/ -static void -xs_identify(driver_t *driver, device_t parent) -{ - - BUS_ADD_CHILD(parent, 0, "xenstore", 0); -} - -/** - * Probe for the existance of the XenStore. - * - * \param dev - */ -static int -xs_probe(device_t dev) -{ - /* - * We are either operating within a PV kernel or being probed - * as the child of the successfully attached xenpci device. - * Thus we are in a Xen environment and there will be a XenStore. - * Unconditionally return success. - */ - device_set_desc(dev, "XenStore"); - return (0); -} - -static void -xs_attach_deferred(void *arg) -{ - xs_dev_init(); - - bus_generic_probe(xs.xs_dev); - bus_generic_attach(xs.xs_dev); - - config_intrhook_disestablish(&xs.xs_attachcb); -} - -/** - * Attach to the XenStore. - * - * This routine also prepares for the probe/attach of drivers that rely - * on the XenStore. - */ -static int -xs_attach(device_t dev) -{ - int error; - - /* Allow us to get device_t from softc and vice-versa. */ - xs.xs_dev = dev; - device_set_softc(dev, &xs); - - /* Initialize the interface to xenstore. */ - struct proc *p; - - if (xen_hvm_domain()) { - xs.evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); - xs.gpfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); - xen_store = pmap_mapdev(xs.gpfn * PAGE_SIZE, PAGE_SIZE); - } else if (xen_pv_domain()) { - xs.evtchn = HYPERVISOR_start_info->store_evtchn; - } else { - panic("Unknown domain type, cannot initialize xenstore."); - } - - TAILQ_INIT(&xs.reply_list); - TAILQ_INIT(&xs.watch_events); - - mtx_init(&xs.ring_lock, "ring lock", NULL, MTX_DEF); - mtx_init(&xs.reply_lock, "reply lock", NULL, MTX_DEF); - sx_init(&xs.xenwatch_mutex, "xenwatch"); - sx_init(&xs.request_mutex, "xenstore request"); - sx_init(&xs.suspend_mutex, "xenstore suspend"); - mtx_init(&xs.registered_watches_lock, "watches", NULL, MTX_DEF); - mtx_init(&xs.watch_events_lock, "watch events", NULL, MTX_DEF); - - /* Initialize the shared memory rings to talk to xenstored */ - error = xs_init_comms(); - if (error) - return (error); - - error = kproc_create(xenwatch_thread, NULL, &p, RFHIGHPID, - 0, "xenwatch"); - if (error) - return (error); - xs.xenwatch_pid = p->p_pid; - - error = kproc_create(xs_rcv_thread, NULL, NULL, - RFHIGHPID, 0, "xenstore_rcv"); - - xs.xs_attachcb.ich_func = xs_attach_deferred; - xs.xs_attachcb.ich_arg = NULL; - config_intrhook_establish(&xs.xs_attachcb); - - return (error); -} - -/** - * Prepare for suspension of this VM by halting XenStore access after - * all transactions and individual requests have completed. - */ -static int -xs_suspend(device_t dev) -{ - int error; - - /* Suspend child Xen devices. */ - error = bus_generic_suspend(dev); - if (error != 0) - return (error); - - sx_xlock(&xs.suspend_mutex); - sx_xlock(&xs.request_mutex); - - return (0); -} - -/** - * Resume XenStore operations after this VM is resumed. - */ -static int -xs_resume(device_t dev __unused) -{ - struct xs_watch *watch; - char token[sizeof(watch) * 2 + 1]; - - xs_init_comms(); - - sx_xunlock(&xs.request_mutex); - - /* - * No need for registered_watches_lock: the suspend_mutex - * is sufficient. - */ - LIST_FOREACH(watch, &xs.registered_watches, list) { - sprintf(token, "%lX", (long)watch); - xs_watch(watch->node, token); - } - - sx_xunlock(&xs.suspend_mutex); - - /* Resume child Xen devices. */ - bus_generic_resume(dev); - - return (0); -} - -/*-------------------- Private Device Attachment Data -----------------------*/ -static device_method_t xenstore_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, xs_identify), - DEVMETHOD(device_probe, xs_probe), - DEVMETHOD(device_attach, xs_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, xs_suspend), - DEVMETHOD(device_resume, xs_resume), - - /* Bus interface */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - - DEVMETHOD_END -}; - -DEFINE_CLASS_0(xenstore, xenstore_driver, xenstore_methods, 0); -static devclass_t xenstore_devclass; - -DRIVER_MODULE(xenstore, xenpv, xenstore_driver, xenstore_devclass, 0, 0); - -/*------------------------------- Sysctl Data --------------------------------*/ -/* XXX Shouldn't the node be somewhere else? */ -SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); -SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xs.evtchn, 0, ""); -SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, ""); - -/*-------------------------------- Public API --------------------------------*/ -/*------- API comments for these methods can be found in xenstorevar.h -------*/ -int -xs_directory(struct xs_transaction t, const char *dir, const char *node, - u_int *num, const char ***result) -{ - struct sbuf *path; - char *strings; - u_int len = 0; - int error; - - path = xs_join(dir, node); - error = xs_single(t, XS_DIRECTORY, sbuf_data(path), &len, - (void **)&strings); - sbuf_delete(path); - if (error) - return (error); - - *result = split(strings, len, num); - - return (0); -} - -int -xs_exists(struct xs_transaction t, const char *dir, const char *node) -{ - const char **d; - int error, dir_n; - - error = xs_directory(t, dir, node, &dir_n, &d); - if (error) - return (0); - free(d, M_XENSTORE); - return (1); -} - -int -xs_read(struct xs_transaction t, const char *dir, const char *node, - u_int *len, void **result) -{ - struct sbuf *path; - void *ret; - int error; - - path = xs_join(dir, node); - error = xs_single(t, XS_READ, sbuf_data(path), len, &ret); - sbuf_delete(path); - if (error) - return (error); - *result = ret; - return (0); -} - -int -xs_write(struct xs_transaction t, const char *dir, const char *node, - const char *string) -{ - struct sbuf *path; - struct iovec iovec[2]; - int error; - - path = xs_join(dir, node); - - iovec[0].iov_base = (void *)(uintptr_t) sbuf_data(path); - iovec[0].iov_len = sbuf_len(path) + 1; - iovec[1].iov_base = (void *)(uintptr_t) string; - iovec[1].iov_len = strlen(string); - - error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL); - sbuf_delete(path); - - return (error); -} - -int -xs_mkdir(struct xs_transaction t, const char *dir, const char *node) -{ - struct sbuf *path; - int ret; - - path = xs_join(dir, node); - ret = xs_single(t, XS_MKDIR, sbuf_data(path), NULL, NULL); - sbuf_delete(path); - - return (ret); -} - -int -xs_rm(struct xs_transaction t, const char *dir, const char *node) -{ - struct sbuf *path; - int ret; - - path = xs_join(dir, node); - ret = xs_single(t, XS_RM, sbuf_data(path), NULL, NULL); - sbuf_delete(path); - - return (ret); -} - -int -xs_rm_tree(struct xs_transaction xbt, const char *base, const char *node) -{ - struct xs_transaction local_xbt; - struct sbuf *root_path_sbuf; - struct sbuf *cur_path_sbuf; - char *root_path; - char *cur_path; - const char **dir; - int error; - int empty; - -retry: - root_path_sbuf = xs_join(base, node); - cur_path_sbuf = xs_join(base, node); - root_path = sbuf_data(root_path_sbuf); - cur_path = sbuf_data(cur_path_sbuf); - dir = NULL; - local_xbt.id = 0; - - if (xbt.id == 0) { - error = xs_transaction_start(&local_xbt); - if (error != 0) - goto out; - xbt = local_xbt; - } - - empty = 0; - while (1) { - u_int count; - u_int i; - - error = xs_directory(xbt, cur_path, "", &count, &dir); - if (error) - goto out; - - for (i = 0; i < count; i++) { - error = xs_rm(xbt, cur_path, dir[i]); - if (error == ENOTEMPTY) { - struct sbuf *push_dir; - - /* - * Descend to clear out this sub directory. - * We'll return to cur_dir once push_dir - * is empty. - */ - push_dir = xs_join(cur_path, dir[i]); - sbuf_delete(cur_path_sbuf); - cur_path_sbuf = push_dir; - cur_path = sbuf_data(cur_path_sbuf); - break; - } else if (error != 0) { - goto out; - } - } - - free(dir, M_XENSTORE); - dir = NULL; - - if (i == count) { - char *last_slash; - - /* Directory is empty. It is now safe to remove. */ - error = xs_rm(xbt, cur_path, ""); - if (error != 0) - goto out; - - if (!strcmp(cur_path, root_path)) - break; - - /* Return to processing the parent directory. */ - last_slash = strrchr(cur_path, '/'); - KASSERT(last_slash != NULL, - ("xs_rm_tree: mangled path %s", cur_path)); - *last_slash = '\0'; - } - } - -out: - sbuf_delete(cur_path_sbuf); - sbuf_delete(root_path_sbuf); - if (dir != NULL) - free(dir, M_XENSTORE); - - if (local_xbt.id != 0) { - int terror; - - terror = xs_transaction_end(local_xbt, /*abort*/error != 0); - xbt.id = 0; - if (terror == EAGAIN && error == 0) - goto retry; - } - return (error); -} - -int -xs_transaction_start(struct xs_transaction *t) -{ - char *id_str; - int error; - - error = xs_single(XST_NIL, XS_TRANSACTION_START, "", NULL, - (void **)&id_str); - if (error == 0) { - t->id = strtoul(id_str, NULL, 0); - free(id_str, M_XENSTORE); - } - return (error); -} - -int -xs_transaction_end(struct xs_transaction t, int abort) -{ - char abortstr[2]; - - if (abort) - strcpy(abortstr, "F"); - else - strcpy(abortstr, "T"); - - return (xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL)); -} - -int -xs_scanf(struct xs_transaction t, const char *dir, const char *node, - int *scancountp, const char *fmt, ...) -{ - va_list ap; - int error, ns; - char *val; - - error = xs_read(t, dir, node, NULL, (void **) &val); - if (error) - return (error); - - va_start(ap, fmt); - ns = vsscanf(val, fmt, ap); - va_end(ap); - free(val, M_XENSTORE); - /* Distinctive errno. */ - if (ns == 0) - return (ERANGE); - if (scancountp) - *scancountp = ns; - return (0); -} - -int -xs_vprintf(struct xs_transaction t, - const char *dir, const char *node, const char *fmt, va_list ap) -{ - struct sbuf *sb; - int error; - - sb = sbuf_new_auto(); - sbuf_vprintf(sb, fmt, ap); - sbuf_finish(sb); - error = xs_write(t, dir, node, sbuf_data(sb)); - sbuf_delete(sb); - - return (error); -} - -int -xs_printf(struct xs_transaction t, const char *dir, const char *node, - const char *fmt, ...) -{ - va_list ap; - int error; - - va_start(ap, fmt); - error = xs_vprintf(t, dir, node, fmt, ap); - va_end(ap); - - return (error); -} - -int -xs_gather(struct xs_transaction t, const char *dir, ...) -{ - va_list ap; - const char *name; - int error; - - va_start(ap, dir); - error = 0; - while (error == 0 && (name = va_arg(ap, char *)) != NULL) { - const char *fmt = va_arg(ap, char *); - void *result = va_arg(ap, void *); - char *p; - - error = xs_read(t, dir, name, NULL, (void **) &p); - if (error) - break; - - if (fmt) { - if (sscanf(p, fmt, result) == 0) - error = EINVAL; - free(p, M_XENSTORE); - } else - *(char **)result = p; - } - va_end(ap); - - return (error); -} - -int -xs_register_watch(struct xs_watch *watch) -{ - /* Pointer in ascii is the token. */ - char token[sizeof(watch) * 2 + 1]; - int error; - - sprintf(token, "%lX", (long)watch); - - sx_slock(&xs.suspend_mutex); - - mtx_lock(&xs.registered_watches_lock); - KASSERT(find_watch(token) == NULL, ("watch already registered")); - LIST_INSERT_HEAD(&xs.registered_watches, watch, list); - mtx_unlock(&xs.registered_watches_lock); - - error = xs_watch(watch->node, token); - - /* Ignore errors due to multiple registration. */ - if (error == EEXIST) - error = 0; - - if (error != 0) { - mtx_lock(&xs.registered_watches_lock); - LIST_REMOVE(watch, list); - mtx_unlock(&xs.registered_watches_lock); - } - - sx_sunlock(&xs.suspend_mutex); - - return (error); -} - -void -xs_unregister_watch(struct xs_watch *watch) -{ - struct xs_stored_msg *msg, *tmp; - char token[sizeof(watch) * 2 + 1]; - int error; - - sprintf(token, "%lX", (long)watch); - - sx_slock(&xs.suspend_mutex); - - mtx_lock(&xs.registered_watches_lock); - if (find_watch(token) == NULL) { - mtx_unlock(&xs.registered_watches_lock); - sx_sunlock(&xs.suspend_mutex); - return; - } - LIST_REMOVE(watch, list); - mtx_unlock(&xs.registered_watches_lock); - - error = xs_unwatch(watch->node, token); - if (error) - log(LOG_WARNING, "XENSTORE Failed to release watch %s: %i\n", - watch->node, error); - - sx_sunlock(&xs.suspend_mutex); - - /* Cancel pending watch events. */ - mtx_lock(&xs.watch_events_lock); - TAILQ_FOREACH_SAFE(msg, &xs.watch_events, list, tmp) { - if (msg->u.watch.handle != watch) - continue; - TAILQ_REMOVE(&xs.watch_events, msg, list); - free(msg->u.watch.vec, M_XENSTORE); - free(msg, M_XENSTORE); - } - mtx_unlock(&xs.watch_events_lock); - - /* Flush any currently-executing callback, unless we are it. :-) */ - if (curproc->p_pid != xs.xenwatch_pid) { - sx_xlock(&xs.xenwatch_mutex); - sx_xunlock(&xs.xenwatch_mutex); - } -} diff --git a/sys/xen/xenstore/xenstore_dev.c b/sys/xen/xenstore/xenstore_dev.c deleted file mode 100644 index e1b40914..0000000 --- a/sys/xen/xenstore/xenstore_dev.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * xenstore_dev.c - * - * Driver giving user-space access to the kernel's connection to the - * XenStore service. - * - * Copyright (c) 2005, Christian Limpach - * Copyright (c) 2005, Rusty Russell, IBM 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/types.h> -#include <sys/cdefs.h> -#include <sys/errno.h> -#include <sys/uio.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/conf.h> - -#include <xen/xen-os.h> - -#include <xen/hypervisor.h> -#include <xen/xenstore/xenstorevar.h> -#include <xen/xenstore/xenstore_internal.h> - -struct xs_dev_transaction { - LIST_ENTRY(xs_dev_transaction) list; - struct xs_transaction handle; -}; - -struct xs_dev_data { - /* In-progress transaction. */ - LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions; - - /* Partial request. */ - unsigned int len; - union { - struct xsd_sockmsg msg; - char buffer[PAGE_SIZE]; - } u; - - /* Response queue. */ -#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) - char read_buffer[PAGE_SIZE]; - unsigned int read_cons, read_prod; -}; - -static int -xs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) -{ - int error; - struct xs_dev_data *u = dev->si_drv1; - - while (u->read_prod == u->read_cons) { - error = tsleep(u, PCATCH, "xsdread", hz/10); - if (error && error != EWOULDBLOCK) - return (error); - } - - while (uio->uio_resid > 0) { - if (u->read_cons == u->read_prod) - break; - error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], - 1, uio); - if (error) - return (error); - u->read_cons++; - } - return (0); -} - -static void -xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len) -{ - int i; - - for (i = 0; i < len; i++, u->read_prod++) - u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; - - KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), - ("xenstore reply too big")); - - wakeup(u); -} - -static int -xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) -{ - int error; - struct xs_dev_data *u = dev->si_drv1; - struct xs_dev_transaction *trans; - void *reply; - int len = uio->uio_resid; - - if ((len + u->len) > sizeof(u->u.buffer)) - return (EINVAL); - - error = uiomove(u->u.buffer + u->len, len, uio); - if (error) - return (error); - - u->len += len; - if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) - return (0); - - switch (u->u.msg.type) { - case XS_TRANSACTION_START: - case XS_TRANSACTION_END: - case XS_DIRECTORY: - case XS_READ: - case XS_GET_PERMS: - case XS_RELEASE: - case XS_GET_DOMAIN_PATH: - case XS_WRITE: - case XS_MKDIR: - case XS_RM: - case XS_SET_PERMS: - error = xs_dev_request_and_reply(&u->u.msg, &reply); - if (!error) { - if (u->u.msg.type == XS_TRANSACTION_START) { - trans = malloc(sizeof(*trans), M_XENSTORE, - M_WAITOK); - trans->handle.id = strtoul(reply, NULL, 0); - LIST_INSERT_HEAD(&u->transactions, trans, list); - } else if (u->u.msg.type == XS_TRANSACTION_END) { - LIST_FOREACH(trans, &u->transactions, list) - if (trans->handle.id == u->u.msg.tx_id) - break; -#if 0 /* XXX does this mean the list is empty? */ - BUG_ON(&trans->list == &u->transactions); -#endif - LIST_REMOVE(trans, list); - free(trans, M_XENSTORE); - } - xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); - xs_queue_reply(u, (char *)reply, u->u.msg.len); - free(reply, M_XENSTORE); - } - break; - - default: - error = EINVAL; - break; - } - - if (error == 0) - u->len = 0; - - return (error); -} - -static int -xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - struct xs_dev_data *u; - -#if 0 /* XXX figure out if equiv needed */ - nonseekable_open(inode, filp); -#endif - u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); - LIST_INIT(&u->transactions); - dev->si_drv1 = u; - - return (0); -} - -static int -xs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) -{ - struct xs_dev_data *u = dev->si_drv1; - struct xs_dev_transaction *trans, *tmp; - - LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { - xs_transaction_end(trans->handle, 1); - LIST_REMOVE(trans, list); - free(trans, M_XENSTORE); - } - - free(u, M_XENSTORE); - return (0); -} - -static struct cdevsw xs_dev_cdevsw = { - .d_version = D_VERSION, - .d_read = xs_dev_read, - .d_write = xs_dev_write, - .d_open = xs_dev_open, - .d_close = xs_dev_close, - .d_name = "xs_dev", -}; - -void -xs_dev_init() -{ - make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, - "xen/xenstore"); -} |