All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexander Graf <agraf@suse.de>
To: qemu-devel Developers <qemu-devel@nongnu.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH 31/40] xenner: libxc emu: xenstore
Date: Mon,  1 Nov 2010 16:01:44 +0100	[thread overview]
Message-ID: <1288623713-28062-32-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1288623713-28062-1-git-send-email-agraf@suse.de>

Xenner emulates parts of libxc, so we can not use the real xen infrastructure
when running xen pv guests without xen.

This patch adds support for emulation of xenstored.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/xenner_guest_store.c |  494 +++++++++++++++++++++++++++++++++
 hw/xenner_libxenstore.c |  709 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1203 insertions(+), 0 deletions(-)
 create mode 100644 hw/xenner_guest_store.c
 create mode 100644 hw/xenner_libxenstore.c

diff --git a/hw/xenner_guest_store.c b/hw/xenner_guest_store.c
new file mode 100644
index 0000000..c067275
--- /dev/null
+++ b/hw/xenner_guest_store.c
@@ -0,0 +1,494 @@
+/*
+ *  Copyright (C) 2005 Rusty Russell IBM Corporation
+ *  Copyright (C) Red Hat 2007
+ *  Copyright (C) Novell Inc. 2010
+ *
+ *  Author(s): Gerd Hoffmann <kraxel@redhat.com>
+ *             Alexander Graf <agraf@suse.de>
+ *
+ *  Xenner emulation -- guest interface to xenstore
+ *
+ *  tools/xenstore/xenstored_domain.c equivalent, some code is from there.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "xen.h"
+#include "xen_interfaces.h"
+#include "xenner.h"
+#include "qemu-char.h"
+
+/* ------------------------------------------------------------- */
+
+static target_phys_addr_t xen_store_mfn;
+
+static struct xs_handle *xs_guest;
+static char xs_buf[1024];
+static char xs_len;
+static int debug = 0;
+
+static int evtchndev;
+static evtchn_port_t evtchnport;
+
+/* ------------------------------------------------------------- */
+
+static const char *msgname[] = {
+    [ XS_DEBUG                 ] = "XS_DEBUG",
+    [ XS_DIRECTORY             ] = "XS_DIRECTORY",
+    [ XS_READ                  ] = "XS_READ",
+    [ XS_GET_PERMS             ] = "XS_GET_PERMS",
+    [ XS_WATCH                 ] = "XS_WATCH",
+    [ XS_UNWATCH               ] = "XS_UNWATCH",
+    [ XS_TRANSACTION_START     ] = "XS_TRANSACTION_START",
+    [ XS_TRANSACTION_END       ] = "XS_TRANSACTION_END",
+    [ XS_INTRODUCE             ] = "XS_INTRODUCE",
+    [ XS_RELEASE               ] = "XS_RELEASE",
+    [ XS_GET_DOMAIN_PATH       ] = "XS_GET_DOMAIN_PATH",
+    [ XS_WRITE                 ] = "XS_WRITE",
+    [ XS_MKDIR                 ] = "XS_MKDIR",
+    [ XS_RM                    ] = "XS_RM",
+    [ XS_SET_PERMS             ] = "XS_SET_PERMS",
+    [ XS_WATCH_EVENT           ] = "XS_WATCH_EVENT",
+    [ XS_ERROR                 ] = "XS_ERROR",
+    [ XS_IS_DOMAIN_INTRODUCED  ] = "XS_IS_DOMAIN_INTRODUCED",
+    [ XS_RESUME                ] = "XS_RESUME",
+};
+
+/* ------------------------------------------------------------- */
+
+static bool check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+    return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *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);
+}
+
+static const void *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);
+}
+
+static int domain_write(struct xenstore_domain_interface *intf,
+                        const void *data, unsigned int len)
+{
+    uint32_t avail;
+    void *dest;
+    XENSTORE_RING_IDX cons, prod;
+
+    /* Must read indexes once, and before anything else, and verified. */
+    cons = intf->rsp_cons;
+    prod = intf->rsp_prod;
+    xen_mb();
+
+    if (!check_indexes(cons, prod)) {
+        errno = EIO;
+        return -1;
+    }
+
+    dest = get_output_chunk(cons, prod, intf->rsp, &avail);
+    if (avail < len) {
+        /* write hangover at the beginning */
+        memcpy(intf->rsp, data + avail, len - avail);
+    }
+
+    memcpy(dest, data, avail);
+    xen_mb();
+    intf->rsp_prod += len;
+
+    xc_evtchn.notify(evtchndev, evtchnport);
+    return len;
+}
+
+static int domain_read(struct xenstore_domain_interface *intf,
+                       void *data, unsigned int len)
+{
+    uint32_t avail;
+    const void *src;
+    XENSTORE_RING_IDX cons, prod;
+
+    /* Must read indexes once, and before anything else, and verified. */
+    cons = intf->req_cons;
+    prod = intf->req_prod;
+    xen_mb();
+
+    if (!check_indexes(cons, prod)) {
+        errno = EIO;
+        return -1;
+    }
+
+    src = get_input_chunk(cons, prod, intf->req, &avail);
+    if (avail < len) {
+        len = avail;
+    }
+
+    memcpy(data, src, len);
+    xen_mb();
+    intf->req_cons += len;
+
+    xc_evtchn.notify(evtchndev, evtchnport);
+    return len;
+}
+
+/* ------------------------------------------------------------- */
+
+static int blen;
+static char *backlog = NULL;
+
+static void backlog_create(void *reply, int mlen, int sent)
+{
+    blen = mlen-sent;
+    backlog = qemu_malloc(blen);
+    memcpy(backlog, ((char*)reply) + sent, blen);
+    if (debug) {
+        fprintf(stderr, "%s: backlog created: %d bytes\n",
+                __FUNCTION__, blen);
+    }
+}
+
+static int backlog_shift(struct xenstore_domain_interface *di,
+                         void *reply, int mlen)
+{
+    int rc;
+
+    rc = domain_write(di, backlog, blen);
+    if (rc == blen) {
+        if (debug) {
+            fprintf(stderr, "%s: backlog cleared\n",
+                    __FUNCTION__);
+        }
+        qemu_free(backlog);
+        backlog = NULL;
+        blen = 0;
+    } else {
+        memmove(backlog, backlog+rc, blen-rc);
+        blen -= rc;
+        backlog = qemu_realloc(backlog, blen + mlen);
+        if (reply) {
+            memcpy(backlog + blen, reply, mlen);
+        }
+        blen += mlen;
+        if (debug) {
+            fprintf(stderr, "%s: backlog resized: %d bytes (%d sent, %d added)\n",
+                    __FUNCTION__, blen, rc, mlen);
+        }
+    }
+    return blen;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct xenstore_domain_interface *get_xdf(void)
+{
+    struct xenstore_domain_interface *xdf;
+    target_phys_addr_t len = sizeof(*xdf);
+
+    xdf = cpu_physical_memory_map(xen_store_mfn << PAGE_SHIFT, &len, 1);
+
+    if (len < sizeof(*xdf)) {
+        return NULL;
+    }
+
+    return xdf;
+}
+
+static int xen_reply(struct xsd_sockmsg *msg, int type, const void *data, int len)
+{
+    struct xenstore_domain_interface *di = get_xdf();
+    struct xsd_sockmsg *reply;
+    int mlen, rc;
+
+    reply = qemu_mallocz(sizeof(*reply) + len);
+    if (!reply) {
+        return -1;
+    }
+    if (msg) {
+        *reply = *msg;
+    }
+    reply->type = type;
+    reply->len = len;
+    if (len) {
+        memcpy(reply+1, data, len);
+    }
+    mlen = sizeof(*reply) + len;
+
+    if (debug) {
+        fprintf(stderr, "%s: %s (#%d) %d:[%.*s]\n", __FUNCTION__,
+                msgname[reply->type], reply->type, len, len, (char*)(reply+1));
+    }
+
+    if (backlog) {
+        if (backlog_shift(di, reply, mlen)) {
+            goto out;
+        }
+    }
+
+    rc = domain_write(di, reply, mlen);
+    if (rc == -1) {
+        fprintf(stderr, "%s: domain_write error\n", __FUNCTION__);
+    } else if (rc != mlen) {
+        backlog_create(reply, mlen, rc);
+    }
+
+out:
+    qemu_free(reply);
+    return 0;
+}
+
+static int xen_reply_str(struct xsd_sockmsg *msg, int type, const char *str)
+{
+    if (str) {
+        return xen_reply(msg, type, str, strlen(str)+1);
+    } else {
+        return xen_reply(msg, type, NULL, 0);
+    }
+}
+
+static int xen_reply_vec(struct xsd_sockmsg *msg, int type, char **vec, int vlen)
+{
+    char payload[1024];
+    int i,len,pos;
+
+    if (!vec) {
+        vlen = 0;
+    }
+    for (pos = 0, i = 0; i < vlen; i++) {
+        len = strlen(vec[i])+1;
+        if (pos+len > sizeof(payload)) {
+            fprintf(stderr, "%s: oops: payload too small\n", __FUNCTION__);
+            break;
+        }
+        memcpy(payload+pos, vec[i], len);
+        pos += len;
+    }
+    return xen_reply(msg, type, payload, pos);
+}
+
+static int xen_handle_data(void *data, int len)
+{
+    struct xsd_sockmsg *msg;
+    char *payload, *arg2, *val, **vec, id[16];
+    unsigned int slen,vlen,alen;
+    bool rc;
+
+    if (len < sizeof(*msg)) {
+        if (debug) {
+            fprintf(stderr, "%s: header incomplete (%d/%zd)\n",
+                    __FUNCTION__, len, sizeof(*msg));
+        }
+        return 0;
+    }
+    msg = data;
+    if (len < sizeof(*msg) + msg->len) {
+        if (debug) {
+            fprintf(stderr, "%s: msg incomplete (%d/%zd)\n",
+                    __FUNCTION__, len, sizeof(*msg) + msg->len);
+        }
+        return 0;
+    }
+    payload = data + sizeof(*msg);
+    payload[msg->len] = 0;
+
+    if (debug) {
+        fprintf(stderr, "%s: %s (#%d) %d:[%.*s]\n", __FUNCTION__,
+                msgname[msg->type], msg->type, msg->len, msg->len, payload);
+    }
+
+    switch (msg->type) {
+    case XS_DEBUG:
+        xen_reply_str(msg, XS_DEBUG, "OK");
+        break;
+    case XS_DIRECTORY:
+        vec = xs.directory(xs_guest, msg->tx_id, payload, &vlen);
+        xen_reply_vec(msg, msg->type, vec, vlen);
+        qemu_free(vec);
+        break;
+    case XS_READ:
+        val = xs.read(xs_guest, msg->tx_id, payload, &slen);
+        if (!val) {
+            xen_reply_str(msg, XS_ERROR, "ENOENT");
+        } else {
+            xen_reply_str(msg, msg->type, val);
+            qemu_free(val);
+        }
+        break;
+    case XS_WRITE:
+        arg2 = payload + strlen(payload) + 1;
+        alen = msg->len - (arg2 - payload);
+        if (xs.write(xs_guest, msg->tx_id, payload, arg2, alen)) {
+            xen_reply(msg, msg->type, NULL, 0);
+        } else {
+            xen_reply_str(msg, XS_ERROR, "EINVAL");
+        }
+        break;
+    case XS_WATCH:
+        arg2 = payload + strlen(payload) + 1;
+        if (xs.watch(xs_guest, payload, arg2)) {
+            xen_reply(msg, msg->type, NULL, 0);
+        } else {
+            xen_reply_str(msg, XS_ERROR, "EINVAL");
+        }
+        break;
+    case XS_UNWATCH:
+        arg2 = payload + strlen(payload) + 1;
+        if (xs.unwatch(xs_guest, payload, arg2)) {
+            xen_reply(msg, msg->type, NULL, 0);
+        } else {
+            xen_reply_str(msg, XS_ERROR, "EINVAL");
+        }
+        break;
+    case XS_TRANSACTION_START:
+        snprintf(id, sizeof(id), "%u", xs.transaction_start(xs_guest));
+        xen_reply_str(msg, msg->type, id);
+        break;
+    case XS_TRANSACTION_END:
+        if (payload[0] == 'T') {
+            /* commit */
+            rc = xs.transaction_end(xs_guest, msg->tx_id, 0);
+        } else if (payload[0] == 'F') {
+            /* abort */
+            rc = xs.transaction_end(xs_guest, msg->tx_id, 1);
+        } else {
+            /* Huh? */
+            xen_reply_str(msg, XS_ERROR, "EINVAL");
+            break;
+        }
+        if (rc) {
+            xen_reply(msg, msg->type, NULL, 0);
+        } else {
+            xen_reply_str(msg, XS_ERROR, "EINVAL");
+        }
+        break;
+    case XS_RM:
+        if (xs.rm(xs_guest, msg->tx_id, payload)) {
+            xen_reply(msg, msg->type, NULL, 0);
+        } else {
+            xen_reply_str(msg, XS_ERROR, "EINVAL");
+        }
+        break;
+    default:
+        fprintf(stderr, "xs guest: unknown msg type %d, payload %d\n",
+                msg->type, msg->len);
+        xen_reply_str(msg, XS_ERROR, "EIO");
+        break;
+    }
+    return sizeof(*msg) + msg->len;
+}
+
+static void xen_store_evtchn_event(void *opaque)
+{
+    struct xenstore_domain_interface *di = get_xdf();
+    evtchn_port_t port;
+    int rc;
+
+    port = xc_evtchn.pending(evtchndev);
+    if (port != evtchnport) {
+        fprintf(stderr,"%s: xc_evtchn.pending returned %d (expected %d)\n",
+                __FUNCTION__, port, evtchnport );
+        return;
+    }
+    xc_evtchn.unmask(evtchndev, port);
+
+    rc = domain_read(di, xs_buf + xs_len, sizeof(xs_buf) - xs_len);
+    if (rc <= 0) {
+        if (backlog) {
+            backlog_shift(di, NULL, 0);
+        }
+        return;
+    }
+    xs_len += rc;
+    if (debug) {
+        fprintf(stderr, "%s: got %d bytes\n", __FUNCTION__, rc);
+    }
+
+    rc = domain_read(di, xs_buf + xs_len, sizeof(xs_buf) - xs_len);
+    if (rc > 0) {
+        xs_len += rc;
+        if (debug) {
+            fprintf(stderr, "%s: got %d bytes (ring wrap, part #2)\n", __FUNCTION__, rc);
+        }
+    }
+
+    for (;;) {
+        rc = xen_handle_data(xs_buf, xs_len);
+        if (!rc) {
+            break;
+        }
+        if (rc == xs_len) {
+            xs_len = 0;
+            break;
+        }
+        memmove(xs_buf, xs_buf + rc, xs_len - rc);
+        xs_len -= rc;
+    }
+}
+
+static void xen_store_watch_event(void *opaque)
+{
+    char **vec;
+    unsigned int len = 1;
+
+    vec = xs.read_watch(xs_guest, &len);
+    if (!vec) {
+        return;
+    }
+    xen_reply_vec(NULL, XS_WATCH_EVENT, vec, 2);
+}
+
+/* ------------------------------------------------------------- */
+
+void xenner_guest_store_setup(uint64_t guest_mfn, evtchn_port_t guest_evtchn)
+{
+    xen_store_mfn = guest_mfn;
+
+    /* xenstore event channel */
+    evtchndev = xc_evtchn.open();
+    evtchnport = xc_evtchn.bind_interdomain(evtchndev, xen_domid,
+                                            guest_evtchn);
+    qemu_set_fd_handler(xc_evtchn.fd(evtchndev),
+                        xen_store_evtchn_event, NULL, NULL);
+
+    /* guest connection to xenstore  */
+    xs_guest = xs.daemon_open();
+    xs.domid(xs_guest, xen_domid);
+    qemu_set_fd_handler(xs.fileno(xs_guest),
+                        xen_store_watch_event, NULL, NULL);
+}
+
+/* this clears guest watches */
+void xenner_guest_store_reset(void)
+{
+    /* close */
+    qemu_set_fd_handler(xs.fileno(xs_guest), NULL, NULL, NULL);
+    xs.daemon_close(xs_guest);
+
+    /* reopen */
+    xs_guest = xs.daemon_open();
+    xs.domid(xs_guest, xen_domid);
+    qemu_set_fd_handler(xs.fileno(xs_guest),
+                        xen_store_watch_event, NULL, NULL);
+}
diff --git a/hw/xenner_libxenstore.c b/hw/xenner_libxenstore.c
new file mode 100644
index 0000000..4110a13
--- /dev/null
+++ b/hw/xenner_libxenstore.c
@@ -0,0 +1,709 @@
+/*
+ *  Copyright (C) Red Hat 2007
+ *  Copyright (C) Novell Inc. 2010
+ *
+ *  Author(s): Gerd Hoffmann <kraxel@redhat.com>
+ *             Alexander Graf <agraf@suse.de>
+ *
+ *  Xenner Core -- xenstored
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "xen.h"
+#include "xen_interfaces.h"
+#include "qemu-char.h"
+#include "console.h"
+#include "monitor.h"
+
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+#define XS_PATH_MAX 256
+
+struct node {
+    char                *path;
+    struct node         *parent;
+    char                *value;
+    int                 len;
+    int                 is_dir;
+    QTAILQ_ENTRY(node)  list;
+};
+static QTAILQ_HEAD(node_head, node) nodes = QTAILQ_HEAD_INITIALIZER(nodes);
+
+struct watch {
+    struct xs_handle    *who;
+    char                *path;
+    char                *token;
+    int                 offset;
+    QTAILQ_ENTRY(watch) list;
+};
+static QTAILQ_HEAD(watch_head, watch) watches = QTAILQ_HEAD_INITIALIZER(watches);
+
+struct event {
+    char                **vec;
+    QTAILQ_ENTRY(event)  list;
+};
+
+struct xs_handle {
+    int                 fd_read;
+    int                 fd_write;
+    int                 domid;
+    QTAILQ_HEAD(event_head, event) events;
+};
+
+/* ------------------------------------------------------------- */
+
+static struct node *node_find(const char *path)
+{
+    struct node *node;
+
+    QTAILQ_FOREACH(node, &nodes, list) {
+        if (!strcmp(path, node->path)) {
+            /* move to head of list */
+            QTAILQ_REMOVE(&nodes, node, list);
+            QTAILQ_INSERT_HEAD(&nodes, node, list);
+            return node;
+        }
+    }
+    return NULL;
+}
+
+static struct node *node_add(struct node *parent, const char *path)
+{
+    struct node *node;
+
+    node = qemu_mallocz(sizeof(*node));
+    if (!node) {
+        goto err;
+    }
+    node->path = qemu_strdup(path);
+    if (!node->path) {
+        goto err;
+    }
+    node->parent = parent;
+    QTAILQ_INSERT_HEAD(&nodes, node, list);
+    return node;
+
+err:
+    qemu_free(node);
+    return NULL;
+}
+
+static void node_del(struct node *node)
+{
+    struct node *child;
+    int found_child;
+
+    do {
+        found_child = 0;
+        QTAILQ_FOREACH(child, &nodes, list) {
+            if (child->parent != node) {
+                continue;
+            }
+            found_child = 1;
+            node_del(child);
+            break;
+        }
+    } while (found_child);
+
+    if (debug) {
+        fprintf(stderr, "%s: %s\n", __FUNCTION__, node->path);
+    }
+    QTAILQ_REMOVE(&nodes, node, list);
+    qemu_free(node->path);
+    qemu_free(node->value);
+    qemu_free(node);
+}
+
+static void node_path(struct xs_handle *h, const char *path, char *dest, int len)
+{
+    if (path[0] == '/') {
+        snprintf(dest, len, "%s", path);
+    } else {
+        snprintf(dest, len, "/local/domain/%d/%s",
+                 h->domid, path);
+    }
+}
+
+static void parent_path(struct xs_handle *h, const char *path, char *dest, int len)
+{
+    char *c;
+
+    node_path(h, path, dest, len);
+    c = strrchr(dest, '/');
+    if (c) {
+        if (c == dest && c[1]) {
+            c++;
+        }
+        *c = 0;
+    }
+}
+
+static void fire_watch(struct node *node, struct watch *watch)
+{
+    struct event *event;
+    char *path, *token, *dst, byte = 0;
+    int r;
+
+    path  = node->path + watch->offset;
+    token = watch->token;
+
+    event = qemu_mallocz(sizeof(*event));
+    if (!event) {
+        return;
+    }
+    event->vec = qemu_malloc(sizeof(char*)*2 +
+                             strlen(path)    +
+                             strlen(token)   +
+                             2);
+    if (!event->vec) {
+        qemu_free(event);
+        return;
+    }
+    dst = (void*)(event->vec+2);
+    event->vec[0] = dst;
+    strcpy(dst, path);
+    dst += strlen(path)+1;
+    event->vec[1] = dst;
+    strcpy(dst, token);
+
+    QTAILQ_INSERT_TAIL(&watch->who->events, event, list);
+    r = write(watch->who->fd_write, &byte, 1);
+}
+
+static void fire_watches(struct node *node)
+{
+    struct watch *watch;
+    int nlen,wlen;
+
+    nlen = strlen(node->path);
+    QTAILQ_FOREACH(watch, &watches, list) {
+        wlen = strlen(watch->path);
+        if (wlen > nlen) {
+            continue;
+        }
+        if (strncmp(watch->path, node->path, wlen)) {
+            continue;
+        }
+        fire_watch(node, watch);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static struct xs_handle *_qemu_open(void)
+{
+    struct xs_handle *h;
+    int fd[2];
+
+    h = qemu_mallocz(sizeof(*h));
+    if (!h) {
+        goto err;
+    }
+
+    if (pipe(fd)) {
+        goto err;
+    }
+    h->fd_read  = fd[0];
+    h->fd_write = fd[1];
+    QTAILQ_INIT(&h->events);
+    return h;
+
+err:
+    qemu_free(h);
+    return NULL;
+}
+
+static int qemu_domid(struct xs_handle *h, int domid)
+{
+    h->domid = domid;
+    return 0;
+}
+
+static void qemu_close(struct xs_handle *h)
+{
+    struct watch *watch, *check;
+    struct event *event;
+
+    watch = QTAILQ_FIRST(&watches);
+    while (watch) {
+        check = watch;
+        watch = QTAILQ_NEXT(watch, list);
+        if (h != check->who) {
+            continue;
+        }
+        QTAILQ_REMOVE(&watches, check, list);
+        free(check);
+    }
+
+    while ((event = QTAILQ_FIRST(&h->events))) {
+        QTAILQ_REMOVE(&h->events, event, list);
+        free(event->vec);
+        free(event);
+    }
+
+    close(h->fd_read);
+    close(h->fd_write);
+    qemu_free(h);
+}
+
+static char **qemu_directory(struct xs_handle *h, xs_transaction_t t,
+                             const char *path, unsigned int *num)
+{
+    char npath[XS_PATH_MAX];
+    struct node *parent, *node;
+    int i,pos,size,plen,nlen;
+    char **vec, *dst, *name;
+
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s\n", __FUNCTION__, path);
+    }
+    node_path(h, path, npath, sizeof(npath));
+    plen = strlen(npath);
+    parent = node_find(npath);
+    if (!parent) {
+        return NULL;
+    }
+    if (!parent->is_dir) {
+        return NULL;
+    }
+
+    /* count */
+    *num = 0;
+    size = 0;
+    QTAILQ_FOREACH(node, &nodes, list) {
+        if (node->parent != parent) {
+            continue;
+        }
+        name = node->path + plen + 1;
+        nlen = strlen(name)+1;
+        (*num)++;
+        size += nlen;
+    }
+    if (!*num) {
+        return NULL;
+    }
+
+    /* alloc memory */
+    vec = qemu_malloc(*num * sizeof(char*) + size);
+    dst = (void*)(vec + (*num));
+
+    /* fill data */
+    i = 0;
+    pos = 0;
+    QTAILQ_FOREACH(node, &nodes, list) {
+        if (node->parent != parent) {
+            continue;
+        }
+        name = node->path + plen + 1;
+        nlen = strlen(name)+1;
+        vec[i] = dst + pos;
+        memcpy(vec[i], name, nlen);
+        i++;
+        pos += nlen;
+    }
+    return vec;
+}
+
+static void *qemu_read(struct xs_handle *h, xs_transaction_t t,
+                       const char *path, unsigned int *len)
+{
+    char npath[XS_PATH_MAX];
+    struct node *node;
+    char *ret;
+
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s\n", __FUNCTION__, path);
+    }
+    node_path(h, path, npath, sizeof(npath));
+    node = node_find(npath);
+    if (!node) {
+        *len = 0;
+        return NULL;
+    }
+    ret = qemu_malloc(node->len+1);
+    memcpy(ret, node->value, node->len);
+    ret[node->len] = 0;
+    *len = node->len;
+    return ret;
+}
+
+static bool qemu_mkdir(struct xs_handle *h, xs_transaction_t t,
+                       const char *path)
+{
+    char npath[XS_PATH_MAX], ppath[XS_PATH_MAX];
+    struct node *node;
+
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s\n", __FUNCTION__, path);
+    }
+    node_path(h, path, npath, sizeof(npath));
+    node = node_find(npath);
+    if (node) {
+        return node->is_dir ? true : false;
+    }
+    parent_path(h, path, ppath, sizeof(ppath));
+    if (strlen(ppath)) {
+        node = node_find(ppath);
+        if (!node) {
+            if (!qemu_mkdir(h, t, ppath)) {
+                return false;
+            }
+            node = node_find(ppath);
+        }
+    } else {
+        node = NULL;
+    }
+    node = node_add(node, npath);
+    if (!node) {
+        return false;
+    }
+    node->is_dir = 1;
+    fire_watches(node);
+    return true;
+}
+
+static bool qemu_write(struct xs_handle *h, xs_transaction_t t,
+                       const char *path, const void *data, unsigned int len)
+{
+    char npath[XS_PATH_MAX], ppath[XS_PATH_MAX];
+    struct node *node;
+
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s = %.*s\n", __FUNCTION__, path, len, (char*)data);
+    }
+    node_path(h, path, npath, sizeof(npath));
+    if (h->domid != 0) {
+        /* simple access control: guest can write to its own tree only */
+        int domid;
+        if (sscanf(npath, "/local/domain/%d", &domid) != 1) {
+            fprintf(stderr, "deny guest access: %s\n", npath);
+            return false;
+        }
+        if (domid != h->domid) {
+            fprintf(stderr, "deny guest access (domid %d): %s\n", h->domid, npath);
+            return false;
+        }
+    }
+    node = node_find(npath);
+    if (!node) {
+        parent_path(h, path, ppath, sizeof(ppath));
+        node = node_find(ppath);
+        if (!node) {
+            if (!qemu_mkdir(h, t, ppath)) {
+                return false;
+            }
+            node = node_find(ppath);
+        }
+        if (!node->is_dir) {
+            return false;
+        }
+        node = node_add(node, npath);
+    }
+    node->len = 0;
+    qemu_free(node->value);
+    if (len) {
+        node->value = qemu_malloc(len);
+        if (!node->value) {
+            return false;
+        }
+    }
+    node->len = len;
+    memcpy(node->value, data, len);
+    if (debug) {
+        fprintf(stderr, "xs: new value: %s = %.*s (%d)\n",
+                npath, len, (char*)data, len);
+    }
+    fire_watches(node);
+    return true;
+}
+
+static bool qemu_rm(struct xs_handle *h, xs_transaction_t t,
+                    const char *path)
+{
+    char npath[XS_PATH_MAX];
+    struct node *node;
+
+    if (debug) {
+        fprintf(stderr, "xs: %s: %s\n", __FUNCTION__, path);
+    }
+
+    node_path(h, path, npath, sizeof(npath));
+    node = node_find(npath);
+    if (node) {
+        fire_watches(node);
+        node_del(node);
+    }
+    return false;
+}
+
+static struct xs_permissions *qemu_get_permissions(struct xs_handle *h,
+                                                   xs_transaction_t t,
+                                                   const char *path, unsigned int *num)
+{
+    /* we don't implement permissions */
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s\n", __FUNCTION__, path);
+    }
+    return NULL;
+}
+
+static bool qemu_set_permissions(struct xs_handle *h, xs_transaction_t t,
+                                 const char *path, struct xs_permissions *perms,
+                                 unsigned int num_perms)
+{
+    /* we don't implement permissions */
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s\n", __FUNCTION__, path);
+    }
+    return true;
+}
+
+static bool qemu_watch(struct xs_handle *h, const char *path, const char *token)
+{
+    char npath[XS_PATH_MAX];
+    struct node *node;
+    struct watch *w;
+
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s: %s token %s\n", __FUNCTION__, path, token);
+    }
+    node_path(h, path, npath, sizeof(npath));
+    w = qemu_mallocz(sizeof(*w));
+    if (!w) {
+        goto err;
+    }
+    w->path = qemu_strdup(npath);
+    if (!w->path) {
+        goto err;
+    }
+    w->token = qemu_strdup(token);
+    if (!w->token) {
+        goto err;
+    }
+    w->who = h;
+    if (path[0] != '/') {
+        /* relative path offset */
+        w->offset = strlen(npath) - strlen(path);
+    }
+    QTAILQ_INSERT_TAIL(&watches, w, list);
+    if (debug) {
+        fprintf(stderr, "xs: new watch: %s (rel %s, token %s)\n",
+                w->path, w->offset ? w->path + w->offset : "-", w->token);
+    }
+    node = node_find(npath);
+    if (node) {
+        fire_watch(node, w);
+    }
+    return true;
+
+err:
+    if (w) {
+        qemu_free(w->path);
+        qemu_free(w->token);
+        qemu_free(w);
+    }
+    return false;
+}
+
+static int qemu_fileno(struct xs_handle *h)
+{
+    return h->fd_read;
+}
+
+static char **qemu_read_watch(struct xs_handle *h, unsigned int *num)
+{
+    struct event *event;
+    char **vec;
+    char byte;
+    int r;
+
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s\n", __FUNCTION__);
+    }
+    r = read(h->fd_read, &byte, 1);
+    if (QTAILQ_EMPTY(&h->events)) {
+        fprintf(stderr, "%s: Huh? fd readable but no event in list?\n",
+                __FUNCTION__);
+        return NULL;
+    }
+    event = QTAILQ_FIRST(&h->events);
+    if (debug) {
+        fprintf(stderr, "xs: get event: %s %s\n",
+                event->vec[0], event->vec[1]);
+    }
+    vec = event->vec;
+    QTAILQ_REMOVE(&h->events, event, list);
+    qemu_free(event);
+    *num = 1;
+    return vec;
+}
+
+static bool qemu_unwatch(struct xs_handle *h, const char *path, const char *token)
+{
+    struct watch *watch;
+
+    QTAILQ_FOREACH(watch, &watches, list) {
+        if (strcmp(watch->path + watch->offset, path)) {
+            continue;
+        }
+        if (strcmp(watch->token, token)) {
+            continue;
+        }
+        QTAILQ_REMOVE(&watches, watch, list);
+        qemu_free(watch->path);
+        qemu_free(watch->token);
+        qemu_free(watch);
+        return true;
+    }
+    return false;
+}
+
+static xs_transaction_t qemu_transaction_start(struct xs_handle *h)
+{
+    /* Note: transactions are not implemented */
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s\n", __FUNCTION__);
+    }
+    return 42;
+}
+
+static bool qemu_transaction_end(struct xs_handle *h, xs_transaction_t t,
+                                 bool abort)
+{
+    /* Note: transactions are not implemented */
+    if (debug > 1) {
+        fprintf(stderr, "xs: %s\n", __FUNCTION__);
+    }
+    return true;
+}
+
+static bool qemu_introduce_domain(struct xs_handle *h,
+                                  unsigned int domid,
+                                  unsigned long mfn,
+                                  unsigned int eventchn)
+{
+    /* not needed for us */
+    fprintf(stderr, "xs: %s: not implemented\n", __FUNCTION__);
+    return false;
+}
+
+static bool qemu_resume_domain(struct xs_handle *h, unsigned int domid)
+{
+    /* not needed for us */
+    fprintf(stderr, "xs: %s: not implemented\n", __FUNCTION__);
+    return false;
+}
+
+static bool qemu_release_domain(struct xs_handle *h, unsigned int domid)
+{
+    /* not needed for us */
+    fprintf(stderr, "xs: %s: not implemented\n", __FUNCTION__);
+    return false;
+}
+
+static char *qemu_get_domain_path(struct xs_handle *h, unsigned int domid)
+{
+    char *path;
+
+    path = malloc(32);
+    if (!path) {
+        return NULL;
+    }
+    snprintf(path, 32, "/local/domain/%d", domid);
+    return path;
+}
+
+static bool qemu_is_domain_introduced(struct xs_handle *h, unsigned int domid)
+{
+    /* not needed for us */
+    fprintf(stderr, "xs: %s: not implemented\n", __FUNCTION__);
+    return false;
+}
+
+struct XenStoreOps xs_xenner = {
+    .daemon_open           = _qemu_open,
+    .domain_open           = _qemu_open,
+    .daemon_open_readonly  = _qemu_open,
+    .domid                 = qemu_domid,
+    .daemon_close          = qemu_close,
+    .directory             = qemu_directory,
+    .read                  = qemu_read,
+    .write                 = qemu_write,
+    .mkdir                 = qemu_mkdir,
+    .rm                    = qemu_rm,
+    .get_permissions       = qemu_get_permissions,
+    .set_permissions       = qemu_set_permissions,
+    .watch                 = qemu_watch,
+    .fileno                = qemu_fileno,
+    .read_watch            = qemu_read_watch,
+    .unwatch               = qemu_unwatch,
+    .transaction_start     = qemu_transaction_start,
+    .transaction_end       = qemu_transaction_end,
+    .introduce_domain      = qemu_introduce_domain,
+    .resume_domain         = qemu_resume_domain,
+    .release_domain        = qemu_release_domain,
+    .get_domain_path       = qemu_get_domain_path,
+    .is_domain_introduced  = qemu_is_domain_introduced,
+};
+
+/* ------------------------------------------------------------- */
+
+#if 0
+
+static void print_node(Monitor *mon, struct node *node, int indent)
+{
+    struct node *child;
+    int width;
+    char *name;
+
+    width = 40 - indent;
+    name = strrchr(node->path,'/');
+    if (strcmp(name, "/")) {
+        name++;
+    }
+    monitor_printf(mon, "%*s%-*.*s = ", indent, "", width, width, name);
+    if (node->is_dir) {
+        monitor_printf(mon,"<DIR>\n");
+        QTAILQ_FOREACH(child, &nodes, list) {
+            if (child->parent != node) {
+                continue;
+            }
+            print_node(mon, child, indent+2);
+        }
+    } else {
+        monitor_printf(mon, "\"%.*s\"\n", node->len, node->value);
+    }
+}
+
+void do_info_xenstore(Monitor *mon)
+{
+    struct node *root;
+
+    if (xen_mode != XEN_EMULATE) {
+        monitor_printf(mon, "Not emulating xenstore (use /usr/bin/xenstore-ls).\n");
+        return;
+    }
+    root = node_find("/");
+    if (!root) {
+        monitor_printf(mon, "Xenstore is empty.\n");
+        return;
+    }
+    print_node(mon, root, 0);
+}
+
+#endif
+
-- 
1.6.0.2

  parent reply	other threads:[~2010-11-01 15:02 UTC|newest]

