2013-10-13 10:55:34 +04:00
|
|
|
/* $NetBSD: xenbus_probe.c,v 1.38 2013/10/13 06:55:34 riz Exp $ */
|
2006-03-06 23:16:33 +03:00
|
|
|
/******************************************************************************
|
|
|
|
* Talks to Xen Store to figure out what devices we have.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005 Rusty Russell, IBM Corporation
|
|
|
|
* Copyright (C) 2005 Mike Wray, Hewlett-Packard
|
|
|
|
* Copyright (C) 2005 XenSource Ltd
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
#include <sys/cdefs.h>
|
2013-10-13 10:55:34 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: xenbus_probe.c,v 1.38 2013/10/13 06:55:34 riz Exp $");
|
2006-03-06 23:21:35 +03:00
|
|
|
|
2006-03-06 23:16:33 +03:00
|
|
|
#if 0
|
|
|
|
#define DPRINTK(fmt, args...) \
|
2007-12-15 03:39:14 +03:00
|
|
|
printf("xenbus_probe (%s:%d) " fmt ".\n", __func__, __LINE__, ##args)
|
2006-03-06 23:16:33 +03:00
|
|
|
#else
|
|
|
|
#define DPRINTK(fmt, args...) ((void)0)
|
|
|
|
#endif
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/null.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/kthread.h>
|
2006-04-10 01:39:42 +04:00
|
|
|
#include <uvm/uvm.h>
|
|
|
|
|
2008-10-29 16:53:15 +03:00
|
|
|
#include <xen/xen.h> /* for xendomain_is_dom0() */
|
2007-11-22 19:16:40 +03:00
|
|
|
#include <xen/hypervisor.h>
|
|
|
|
#include <xen/xenbus.h>
|
|
|
|
#include <xen/evtchn.h>
|
|
|
|
#include <xen/shutdown_xenbus.h>
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
#include "xenbus_comms.h"
|
|
|
|
|
|
|
|
extern struct semaphore xenwatch_mutex;
|
|
|
|
|
|
|
|
#define streq(a, b) (strcmp((a), (b)) == 0)
|
|
|
|
|
2008-04-16 22:41:48 +04:00
|
|
|
static int xenbus_match(device_t, cfdata_t, void *);
|
|
|
|
static void xenbus_attach(device_t, device_t, void *);
|
2006-03-06 23:21:35 +03:00
|
|
|
static int xenbus_print(void *, const char *);
|
|
|
|
|
Merge jym-xensuspend branch in -current. ok bouyer@.
Goal: save/restore support in NetBSD domUs, for i386, i386 PAE and amd64.
Executive summary:
- split all Xen drivers (xenbus(4), grant tables, xbd(4), xennet(4))
in two parts: suspend and resume, and hook them to pmf(9).
- modify pmap so that Xen hypervisor does not cry out loud in case
it finds "unexpected" recursive memory mappings
- provide a sysctl(7), machdep.xen.suspend, to command suspend from
userland via powerd(8). Note: a suspend can only be handled correctly
when dom0 requested it, so provide a mechanism that will prevent
kernel to blindly validate user's commands
The code is still in experimental state, use at your own risk: restore
can corrupt backend communications rings; this can completely thrash
dom0 as it will loop at a high interrupt level trying to honor
all domU requests.
XXX PAE suspend does not work in amd64 currently, due to (yet again!)
page validation issues with hypervisor. Will fix.
XXX secondary CPUs are not suspended, I will write the handlers
in sync with cherry's Xen MP work.
Tested under i386 and amd64, bear in mind ring corruption though.
No build break expected, GENERICs and XEN* kernels should be fine.
./build.sh distribution still running. In any case: sorry if it does
break for you, contact me directly for reports.
2011-09-20 04:12:23 +04:00
|
|
|
/* power management, for save/restore */
|
|
|
|
static bool xenbus_suspend(device_t, const pmf_qual_t *);
|
|
|
|
static bool xenbus_resume(device_t, const pmf_qual_t *);
|
|
|
|
|
2011-03-31 02:34:03 +04:00
|
|
|
/* routines gathering device information from XenStore */
|
|
|
|
static int read_otherend_details(struct xenbus_device *,
|
|
|
|
const char *, const char *);
|
|
|
|
static int read_backend_details (struct xenbus_device *);
|
|
|
|
static int read_frontend_details(struct xenbus_device *);
|
|
|
|
static void free_otherend_details(struct xenbus_device *);
|
|
|
|
|
|
|
|
static int watch_otherend (struct xenbus_device *);
|
|
|
|
static void free_otherend_watch(struct xenbus_device *);
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void xenbus_probe_init(void *);
|
|
|
|
|
2006-03-27 02:02:57 +04:00
|
|
|
static struct xenbus_device *xenbus_lookup_device_path(const char *);
|
|
|
|
|
2008-04-16 22:41:48 +04:00
|
|
|
CFATTACH_DECL_NEW(xenbus, 0, xenbus_match, xenbus_attach,
|
2006-03-06 23:21:35 +03:00
|
|
|
NULL, NULL);
|
|
|
|
|
2008-10-22 01:55:44 +04:00
|
|
|
device_t xenbus_dev;
|
2006-03-27 02:02:57 +04:00
|
|
|
|
|
|
|
SLIST_HEAD(, xenbus_device) xenbus_device_list;
|
2006-05-24 01:07:56 +04:00
|
|
|
SLIST_HEAD(, xenbus_backend_driver) xenbus_backend_driver_list =
|
|
|
|
SLIST_HEAD_INITIALIZER(xenbus_backend_driver);
|
2006-03-06 23:21:35 +03:00
|
|
|
|
|
|
|
int
|
2008-04-16 22:41:48 +04:00
|
|
|
xenbus_match(device_t parent, cfdata_t match, void *aux)
|
2006-03-06 23:21:35 +03:00
|
|
|
{
|
|
|
|
struct xenbus_attach_args *xa = (struct xenbus_attach_args *)aux;
|
|
|
|
|
|
|
|
if (strcmp(xa->xa_device, "xenbus") == 0)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-04-16 22:41:48 +04:00
|
|
|
xenbus_attach(device_t parent, device_t self, void *aux)
|
2006-03-06 23:21:35 +03:00
|
|
|
{
|
2007-07-10 00:51:58 +04:00
|
|
|
int err;
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
aprint_normal(": Xen Virtual Bus Interface\n");
|
2008-10-22 01:55:44 +04:00
|
|
|
xenbus_dev = self;
|
2013-10-13 10:55:34 +04:00
|
|
|
config_pending_incr(self);
|
2007-07-10 00:51:58 +04:00
|
|
|
|
|
|
|
err = kthread_create(PRI_NONE, 0, NULL, xenbus_probe_init, NULL,
|
|
|
|
NULL, "xenbus_probe");
|
|
|
|
if (err)
|
2008-10-22 01:55:44 +04:00
|
|
|
aprint_error_dev(xenbus_dev,
|
2008-10-22 01:28:05 +04:00
|
|
|
"kthread_create(xenbus_probe): %d\n", err);
|
Merge jym-xensuspend branch in -current. ok bouyer@.
Goal: save/restore support in NetBSD domUs, for i386, i386 PAE and amd64.
Executive summary:
- split all Xen drivers (xenbus(4), grant tables, xbd(4), xennet(4))
in two parts: suspend and resume, and hook them to pmf(9).
- modify pmap so that Xen hypervisor does not cry out loud in case
it finds "unexpected" recursive memory mappings
- provide a sysctl(7), machdep.xen.suspend, to command suspend from
userland via powerd(8). Note: a suspend can only be handled correctly
when dom0 requested it, so provide a mechanism that will prevent
kernel to blindly validate user's commands
The code is still in experimental state, use at your own risk: restore
can corrupt backend communications rings; this can completely thrash
dom0 as it will loop at a high interrupt level trying to honor
all domU requests.
XXX PAE suspend does not work in amd64 currently, due to (yet again!)
page validation issues with hypervisor. Will fix.
XXX secondary CPUs are not suspended, I will write the handlers
in sync with cherry's Xen MP work.
Tested under i386 and amd64, bear in mind ring corruption though.
No build break expected, GENERICs and XEN* kernels should be fine.
./build.sh distribution still running. In any case: sorry if it does
break for you, contact me directly for reports.
2011-09-20 04:12:23 +04:00
|
|
|
|
|
|
|
if (!pmf_device_register(self, xenbus_suspend, xenbus_resume))
|
|
|
|
aprint_error_dev(self, "couldn't establish power handler\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
xenbus_suspend(device_t dev, const pmf_qual_t *qual)
|
|
|
|
{
|
|
|
|
xs_suspend();
|
|
|
|
xb_suspend_comms(dev);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
xenbus_resume(device_t dev, const pmf_qual_t *qual)
|
|
|
|
{
|
|
|
|
xb_init_comms(dev);
|
|
|
|
xs_resume();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Suspend a xenbus device
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
xenbus_device_suspend(struct xenbus_device *dev) {
|
|
|
|
|
|
|
|
free_otherend_details(dev);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Resume a xenbus device
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
xenbus_device_resume(struct xenbus_device *dev) {
|
|
|
|
|
|
|
|
if (dev->xbusd_type == XENBUS_FRONTEND_DEVICE) {
|
|
|
|
read_backend_details(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2006-03-06 23:21:35 +03:00
|
|
|
}
|
|
|
|
|
2006-05-24 01:07:56 +04:00
|
|
|
void
|
|
|
|
xenbus_backend_register(struct xenbus_backend_driver *xbakd)
|
|
|
|
{
|
|
|
|
SLIST_INSERT_HEAD(&xenbus_backend_driver_list, xbakd, xbakd_entries);
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static int
|
|
|
|
read_otherend_details(struct xenbus_device *xendev,
|
|
|
|
const char *id_node, const char *path_node)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
2006-03-06 23:21:35 +03:00
|
|
|
int err;
|
|
|
|
char *val, *ep;
|
|
|
|
|
|
|
|
err = xenbus_read(NULL, xendev->xbusd_path, id_node, NULL, &val);
|
2006-03-06 23:16:33 +03:00
|
|
|
if (err) {
|
2006-03-06 23:21:35 +03:00
|
|
|
printf("reading other end details %s from %s\n",
|
|
|
|
id_node, xendev->xbusd_path);
|
2006-03-06 23:16:33 +03:00
|
|
|
xenbus_dev_fatal(xendev, err,
|
2006-03-06 23:21:35 +03:00
|
|
|
"reading other end details %s from %s",
|
|
|
|
id_node, xendev->xbusd_path);
|
2006-03-06 23:16:33 +03:00
|
|
|
return err;
|
|
|
|
}
|
2006-03-06 23:21:35 +03:00
|
|
|
xendev->xbusd_otherend_id = strtoul(val, &ep, 10);
|
|
|
|
if (val[0] == '\0' || *ep != '\0') {
|
|
|
|
printf("reading other end details %s from %s: %s is not a number\n", id_node, xendev->xbusd_path, val);
|
|
|
|
xenbus_dev_fatal(xendev, err,
|
|
|
|
"reading other end details %s from %s: %s is not a number",
|
|
|
|
id_node, xendev->xbusd_path, val);
|
|
|
|
free(val, M_DEVBUF);
|
|
|
|
return EFTYPE;
|
|
|
|
}
|
|
|
|
free(val, M_DEVBUF);
|
|
|
|
err = xenbus_read(NULL, xendev->xbusd_path, path_node, NULL, &val);
|
|
|
|
if (err) {
|
|
|
|
printf("reading other end details %s from %s (%d)\n",
|
|
|
|
path_node, xendev->xbusd_path, err);
|
|
|
|
xenbus_dev_fatal(xendev, err,
|
|
|
|
"reading other end details %s from %s",
|
|
|
|
path_node, xendev->xbusd_path);
|
|
|
|
return err;
|
|
|
|
}
|
2006-03-16 01:20:06 +03:00
|
|
|
DPRINTK("read_otherend_details: read %s/%s returned %s\n",
|
|
|
|
xendev->xbusd_path, path_node, val);
|
2006-03-06 23:21:35 +03:00
|
|
|
xendev->xbusd_otherend = val;
|
|
|
|
|
|
|
|
if (strlen(xendev->xbusd_otherend) == 0 ||
|
|
|
|
!xenbus_exists(NULL, xendev->xbusd_otherend, "")) {
|
|
|
|
printf("missing other end from %s\n", xendev->xbusd_path);
|
2006-03-06 23:16:33 +03:00
|
|
|
xenbus_dev_fatal(xendev, -ENOENT, "missing other end from %s",
|
2006-03-06 23:21:35 +03:00
|
|
|
xendev->xbusd_path);
|
2011-03-31 02:34:03 +04:00
|
|
|
free_otherend_details(xendev);
|
2006-03-06 23:21:35 +03:00
|
|
|
return ENOENT;
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static int
|
|
|
|
read_backend_details(struct xenbus_device *xendev)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
|
|
|
return read_otherend_details(xendev, "backend-id", "backend");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static int
|
|
|
|
read_frontend_details(struct xenbus_device *xendev)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
|
|
|
return read_otherend_details(xendev, "frontend-id", "frontend");
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void
|
|
|
|
free_otherend_details(struct xenbus_device *dev)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
2006-03-06 23:21:35 +03:00
|
|
|
free(dev->xbusd_otherend, M_DEVBUF);
|
|
|
|
dev->xbusd_otherend = NULL;
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void
|
|
|
|
free_otherend_watch(struct xenbus_device *dev)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
2006-03-06 23:21:35 +03:00
|
|
|
if (dev->xbusd_otherend_watch.node) {
|
|
|
|
unregister_xenbus_watch(&dev->xbusd_otherend_watch);
|
2006-03-16 01:20:06 +03:00
|
|
|
free(dev->xbusd_otherend_watch.node, M_DEVBUF);
|
2006-03-06 23:21:35 +03:00
|
|
|
dev->xbusd_otherend_watch.node = NULL;
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void
|
|
|
|
otherend_changed(struct xenbus_watch *watch,
|
2006-03-06 23:16:33 +03:00
|
|
|
const char **vec, unsigned int len)
|
|
|
|
{
|
2006-03-16 01:20:06 +03:00
|
|
|
struct xenbus_device *xdev = watch->xbw_dev;
|
2006-03-06 23:16:33 +03:00
|
|
|
XenbusState state;
|
|
|
|
|
|
|
|
/* Protect us against watches firing on old details when the otherend
|
|
|
|
details change, say immediately after a resume. */
|
2006-03-16 01:20:06 +03:00
|
|
|
if (!xdev->xbusd_otherend ||
|
|
|
|
strncmp(xdev->xbusd_otherend, vec[XS_WATCH_PATH],
|
|
|
|
strlen(xdev->xbusd_otherend))) {
|
2006-03-06 23:16:33 +03:00
|
|
|
DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-16 01:20:06 +03:00
|
|
|
state = xenbus_read_driver_state(xdev->xbusd_otherend);
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
DPRINTK("state is %d, %s, %s",
|
2006-03-16 01:20:06 +03:00
|
|
|
state, xdev->xbusd_otherend_watch.node, vec[XS_WATCH_PATH]);
|
2006-03-27 02:02:57 +04:00
|
|
|
if (state == XenbusStateClosed) {
|
|
|
|
int error;
|
2006-05-24 01:07:56 +04:00
|
|
|
if (xdev->xbusd_type == XENBUS_BACKEND_DEVICE) {
|
|
|
|
error = xdev->xbusd_u.b.b_detach(
|
|
|
|
xdev->xbusd_u.b.b_cookie);
|
|
|
|
if (error) {
|
|
|
|
printf("could not detach %s: %d\n",
|
|
|
|
xdev->xbusd_path, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error = config_detach(xdev->xbusd_u.f.f_dev,
|
|
|
|
DETACH_FORCE);
|
|
|
|
if (error) {
|
|
|
|
printf("could not detach %s: %d\n",
|
2008-04-06 11:23:57 +04:00
|
|
|
device_xname(xdev->xbusd_u.f.f_dev), error);
|
2006-05-24 01:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
2006-03-27 02:02:57 +04:00
|
|
|
}
|
|
|
|
xenbus_free_device(xdev);
|
|
|
|
return;
|
|
|
|
}
|
2006-03-16 01:20:06 +03:00
|
|
|
if (xdev->xbusd_otherend_changed)
|
2006-05-24 01:07:56 +04:00
|
|
|
xdev->xbusd_otherend_changed(
|
|
|
|
(xdev->xbusd_type == XENBUS_BACKEND_DEVICE) ?
|
|
|
|
xdev->xbusd_u.b.b_cookie : xdev->xbusd_u.f.f_dev, state);
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static int
|
2011-03-31 02:34:03 +04:00
|
|
|
watch_otherend(struct xenbus_device *dev)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
|
|
|
free_otherend_watch(dev);
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
return xenbus_watch_path2(dev, dev->xbusd_otherend, "state",
|
2006-03-16 01:20:06 +03:00
|
|
|
&dev->xbusd_otherend_watch,
|
|
|
|
otherend_changed);
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2006-03-27 02:02:57 +04:00
|
|
|
static struct xenbus_device *
|
|
|
|
xenbus_lookup_device_path(const char *path)
|
|
|
|
{
|
|
|
|
struct xenbus_device *xbusd;
|
|
|
|
|
|
|
|
SLIST_FOREACH(xbusd, &xenbus_device_list, xbusd_entries) {
|
|
|
|
if (strcmp(xbusd->xbusd_path, path) == 0)
|
|
|
|
return xbusd;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static int
|
2006-05-24 01:07:56 +04:00
|
|
|
xenbus_probe_device_type(const char *path, const char *type,
|
|
|
|
int (*create)(struct xenbus_device *))
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
2012-06-05 14:58:56 +04:00
|
|
|
int err, i, pos, msize;
|
|
|
|
int *lookup = NULL;
|
2006-05-24 01:07:56 +04:00
|
|
|
unsigned long state;
|
2006-03-06 23:16:33 +03:00
|
|
|
char **dir;
|
|
|
|
unsigned int dir_n = 0;
|
2006-03-06 23:21:35 +03:00
|
|
|
struct xenbus_device *xbusd;
|
|
|
|
struct xenbusdev_attach_args xa;
|
|
|
|
char *ep;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
2006-05-24 01:07:56 +04:00
|
|
|
DPRINTK("probe %s type %s", path, type);
|
|
|
|
err = xenbus_directory(NULL, path, "", &dir_n, &dir);
|
2006-03-06 23:21:35 +03:00
|
|
|
DPRINTK("directory err %d dir_n %d", err, dir_n);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
2012-06-05 14:58:56 +04:00
|
|
|
/* Only sort frontend devices i.e. create == NULL*/
|
|
|
|
if (dir_n > 1 && create == NULL) {
|
|
|
|
int minp;
|
|
|
|
unsigned long minv;
|
|
|
|
unsigned long *id;
|
|
|
|
|
|
|
|
lookup = malloc(sizeof(int) * dir_n, M_DEVBUF,
|
|
|
|
M_WAITOK | M_ZERO);
|
|
|
|
if (lookup == NULL)
|
|
|
|
panic("can't malloc lookup");
|
|
|
|
|
|
|
|
id = malloc(sizeof(unsigned long) * dir_n, M_DEVBUF,
|
|
|
|
M_WAITOK | M_ZERO);
|
|
|
|
if (id == NULL)
|
|
|
|
panic("can't malloc id");
|
|
|
|
|
|
|
|
/* Convert string values to numeric; skip invalid */
|
|
|
|
for (i = 0; i < dir_n; i++) {
|
2012-06-07 18:05:13 +04:00
|
|
|
/*
|
|
|
|
* Add one to differentiate numerical zero from invalid
|
|
|
|
* string. Has no effect on sort order.
|
|
|
|
*/
|
|
|
|
id[i] = strtoul(dir[i], &ep, 10) + 1;
|
2012-06-05 14:58:56 +04:00
|
|
|
if (dir[i][0] == '\0' || *ep != '\0')
|
|
|
|
id[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build lookup table in ascending order */
|
|
|
|
for (pos = 0; pos < dir_n; ) {
|
|
|
|
minv = UINT32_MAX;
|
|
|
|
minp = -1;
|
|
|
|
for (i = 0; i < dir_n; i++) {
|
|
|
|
if (id[i] < minv && id[i] > 0) {
|
|
|
|
minv = id[i];
|
|
|
|
minp = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (minp >= 0) {
|
|
|
|
lookup[pos++] = minp;
|
|
|
|
id[minp] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(id, M_DEVBUF);
|
|
|
|
/* Adjust in case we had to skip non-numeric entries */
|
|
|
|
dir_n = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pos = 0; pos < dir_n; pos++) {
|
2011-04-11 19:00:49 +04:00
|
|
|
err = 0;
|
2012-06-05 14:58:56 +04:00
|
|
|
if (lookup)
|
|
|
|
i = lookup[pos];
|
|
|
|
else
|
|
|
|
i = pos;
|
2006-03-27 02:02:57 +04:00
|
|
|
/*
|
|
|
|
* add size of path to size of xenbus_device. xenbus_device
|
|
|
|
* already has room for one char in xbusd_path.
|
|
|
|
*/
|
2006-05-24 01:07:56 +04:00
|
|
|
msize = sizeof(*xbusd) + strlen(path) + strlen(dir[i]) + 2;
|
2006-03-27 02:02:57 +04:00
|
|
|
xbusd = malloc(msize, M_DEVBUF, M_WAITOK | M_ZERO);
|
2006-03-06 23:21:35 +03:00
|
|
|
if (xbusd == NULL)
|
|
|
|
panic("can't malloc xbusd");
|
|
|
|
|
|
|
|
snprintf(__UNCONST(xbusd->xbusd_path),
|
2006-05-24 01:07:56 +04:00
|
|
|
msize - sizeof(*xbusd) + 1, "%s/%s", path, dir[i]);
|
2006-03-27 02:02:57 +04:00
|
|
|
if (xenbus_lookup_device_path(xbusd->xbusd_path) != NULL) {
|
|
|
|
/* device already registered */
|
|
|
|
free(xbusd, M_DEVBUF);
|
|
|
|
continue;
|
|
|
|
}
|
2006-05-24 01:07:56 +04:00
|
|
|
err = xenbus_read_ul(NULL, xbusd->xbusd_path, "state",
|
2006-06-25 20:46:59 +04:00
|
|
|
&state, 10);
|
2006-05-24 01:07:56 +04:00
|
|
|
if (err) {
|
|
|
|
printf("xenbus: can't get state "
|
|
|
|
"for %s (%d)\n", xbusd->xbusd_path, err);
|
|
|
|
free(xbusd, M_DEVBUF);
|
2011-04-12 09:09:32 +04:00
|
|
|
err = 0;
|
2006-05-24 01:07:56 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (state != XenbusStateInitialising) {
|
|
|
|
/* device is not new */
|
|
|
|
free(xbusd, M_DEVBUF);
|
|
|
|
continue;
|
|
|
|
}
|
2006-03-27 02:02:57 +04:00
|
|
|
|
2006-03-16 01:20:06 +03:00
|
|
|
xbusd->xbusd_otherend_watch.xbw_dev = xbusd;
|
2006-03-06 23:21:35 +03:00
|
|
|
DPRINTK("xenbus_probe_device_type probe %s\n",
|
|
|
|
xbusd->xbusd_path);
|
2006-05-24 01:07:56 +04:00
|
|
|
if (create != NULL) {
|
|
|
|
xbusd->xbusd_type = XENBUS_BACKEND_DEVICE;
|
|
|
|
err = read_frontend_details(xbusd);
|
|
|
|
if (err != 0) {
|
|
|
|
printf("xenbus: can't get frontend details "
|
|
|
|
"for %s (%d)\n", xbusd->xbusd_path, err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (create(xbusd)) {
|
|
|
|
free(xbusd, M_DEVBUF);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
xbusd->xbusd_type = XENBUS_FRONTEND_DEVICE;
|
|
|
|
xa.xa_xbusd = xbusd;
|
|
|
|
xa.xa_type = type;
|
|
|
|
xa.xa_id = strtoul(dir[i], &ep, 0);
|
|
|
|
if (dir[i][0] == '\0' || *ep != '\0') {
|
|
|
|
printf("xenbus device type %s: id %s is not a"
|
|
|
|
" number\n", type, dir[i]);
|
|
|
|
err = EFTYPE;
|
|
|
|
free(xbusd, M_DEVBUF);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
err = read_backend_details(xbusd);
|
|
|
|
if (err != 0) {
|
|
|
|
printf("xenbus: can't get backend details "
|
|
|
|
"for %s (%d)\n", xbusd->xbusd_path, err);
|
|
|
|
break;
|
|
|
|
}
|
2008-10-22 01:55:44 +04:00
|
|
|
xbusd->xbusd_u.f.f_dev = config_found_ia(xenbus_dev,
|
2006-05-24 01:07:56 +04:00
|
|
|
"xenbus", &xa, xenbus_print);
|
|
|
|
if (xbusd->xbusd_u.f.f_dev == NULL) {
|
|
|
|
free(xbusd, M_DEVBUF);
|
|
|
|
continue;
|
|
|
|
}
|
2006-03-16 01:20:06 +03:00
|
|
|
}
|
2006-05-24 01:07:56 +04:00
|
|
|
SLIST_INSERT_HEAD(&xenbus_device_list,
|
|
|
|
xbusd, xbusd_entries);
|
2011-03-31 02:34:03 +04:00
|
|
|
watch_otherend(xbusd);
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
2006-03-06 23:21:35 +03:00
|
|
|
free(dir, M_DEVBUF);
|
2012-06-05 14:58:56 +04:00
|
|
|
if (lookup)
|
|
|
|
free(lookup, M_DEVBUF);
|
|
|
|
|
2006-03-06 23:16:33 +03:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static int
|
|
|
|
xenbus_print(void *aux, const char *pnp)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
2006-03-06 23:21:35 +03:00
|
|
|
struct xenbusdev_attach_args *xa = aux;
|
|
|
|
|
|
|
|
if (pnp) {
|
|
|
|
if (strcmp(xa->xa_type, "vbd") == 0)
|
|
|
|
aprint_normal("xbd");
|
|
|
|
else if (strcmp(xa->xa_type, "vif") == 0)
|
|
|
|
aprint_normal("xennet");
|
Large rewrite of the balloon driver. This one:
- turns balloon into a driver that attaches to xenbus(4). This allows to
disable the functionality either at compile time or boot time via
userconf(4). Driver can implement detach or pmf(9) hooks if deemed
necessary.
- keeps Cherry's locking model, but simplify it a bit. There is now
only one target value serialized inside balloon, we do not feedback
alternative value to Xenstore (clients are not expected to see its value
evolve behind their back, and can't do much about that either)
- implements min threshold; this is an admin-settable value that tells
driver to "not balloon below this threshold." This can be used by domain
to keep memory reservations, useful if activity is expected in the near
future.
- in addition to min threshold, the driver implements internally a
safeguard value (uvmexp.freemin + 1MiB), so that admin cannot
inadvertently set min to a very low value forcing domain into heavy
memory pressure and swapping.
- create the sysctl(8) kern.xen.balloon tree. 4 nodes are actually present
(values are in KiB):
- min: (rw) an admin-settable value that prevents ballooning below this
mark
- max: (ro) the maximum size for reservation, as set by xm(1) mem-max.
- current: (ro) the current reservation for domain.
- target: (rw) the targetted reservation for domain.
- fix a few limitations here and there, most notably the max_reservation
hypercall, and KiB vs pages representations at interfaces.
The driver is still turned off by default. Enabling it would need more
approval, especially from bouyer@, cherry@ and cegger@.
FWIW: tested it two days long, from amd64 dom0 (with dom0 ballooning
enabled for xend), and bunch of domUs. Did not notice anything suspicious.
XXX it still has one big limitation: it cannot hotplug memory pages in
uvm(9) if they were not present beforehand. Example: ballooning above
physmem will give more pages to domain but it won't use it to serve
allocations, unless we teach uvm(9) how to handle the extra pages.
2011-04-18 05:36:24 +04:00
|
|
|
else if (strcmp(xa->xa_type, "balloon") == 0)
|
|
|
|
aprint_normal("balloon");
|
2006-03-06 23:21:35 +03:00
|
|
|
else
|
|
|
|
aprint_normal("unknown type %s", xa->xa_type);
|
|
|
|
aprint_normal(" at %s", pnp);
|
|
|
|
}
|
|
|
|
aprint_normal(" id %d", xa->xa_id);
|
|
|
|
return(UNCONF);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-05-24 01:07:56 +04:00
|
|
|
xenbus_probe_frontends(void)
|
2006-03-06 23:21:35 +03:00
|
|
|
{
|
|
|
|
int err;
|
2006-03-06 23:16:33 +03:00
|
|
|
char **dir;
|
|
|
|
unsigned int i, dir_n;
|
2006-05-24 01:07:56 +04:00
|
|
|
char path[30];
|
2006-03-06 23:16:33 +03:00
|
|
|
|
2006-05-24 01:07:56 +04:00
|
|
|
DPRINTK("probe device");
|
|
|
|
err = xenbus_directory(NULL, "device", "", &dir_n, &dir);
|
2006-03-06 23:21:35 +03:00
|
|
|
DPRINTK("directory err %d dir_n %d", err, dir_n);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
for (i = 0; i < dir_n; i++) {
|
2009-01-10 01:26:25 +03:00
|
|
|
/*
|
|
|
|
* console is configured through xen_start_info when
|
|
|
|
* xencons is attaching to hypervisor, so avoid console
|
|
|
|
* probing when configuring xenbus devices
|
|
|
|
*/
|
|
|
|
if (strcmp(dir[i], "console") == 0)
|
|
|
|
continue;
|
|
|
|
|
2006-05-24 01:07:56 +04:00
|
|
|
snprintf(path, sizeof(path), "device/%s", dir[i]);
|
|
|
|
err = xenbus_probe_device_type(path, dir[i], NULL);
|
2006-03-06 23:16:33 +03:00
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
2006-03-06 23:21:35 +03:00
|
|
|
free(dir, M_DEVBUF);
|
2006-03-06 23:16:33 +03:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-05-24 01:07:56 +04:00
|
|
|
static int
|
|
|
|
xenbus_probe_backends(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
char **dirt, **dirid;
|
|
|
|
unsigned int type, id, dirt_n, dirid_n;
|
|
|
|
char path[30];
|
|
|
|
struct xenbus_backend_driver *xbakd;
|
|
|
|
|
|
|
|
DPRINTK("probe backend");
|
|
|
|
err = xenbus_directory(NULL, "backend", "", &dirt_n, &dirt);
|
|
|
|
DPRINTK("directory err %d dirt_n %d", err, dirt_n);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
for (type = 0; type < dirt_n; type++) {
|
|
|
|
SLIST_FOREACH(xbakd, &xenbus_backend_driver_list,
|
|
|
|
xbakd_entries) {
|
|
|
|
if (strcmp(dirt[type], xbakd->xbakd_type) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (xbakd == NULL)
|
|
|
|
continue;
|
|
|
|
err = xenbus_directory(NULL, "backend", dirt[type],
|
|
|
|
&dirid_n, &dirid);
|
|
|
|
DPRINTK("directory backend/%s err %d dirid_n %d",
|
|
|
|
dirt[type], err, dirid_n);
|
2006-09-29 18:36:30 +04:00
|
|
|
if (err) {
|
|
|
|
free(dirt, M_DEVBUF); /* to be checked */
|
2006-05-24 01:07:56 +04:00
|
|
|
return err;
|
2006-09-29 18:36:30 +04:00
|
|
|
}
|
2006-05-24 01:07:56 +04:00
|
|
|
for (id = 0; id < dirid_n; id++) {
|
|
|
|
snprintf(path, sizeof(path), "backend/%s/%s",
|
|
|
|
dirt[type], dirid[id]);
|
|
|
|
err = xenbus_probe_device_type(path, dirt[type],
|
|
|
|
xbakd->xbakd_create);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(dirid, M_DEVBUF);
|
|
|
|
}
|
|
|
|
free(dirt, M_DEVBUF);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-03-27 02:02:57 +04:00
|
|
|
int
|
|
|
|
xenbus_free_device(struct xenbus_device *xbusd)
|
|
|
|
{
|
|
|
|
KASSERT(xenbus_lookup_device_path(xbusd->xbusd_path) == xbusd);
|
|
|
|
SLIST_REMOVE(&xenbus_device_list, xbusd, xenbus_device, xbusd_entries);
|
|
|
|
free_otherend_watch(xbusd);
|
2011-03-31 02:34:03 +04:00
|
|
|
free_otherend_details(xbusd);
|
2006-03-27 02:02:57 +04:00
|
|
|
xenbus_switch_state(xbusd, NULL, XenbusStateClosed);
|
|
|
|
free(xbusd, M_DEVBUF);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void
|
|
|
|
frontend_changed(struct xenbus_watch *watch,
|
2006-03-06 23:16:33 +03:00
|
|
|
const char **vec, unsigned int len)
|
|
|
|
{
|
2006-05-24 01:07:56 +04:00
|
|
|
DPRINTK("frontend_changed %s\n", vec[XS_WATCH_PATH]);
|
|
|
|
xenbus_probe_frontends();
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void
|
|
|
|
backend_changed(struct xenbus_watch *watch,
|
2006-03-06 23:16:33 +03:00
|
|
|
const char **vec, unsigned int len)
|
|
|
|
{
|
2006-05-24 01:07:56 +04:00
|
|
|
DPRINTK("backend_changed %s\n", vec[XS_WATCH_PATH]);
|
|
|
|
xenbus_probe_backends();
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
|
2006-03-06 23:16:33 +03:00
|
|
|
/* We watch for devices appearing and vanishing. */
|
2006-03-16 01:20:06 +03:00
|
|
|
static struct xenbus_watch fe_watch;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
2006-03-16 01:20:06 +03:00
|
|
|
static struct xenbus_watch be_watch;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
/* A flag to determine if xenstored is 'ready' (i.e. has started) */
|
|
|
|
int xenstored_ready = 0;
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
void
|
|
|
|
xenbus_probe(void *unused)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
Large rewrite of the balloon driver. This one:
- turns balloon into a driver that attaches to xenbus(4). This allows to
disable the functionality either at compile time or boot time via
userconf(4). Driver can implement detach or pmf(9) hooks if deemed
necessary.
- keeps Cherry's locking model, but simplify it a bit. There is now
only one target value serialized inside balloon, we do not feedback
alternative value to Xenstore (clients are not expected to see its value
evolve behind their back, and can't do much about that either)
- implements min threshold; this is an admin-settable value that tells
driver to "not balloon below this threshold." This can be used by domain
to keep memory reservations, useful if activity is expected in the near
future.
- in addition to min threshold, the driver implements internally a
safeguard value (uvmexp.freemin + 1MiB), so that admin cannot
inadvertently set min to a very low value forcing domain into heavy
memory pressure and swapping.
- create the sysctl(8) kern.xen.balloon tree. 4 nodes are actually present
(values are in KiB):
- min: (rw) an admin-settable value that prevents ballooning below this
mark
- max: (ro) the maximum size for reservation, as set by xm(1) mem-max.
- current: (ro) the current reservation for domain.
- target: (rw) the targetted reservation for domain.
- fix a few limitations here and there, most notably the max_reservation
hypercall, and KiB vs pages representations at interfaces.
The driver is still turned off by default. Enabling it would need more
approval, especially from bouyer@, cherry@ and cegger@.
FWIW: tested it two days long, from amd64 dom0 (with dom0 ballooning
enabled for xend), and bunch of domUs. Did not notice anything suspicious.
XXX it still has one big limitation: it cannot hotplug memory pages in
uvm(9) if they were not present beforehand. Example: ballooning above
physmem will give more pages to domain but it won't use it to serve
allocations, unless we teach uvm(9) how to handle the extra pages.
2011-04-18 05:36:24 +04:00
|
|
|
struct xenbusdev_attach_args balloon_xa = {
|
|
|
|
.xa_id = 0,
|
|
|
|
.xa_type = "balloon"
|
|
|
|
};
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
KASSERT((xenstored_ready > 0));
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
/* Enumerate devices in xenstore. */
|
2006-05-24 01:07:56 +04:00
|
|
|
xenbus_probe_frontends();
|
|
|
|
xenbus_probe_backends();
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
/* Watch for changes. */
|
2006-03-16 01:20:06 +03:00
|
|
|
fe_watch.node = malloc(strlen("device" + 1), M_DEVBUF, M_NOWAIT);
|
|
|
|
strcpy(fe_watch.node, "device");
|
|
|
|
fe_watch.xbw_callback = frontend_changed;
|
2006-03-06 23:16:33 +03:00
|
|
|
register_xenbus_watch(&fe_watch);
|
2006-03-16 01:20:06 +03:00
|
|
|
be_watch.node = malloc(strlen("backend" + 1), M_DEVBUF, M_NOWAIT);
|
|
|
|
strcpy(be_watch.node, "backend");
|
|
|
|
be_watch.xbw_callback = backend_changed;
|
2006-03-06 23:16:33 +03:00
|
|
|
register_xenbus_watch(&be_watch);
|
|
|
|
|
Large rewrite of the balloon driver. This one:
- turns balloon into a driver that attaches to xenbus(4). This allows to
disable the functionality either at compile time or boot time via
userconf(4). Driver can implement detach or pmf(9) hooks if deemed
necessary.
- keeps Cherry's locking model, but simplify it a bit. There is now
only one target value serialized inside balloon, we do not feedback
alternative value to Xenstore (clients are not expected to see its value
evolve behind their back, and can't do much about that either)
- implements min threshold; this is an admin-settable value that tells
driver to "not balloon below this threshold." This can be used by domain
to keep memory reservations, useful if activity is expected in the near
future.
- in addition to min threshold, the driver implements internally a
safeguard value (uvmexp.freemin + 1MiB), so that admin cannot
inadvertently set min to a very low value forcing domain into heavy
memory pressure and swapping.
- create the sysctl(8) kern.xen.balloon tree. 4 nodes are actually present
(values are in KiB):
- min: (rw) an admin-settable value that prevents ballooning below this
mark
- max: (ro) the maximum size for reservation, as set by xm(1) mem-max.
- current: (ro) the current reservation for domain.
- target: (rw) the targetted reservation for domain.
- fix a few limitations here and there, most notably the max_reservation
hypercall, and KiB vs pages representations at interfaces.
The driver is still turned off by default. Enabling it would need more
approval, especially from bouyer@, cherry@ and cegger@.
FWIW: tested it two days long, from amd64 dom0 (with dom0 ballooning
enabled for xend), and bunch of domUs. Did not notice anything suspicious.
XXX it still has one big limitation: it cannot hotplug memory pages in
uvm(9) if they were not present beforehand. Example: ballooning above
physmem will give more pages to domain but it won't use it to serve
allocations, unless we teach uvm(9) how to handle the extra pages.
2011-04-18 05:36:24 +04:00
|
|
|
/* attach balloon. */
|
|
|
|
config_found_ia(xenbus_dev, "xenbus", &balloon_xa, xenbus_print);
|
|
|
|
|
|
|
|
shutdown_xenbus_setup();
|
2010-07-06 19:00:09 +04:00
|
|
|
|
2006-03-06 23:16:33 +03:00
|
|
|
/* Notify others that xenstore is up */
|
2006-03-06 23:21:35 +03:00
|
|
|
//notifier_call_chain(&xenstore_chain, 0, NULL);
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
static void
|
|
|
|
xenbus_probe_init(void *unused)
|
2006-03-06 23:16:33 +03:00
|
|
|
{
|
2008-10-22 01:28:05 +04:00
|
|
|
int err = 0;
|
|
|
|
bool dom0;
|
|
|
|
vaddr_t page = 0;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
DPRINTK("");
|
|
|
|
|
2006-03-27 02:02:57 +04:00
|
|
|
SLIST_INIT(&xenbus_device_list);
|
|
|
|
|
2006-03-06 23:16:33 +03:00
|
|
|
/*
|
|
|
|
** Domain0 doesn't have a store_evtchn or store_mfn yet.
|
|
|
|
*/
|
2008-10-22 01:28:05 +04:00
|
|
|
dom0 = xendomain_is_dom0();
|
2006-03-06 23:16:33 +03:00
|
|
|
if (dom0) {
|
2006-04-10 01:39:42 +04:00
|
|
|
#if defined(DOM0OPS)
|
|
|
|
paddr_t ma;
|
2008-09-05 17:37:24 +04:00
|
|
|
evtchn_op_t op = { .cmd = 0 };
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
/* Allocate page. */
|
2006-04-10 01:39:42 +04:00
|
|
|
page = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
|
|
|
|
UVM_KMF_ZERO | UVM_KMF_WIRED);
|
2006-03-06 23:16:33 +03:00
|
|
|
if (!page)
|
2006-04-10 01:39:42 +04:00
|
|
|
panic("can't get xenstore page");
|
2006-03-06 23:16:33 +03:00
|
|
|
|
2006-04-10 01:39:42 +04:00
|
|
|
(void)pmap_extract_ma(pmap_kernel(), page, &ma);
|
|
|
|
xen_start_info.store_mfn = ma >> PAGE_SHIFT;
|
|
|
|
xenstore_interface = (void *)page;
|
2006-03-06 23:16:33 +03:00
|
|
|
|
|
|
|
/* Next allocate a local port which xenstored can bind to */
|
|
|
|
op.cmd = EVTCHNOP_alloc_unbound;
|
|
|
|
op.u.alloc_unbound.dom = DOMID_SELF;
|
|
|
|
op.u.alloc_unbound.remote_dom = 0;
|
|
|
|
|
2008-10-22 01:28:05 +04:00
|
|
|
err = HYPERVISOR_event_channel_op(&op);
|
|
|
|
if (err) {
|
2008-10-22 01:55:44 +04:00
|
|
|
aprint_error_dev(xenbus_dev,
|
2008-10-22 01:28:05 +04:00
|
|
|
"can't register xenstore event\n");
|
|
|
|
goto err0;
|
|
|
|
}
|
|
|
|
|
2006-04-10 01:39:42 +04:00
|
|
|
xen_start_info.store_evtchn = op.u.alloc_unbound.port;
|
|
|
|
|
2008-06-03 00:54:59 +04:00
|
|
|
DELAY(1000);
|
2006-04-10 01:39:42 +04:00
|
|
|
#else /* DOM0OPS */
|
2008-10-22 01:28:05 +04:00
|
|
|
kthread_exit(0); /* can't get a working xenstore in this case */
|
2006-04-10 01:39:42 +04:00
|
|
|
#endif /* DOM0OPS */
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
2011-09-23 03:02:34 +04:00
|
|
|
/* Publish xenbus and Xenstore info in /kern/xen */
|
|
|
|
xenbus_kernfs_init();
|
|
|
|
|
2006-05-08 01:50:32 +04:00
|
|
|
/* register event handler */
|
2008-10-22 01:55:44 +04:00
|
|
|
xb_init_comms(xenbus_dev);
|
2006-05-08 01:50:32 +04:00
|
|
|
|
2006-03-06 23:16:33 +03:00
|
|
|
/* Initialize the interface to xenstore. */
|
2008-10-25 01:09:24 +04:00
|
|
|
err = xs_init(xenbus_dev);
|
2006-03-06 23:16:33 +03:00
|
|
|
if (err) {
|
2008-10-22 01:55:44 +04:00
|
|
|
aprint_error_dev(xenbus_dev,
|
2008-10-22 01:28:05 +04:00
|
|
|
"Error initializing xenstore comms: %i\n", err);
|
|
|
|
goto err0;
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!dom0) {
|
|
|
|
xenstored_ready = 1;
|
|
|
|
xenbus_probe(NULL);
|
|
|
|
}
|
|
|
|
|
2006-03-06 23:21:35 +03:00
|
|
|
DPRINTK("done");
|
2013-10-13 10:55:34 +04:00
|
|
|
config_pending_decr(xenbus_dev);
|
2006-05-24 01:07:56 +04:00
|
|
|
#ifdef DOM0OPS
|
|
|
|
if (dom0) {
|
|
|
|
int s;
|
|
|
|
s = spltty();
|
|
|
|
while (xenstored_ready == 0) {
|
|
|
|
tsleep(&xenstored_ready, PRIBIO, "xsready", 0);
|
|
|
|
xenbus_probe(NULL);
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
#endif
|
2006-03-06 23:21:35 +03:00
|
|
|
kthread_exit(0);
|
2008-10-22 01:28:05 +04:00
|
|
|
|
|
|
|
err0:
|
|
|
|
if (page)
|
|
|
|
uvm_km_free(kernel_map, page, PAGE_SIZE,
|
|
|
|
UVM_KMF_ZERO | UVM_KMF_WIRED);
|
|
|
|
kthread_exit(err);
|
2006-03-06 23:16:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* c-file-style: "linux"
|
|
|
|
* indent-tabs-mode: t
|
|
|
|
* c-indent-level: 8
|
|
|
|
* c-basic-offset: 8
|
|
|
|
* tab-width: 8
|
|
|
|
* End:
|
|
|
|
*/
|