xenbus_xs.c revision fc621ef0ea706feeefe877e29c056b46fd3915b4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
*
* This is the kernel equivalent of the "xs" library. We don't need everything
* and we use xenbus_comms for communication.
*
* 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,
* 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.
*/
/*
* NOTE: To future maintainers of the Solaris version of this file:
* I found the Linux version of this code to be very disgusting in
* overloading pointers and error codes into void * return values.
* The main difference you will find is that all such usage is changed
* to pass pointers to void* to be filled in with return values and
* the functions return error codes.
*/
#include <sys/sysmacros.h>
#include <sys/mach_mmu.h>
#define _XSD_ERRORS_DEFINED
#ifdef XPV_HVM_DRIVER
#include <sys/xpv_support.h>
#endif
#include <sys/hypervisor.h>
struct xs_stored_msg {
struct xsd_sockmsg hdr;
union {
/* Queued replies. */
struct {
char *body;
} reply;
/* Queued watch events. */
struct {
struct xenbus_watch *handle;
char **vec;
unsigned int vec_size;
} watch;
} un;
};
static struct xs_handle {
/* A list of replies. Currently only one will ever be outstanding. */
/* One request at a time. */
} xs_state;
static int last_req_id;
/*
* List of clients wanting a xenstore up notification, and a lock to protect it
*/
static boolean_t xenstore_up;
static list_t notify_list;
static kmutex_t notify_list_lock;
static taskq_t *xenbus_taskq;
/* List of registered watches, and a lock to protect it. */
static kmutex_t watches_lock;
/* List of pending watch callback events, and a lock to protect it. */
static list_t watch_events;
static kmutex_t watch_events_lock;
/*
* Details of the xenwatch callback kernel thread. The thread waits on the
* watch_events_cv for work to do (queued on watch_events list). When it
* wakes up it acquires the xenwatch_mutex before reading the list and
* carrying out work.
*/
static kmutex_t xenwatch_mutex;
static kcondvar_t watch_events_cv;
static int process_msg(void);
static int
get_error(const char *errorstring)
{
unsigned int i;
"XENBUS xen store gave: unknown error %s",
return (EINVAL);
}
}
return (xsd_errors[i].errnum);
}
/*
* Read a synchronous reply from xenstore. Since we can return early before
* reading a relevant reply, we discard any messages not matching the request
* ID. Caller must free returned message on success.
*/
static int
{
extern int do_polled_io;
for (;;) {
if (interrupts_unleashed && !do_polled_io) {
&xs_state.reply_lock) == 0) {
return (EINTR);
}
} else { /* polled mode needed for early probes */
(void) HYPERVISOR_yield();
(void) process_msg();
}
}
break;
}
return (0);
}
/* Emergency write. */
void
{
struct xsd_sockmsg msg = { 0 };
}
/*
* This is pretty unpleasant. First off, there's the horrible logic around
* suspend_lock and transactions. Also, we can be interrupted either before we
* write a message, or before we receive a reply. A client that wants to
* survive this can't know which case happened. Luckily all clients don't care
* about signals currently, and the alternative (a hard wait on a userspace
* daemon) isn't exactly preferable. Caller must free 'reply' on success.
*/
int
{
int err;
if (err) {
goto out;
}
if (err) {
goto out;
}
out:
return (err);
}
/*
* Send message to xs, return errcode, rval filled in with pointer
* to kmem_alloc'ed reply.
*/
static int
enum xsd_sockmsg_type type,
unsigned int num_vecs,
void **rval,
unsigned int *len)
{
struct xsd_sockmsg msg;
struct xs_stored_msg *reply_msg;
char *reply;
unsigned int i;
int err;
for (i = 0; i < num_vecs; i++)
if (err) {
return (err);
}
for (i = 0; i < num_vecs; i++) {
if (err) {
return (err);
}
}
if (err)
return (err);
goto out;
}
else
out:
return (err);
}
/* Simplified version of xs_talkv: single message. */
static int
enum xsd_sockmsg_type type,
unsigned int *len)
{
}
static unsigned int
{
unsigned int num;
const char *p;
num++;
return (num);
}
/* Return the path to dir with /name appended. Buffer must be kmem_free()'ed */
static char *
{
char *buffer;
KM_SLEEP);
if (slashlen != 0) {
}
return (buffer);
}
static char **
{
char *p, **ret;
/* Count the strings. */
return (NULL);
/* Transfer to one big alloc for easy freeing. */
p += strlen(p) + 1) {
}
return (ret);
}
char **
{
unsigned int len;
int err;
/* sigh, we lose error code info here */
*num = 0;
return (NULL);
}
}
/* Check if a path exists. */
{
void *p;
uint_t n;
return (B_FALSE);
kmem_free(p, n);
return (B_TRUE);
}
/* Check if a directory path exists. */
{
char **d;
unsigned int dir_n;
int i, len;
if (d == NULL)
return (B_FALSE);
return (B_TRUE);
}
/*
* Get the value of a single file.
* Returns a kmem_alloced value in retp: call kmem_free() on it after use.
* len indicates length in bytes.
*/
int
{
char *path;
int err;
return (err);
}
int
{
uint_t n;
int err;
char *str;
/*
* Since we access the xenbus value immediatly we can't be
* part of a transaction.
*/
return (err);
/*
* Why bother with this? Because xenbus is truly annoying in the
* fact that when it returns a string, it doesn't guarantee that
* the memory that holds the string is of size strlen() + 1.
* This forces callers to keep track of the size of the memory
* containing the string. Ugh. We'll work around this by
* re-allocate strings to always be of size strlen() + 1.
*/
return (0);
}
/*
* Write the value of a single file.
* Returns err on failure.
*/
int
{
char *path;
int ret;
return (ret);
}
/* Create a new directory. */
int
{
char *path;
int ret;
return (ret);
}
/* Destroy a file or directory (directories must be empty). */
int
{
char *path;
int ret;
return (ret);
}
/*
* Start a transaction: changes by others will not be seen during this
* transaction, and changes will not be visible to others until end.
*/
int
{
void *id_str;
unsigned long id;
int err;
unsigned int len;
if (err) {
return (err);
}
*t = (xenbus_transaction_t)id;
return (0);
}
/*
* End a transaction.
* If abandon is true, transaction is discarded instead of committed.
*/
int
{
char abortstr[2];
int err;
if (abort)
else
return (err);
}
/*
* Single read and scanf: returns errno or 0. This can only handle a single
* conversion specifier.
*/
/* SCANFLIKE4 */
int
{
int ret;
char *val;
unsigned int len;
if (ret)
return (ret);
return (ret);
}
/* Single printf and write: returns errno or 0. */
/* PRINTFLIKE4 */
int
{
int ret;
#define PRINTF_BUFFER_SIZE 4096
char *printf_buffer;
return (ret);
}
/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
int
{
const char *name;
int ret = 0;
unsigned int len;
char *p;
if (ret)
break;
if (fmt) {
} else
*(char **)result = p;
}
return (ret);
}
static int
{
}
static int
{
}
static struct xenbus_watch *
find_watch(const char *token)
{
struct xenbus_watch *i, *cmp;
if (i == cmp)
break;
return (i);
}
/* Register a xenstore state notify callback */
int
xs_register_xenbus_callback(void (*callback)(int))
{
/*
* Make sure not already on the list
*/
return (EEXIST);
}
}
done:
if (xenstore_up)
return (0);
}
/*
* Notify clients of xenstore state
*/
static void
do_notify_callbacks(void *arg)
{
struct xenbus_notify *xnp;
}
}
void
xs_notify_xenstore_up(void)
{
(void *)XENSTORE_UP, 0);
}
void
xs_notify_xenstore_down(void)
{
(void *)XENSTORE_DOWN, 0);
}
/* Register callback to watch this node. */
int
{
/* Pointer in ascii is the token. */
int err;
/*
* May be re-registering a watch if xenstore daemon was restarted
*/
/* Ignore errors due to multiple registration. */
}
return (err);
}
static void
{
int i, len = 0;
}
void
{
struct xs_stored_msg *msg;
int err;
if (err)
/* Cancel pending watch events. */
}
}
/* Flush any currently-executing callback, unless we are it. :-) */
}
}
void
xenbus_suspend(void)
{
xb_suspend();
}
void
xenbus_resume(void)
{
struct xenbus_watch *watch;
xb_init();
/* No need for watches_lock: the suspend_lock is sufficient. */
}
}
static void
xenwatch_thread(void)
{
struct xs_stored_msg *msg;
struct xenbus_watch *watch;
for (;;) {
while (list_empty(&watch_events))
struct xenbus_watch *, watch,
}
}
static int
process_msg(void)
{
struct xs_stored_msg *msg;
char *body;
if (err) {
return (err);
}
if (err) {
return (err);
}
const char *token;
return (EIO);
}
} else {
}
} else {
}
return (0);
}
static void
xenbus_thread(void)
{
int err;
/*
* We have to wait for interrupts to be ready, so we don't clash
* with the polled-IO code in read_reply().
*/
while (!interrupts_unleashed)
delay(10);
for (;;) {
err = process_msg();
if (err)
"message", err);
}
}
/*
* When setting up xenbus, dom0 and domU have to take different paths, which
* makes this code a little confusing. For dom0:
*
* xs_early_init - mutex init only
* xs_dom0_init - called on xenbus dev attach: set up our xenstore page and
* event channel; start xenbus threads for responding to interrupts.
*
* And for domU:
*
* xs_early_init - mutex init; set up our xenstore page and event channel
* xs_domu_init - installation of IRQ handler; start xenbus threads.
*
* We need an early init on domU so we can use xenbus in polled mode to
* discover devices, VCPUs etc.
*
* On resume, we use xb_init() and xb_setup_intr() to restore xenbus to a
* working state.
*/
void
xs_early_init(void)
{
if (DOMAIN_IS_INITDOMAIN(xen_info))
return;
xb_init();
}
static void
xs_thread_init(void)
{
}
void
xs_domu_init(void)
{
if (DOMAIN_IS_INITDOMAIN(xen_info))
return;
/*
* Add interrupt handler for xenbus now, must wait till after
* psm module is loaded. All use of xenbus is in polled mode
* until xs_init is called since it is what kicks off the xs
* server threads.
*/
}
void
xs_dom0_init(void)
{
/*
* The xenbus driver might be re-attaching.
*/
if (initialized)
return;
xb_init();
}