Thread overview: 96+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-01 15:01 [Qemu-devel] [PATCH 00/40] RFC: Xenner Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 01/40] elf: Move translate_fn to helper struct Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 02/40] elf: Add notes implementation Alexander Graf
2010-11-01 18:29   ` Blue Swirl
2010-11-01 18:42     ` Stefan Weil
2010-11-01 19:51       ` Alexander Graf
2010-11-01 20:19         ` Stefan Weil
2010-11-01 21:17           ` Alexander Graf
2010-11-01 21:28             ` [Qemu-devel] " Paolo Bonzini
2010-11-01 21:31             ` [Qemu-devel] " Stefan Weil
2010-11-02 10:17             ` Michael Matz
2010-11-01 18:41   ` [Qemu-devel] " Paolo Bonzini
2010-11-01 18:52     ` Alexander Graf
2010-11-01 19:43       ` Paolo Bonzini
2010-11-01 19:48         ` Alexander Graf
2010-11-01 21:23           ` Paolo Bonzini
2010-11-01 15:01 ` [Qemu-devel] [PATCH 03/40] elf: add header notification Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 04/40] elf: add section analyzer Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 05/40] xen-disk: disable aio Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 06/40] qdev-ify: xen backends Alexander Graf
2010-11-02 10:08   ` Markus Armbruster
2010-11-02 10:43     ` Gerd Hoffmann
2010-11-02 13:26       ` Markus Armbruster
2010-11-01 15:01 ` [Qemu-devel] [PATCH 07/40] xenner: kernel: 32 bit files Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 08/40] xenner: kernel: 64-bit files Alexander Graf
2010-11-01 15:44   ` Anthony Liguori
2010-11-01 15:47     ` Alexander Graf
2010-11-01 15:59       ` Anthony Liguori
2010-11-01 19:00       ` Blue Swirl
2010-11-01 19:02         ` Anthony Liguori
2010-11-01 19:05           ` Alexander Graf
2010-11-01 19:23             ` Blue Swirl
2010-11-01 19:37             ` Anthony Liguori
2010-11-01 15:01 ` [Qemu-devel] [PATCH 09/40] xenner: kernel: Global data Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 10/40] xenner: kernel: Hypercall handler (i386) Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 11/40] xenner: kernel: Hypercall handler (x86_64) Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 12/40] xenner: kernel: Hypercall handler (generic) Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 13/40] xenner: kernel: Headers Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 14/40] xenner: kernel: Instruction emulator Alexander Graf
2010-11-01 15:41   ` malc
2010-11-01 18:46   ` [Qemu-devel] " Paolo Bonzini
2010-11-01 15:01 ` [Qemu-devel] [PATCH 15/40] xenner: kernel: lapic code Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 16/40] xenner: kernel: Main (i386) Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 17/40] xenner: kernel: Main (x86_64) Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 18/40] xenner: kernel: Main Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 19/40] xenner: kernel: Makefile Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 20/40] xenner: kernel: mmu support for 32-bit PAE Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 21/40] xenner: kernel: mmu support for 32-bit normal Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 22/40] xenner: kernel: mmu support for 64-bit Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 23/40] xenner: kernel: generic MM functionality Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 24/40] xenner: kernel: printk Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 25/40] xenner: kernel: KVM PV code Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 26/40] xenner: kernel: xen-names Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 27/40] xenner: add xc_dom.h Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 28/40] xenner: libxc emu: evtchn Alexander Graf
2010-11-01 15:45   ` Anthony Liguori
2010-11-01 15:49     ` Alexander Graf
2010-11-01 16:01       ` Anthony Liguori
2010-11-01 16:07         ` Alexander Graf
2010-11-01 16:14           ` Anthony Liguori
2010-11-01 16:15             ` Alexander Graf
2010-11-01 19:39         ` [Qemu-devel] " Paolo Bonzini
2010-11-01 19:41           ` Anthony Liguori
2010-11-01 19:47             ` Alexander Graf
2010-11-01 20:32               ` Anthony Liguori
2010-11-01 21:47                 ` Paolo Bonzini
2010-11-01 22:00                   ` Anthony Liguori
2010-11-01 22:08                     ` Paolo Bonzini
2010-11-01 22:29                       ` Anthony Liguori
2010-11-02  4:33                 ` Stefano Stabellini
2010-11-02 10:06                   ` Paolo Bonzini
2010-11-02 10:31                     ` Gerd Hoffmann
2010-11-02 10:38                       ` Paolo Bonzini
2010-11-02 13:55                     ` Stefano Stabellini
2010-11-02 15:48                       ` Alexander Graf
2010-11-02 19:20                         ` Stefano Stabellini
2010-11-01 15:01 ` [Qemu-devel] [PATCH 29/40] xenner: libxc emu: grant tables Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 30/40] xenner: libxc emu: memory mapping Alexander Graf
2010-11-01 15:12   ` malc
2010-11-01 15:15     ` Alexander Graf
2010-11-01 15:01 ` Alexander Graf [this message]
2010-11-01 18:36   ` [Qemu-devel] [PATCH 31/40] xenner: libxc emu: xenstore Blue Swirl
2010-11-01 15:01 ` [Qemu-devel] [PATCH 32/40] xenner: emudev Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 33/40] xenner: core Alexander Graf
2010-11-01 15:13   ` malc
2010-11-01 15:01 ` [Qemu-devel] [PATCH 34/40] xenner: PV machine Alexander Graf
2010-11-01 15:01 ` [Qemu-devel] [PATCH 35/40] xenner: Domain Builder Alexander Graf
2010-11-02 10:09   ` [Qemu-devel] " Paolo Bonzini
2010-11-02 15:36     ` Alexander Graf
2010-11-02 15:51       ` Paolo Bonzini
2010-11-02 16:28         ` Alexander Graf
2010-11-01 15:21 ` [Qemu-devel] [PATCH 00/40] RFC: Xenner Alexander Graf
2010-11-02 16:26 ` [Qemu-devel] [PATCH 36/40] xen: only create dummy env when necessary Alexander Graf
2010-11-02 16:26 ` [Qemu-devel] [PATCH 38/40] xenner: integrate into build system Alexander Graf
2010-11-02 16:26 ` [Qemu-devel] [PATCH 39/40] xenner: integrate into xen pv machine Alexander Graf
2010-11-02 16:26 ` [Qemu-devel] [PATCH 40/40] xen: add sysrq support Alexander Graf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1288623713-28062-32-git-send-email-agraf@suse.de \
    --to=agraf@suse.de \
    --cc=kraxel@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.