]> xenbits.xensource.com Git - osstest/rumprun.git/commitdiff
librumpxen_xendev: xenbus: Reorganise to split minios from rumpkernel parts
authorIan Jackson <ian.jackson@eu.citrix.com>
Wed, 5 Oct 2016 15:30:59 +0000 (16:30 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Fri, 7 Oct 2016 17:39:22 +0000 (18:39 +0100)
Split the xenbus driver into two pieces, busdev.c (in the netbsd
kernel namespacve) and busdev_user.c (in the minios namespace).  They
communicate via the (somewhat ad-hoc) interface in busdev_user.h.  The
interface uses `rumpxenbus_*' names so that the two sides can call
each other.  We split the state structure up into three: a netbsd
part, a minios part, and a common part.

This is actually largely a combination of code motion and function and
type renaming.  There is little functional change from the previous
"header abuse" approach, other than some minor interface adjustments.

In much of the code `d' was used to refer to the device struct.  Now
there are three context stucts.  For now I have retained in each
function the use of `d' which producese the lowest amount of code
churn.  The compiler makes sure the types all line up right.

Later, the uses of `d' will each be changed to `dc', `du' or `dd'.

Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
platform/xen/librumpxen_xendev/Makefile
platform/xen/librumpxen_xendev/busdev.c
platform/xen/librumpxen_xendev/busdev_user.c [new file with mode: 0644]
platform/xen/librumpxen_xendev/busdev_user.h [new file with mode: 0644]
platform/xen/librumpxen_xendev/rumpxen_xendev.h

index b9fd0f937a12f103bf7d26464fbe94f46b24bafa..1aeadacd4042858cc9dd51437b3e5540d2257d1b 100644 (file)
@@ -1,3 +1,5 @@
+.include <bsd.own.mk>
+
 LIB=   rumpxen_xendev
 
 SRCS=  xendev_component.c
@@ -9,16 +11,16 @@ RUMPTOP= ${TOPRUMP}
 
 CPPFLAGS+=     -I${RUMPTOP}/librump/rumpkern -I${RUMPTOP}/librump
 CPPFLAGS+=     -I${RUMPTOP}/librump/rumpvfs
+CPPFLAGS+=     -I${.CURDIR}/../xen/include
 CPPFLAGS+=     -I${.CURDIR}
-CPPFLAGS+=     -I${.CURDIR}/../xen/include -D__RUMP_KERNEL__ -I${.CURDIR}/..
-CPPFLAGS+=     -I${.CURDIR}/../../../include
 
-.if ${BUILDRR:Uno} == "true"
-.include "${RUMPRUN_MKCONF}"
-CPPFLAGS+=     -I${OBJDIR}/dest.stage/include
-.endif
+RUMPCOMP_USER_SRCS=    busdev_user.c
+RUMPCOMP_USER_CPPFLAGS+= -I${.CURDIR}/..
+RUMPCOMP_USER_CPPFLAGS+= -I${.CURDIR}/../xen/include
+RUMPCOMP_USER_CPPFLAGS+= -I${.CURDIR}/../../../include
 
-RUMP_SYM_NORENAME=xenbus_|HYPERVISOR_|minios_|bmk_
+# XXX
+.undef RUMPKERN_ONLY
 
 .include "${RUMPTOP}/Makefile.rump"
 .include <bsd.lib.mk>
index f731e821890dc8a92dc131a9daa58e0b858512e1..b7d74ad93682cea538d3b6c43bb487549c19370a 100644 (file)
@@ -59,57 +59,16 @@ __KERNEL_RCSID(0, "$NetBSD: $");
 
 #include "rumpxen_xendev.h"
 
-#include <bmk-rumpuser/rumpuser.h>
-
-#define BUFFER_SIZE (XENSTORE_PAYLOAD_MAX+sizeof(struct xsd_sockmsg))
-
 #include <xen/io/xs_wire.h>
 
-#include <mini-os/xenbus.h>
-#include <mini-os/wait.h>
-
-/*----- data structures -----*/
+#include "busdev_user.h"
 
-struct xenbus_dev_request {
-       struct xenbus_event xb;
-       uint32_t xb_id, user_id;
-       uint32_t req_type;
-       union {
-               struct xenbus_dev_transaction *trans;
-               struct xenbus_dev_watch *watch;
-       } u;
-};
-
-struct xenbus_dev_transaction {
-       LIST_ENTRY(xenbus_dev_transaction) entry;
-       xenbus_transaction_t tx_id;
-       struct xenbus_dev_request destroy;
-};
-
-struct xenbus_dev_watch {
-       struct xenbus_watch xb;
-       LIST_ENTRY(xenbus_dev_watch) entry;
-       struct xsd_sockmsg *wmsg;
-       char *path, *user_token;
-       _Bool visible_to_user;
-       struct xenbus_dev_request destroy;
-};
-
-struct xenbus_dev_data {
+struct rumpxenbus_data_dev {
        kmutex_t lock;
-       int outstanding_requests;
-       LIST_HEAD(, xenbus_dev_transaction) transactions;
-       LIST_HEAD(, xenbus_dev_watch) watches;
-       struct xenbus_event_queue replies; /* Entirely unread by user. */
 
-       _Bool queued_enomem, want_restart;
+       _Bool want_restart;
 
-       /* Partially written request(s). */
-       unsigned int wbuf_used;
-       union {
-               struct xsd_sockmsg msg;
-               unsigned char buffer[BUFFER_SIZE];
-       } wbuf;
+       struct rumpxenbus_data_common dc;
 
        /* Partially read response. */
        struct xsd_sockmsg *rmsg; /* .id==user_id; data follows */
@@ -121,264 +80,38 @@ struct xenbus_dev_data {
         * is xenbus_req_lock, not d->lock. */
 };
 
-/*----- helpers -----*/
 
-static void
-free_watch(struct xenbus_dev_watch *watch)
-{
-       xbd_free(watch->path);
-       xbd_free(watch->user_token);
-       xbd_free(watch);
-}
-
-static struct xenbus_dev_transaction*
-find_transaction(struct xenbus_dev_data *d, xenbus_transaction_t id)
-{
-       struct xenbus_dev_transaction *trans;
-
-       LIST_FOREACH(trans, &d->transactions, entry)
-               if (trans->tx_id == d->wbuf.msg.tx_id)
-                       return trans;
-       /* not found */
-       return 0;
-}
-
-static struct xenbus_dev_watch*
-find_visible_watch(struct xenbus_dev_data *d,
-                  const char *path, const char *token)
-{
-       struct xenbus_dev_watch *watch;
-
-       LIST_FOREACH(watch, &d->watches, entry)
-               if (watch->visible_to_user &&
-                   !strcmp(path, watch->path) &&
-                   !strcmp(token, watch->user_token))
-                       return watch;
-       /* not found */
-       return 0;
-}
-
-/*----- request handling (writes to the device) -----*/
-
-static void
-make_request(struct xenbus_dev_data *d, struct xenbus_dev_request *req,
-            uint32_t tx_id, const struct write_req *wreqs, int num_wreqs)
-/* Caller should have filled in req->req_id, ->u, and (if needed)
- * ->user_id.  We deal with ->xb and ->xb_id. */
-{
-       req->xb.watch = 0;
-       req->xb_id = xenbus_id_allocate(&d->replies, &req->xb);
-
-       KASSERT(d->outstanding_requests < INT_MAX);
-       d->outstanding_requests++;
-
-       xenbus_xb_write(req->req_type, req->xb_id, tx_id,
-                       wreqs, num_wreqs);
-}
-
-static void
-watch_write_req_string(struct write_req **wreqp, const char *string)
-{
-       struct write_req *wreq = (*wreqp)++;
-       int l = strlen(string);
-       wreq->len = l+1;
-       wreq->data = string;
-}
-
-static void
-make_watch_request(struct xenbus_dev_data *d, struct xenbus_dev_request *req,
-                  uint32_t tx_id, struct xenbus_dev_watch *watch)
-{
-       struct write_req wreqs[2], *wreq = wreqs;
-       watch_write_req_string(&wreq, watch->path);
-       watch_write_req_string(&wreq, watch->xb.token);
-       KASSERT((char*)wreq == (char*)wreqs + sizeof(wreqs));
-
-       req->u.watch = watch;
-       make_request(d, req, tx_id, wreqs, 2);
-}
-
-static void
-write_trouble(struct xenbus_dev_data *d, const char *what)
+void
+rumpxenbus_write_trouble(struct rumpxenbus_data_common *dc, const char *what)
 {
        printf("xenbus dev: bad write: %s\n", what);
 
 #ifdef RUMP_DEV_XEN_DEBUG
        {
                unsigned int i;
-               printf(" %d bytes:", d->wbuf_used);
-               for (i=0; i<d->wbuf_used; i++) {
+               printf(" %d bytes:", dc->wbuf_used);
+               for (i=0; i<dc->wbuf_used; i++) {
                        if (!(i & 3)) printf(" ");
-                       printf("%02x", d->wbuf.buffer[i]);
+                       printf("%02x", dc->wbuf.buffer[i]);
                }
                printf(".\n");
        }
 #endif /*RUMP_DEV_XEN_DEBUG*/
 
-       d->wbuf_used = 0; /* discard everything buffered */
-}
-
-/* void __NORETURN__ WTROUBLE(const char *details_without_newline);
- * assumes:   struct xenbus_dev_data *d;
- *            int err;
- *            end: */
-#define WTROUBLE(s) do{ write_trouble(d,s); err = EINVAL; goto end; }while(0)
-
-static void
-forward_request(struct xenbus_dev_data *d, struct xenbus_dev_request *req)
-{
-       struct write_req wreq = {
-               d->wbuf.buffer + sizeof(d->wbuf.msg),
-               d->wbuf_used - sizeof(d->wbuf.msg),
-       };
-
-       make_request(d, req, d->wbuf.msg.tx_id, &wreq, 1);
+       dc->wbuf_used = 0; /* discard everything buffered */
 }
 
-static _Bool
-watch_message_parse_string(const char **p, const char *end,
-                          const char **string_r)
-{
-       const char *nul = memchr(*p, 0, end - *p);
-       if (!nul)
-               return 0;
-
-       *string_r = *p;
-       *p = nul+1;
+/*----- request handling (writes to the device) -----*/
 
-       return 1;
-}
-
-static _Bool
-watch_message_parse(const struct xsd_sockmsg *msg,
-                   const char **path_r, const char **token_r)
-{
-       const char *begin = (const char*)msg;
-       const char *p = begin + sizeof(*msg);
-       const char *end = p + msg->len;
-       KASSERT(p <= end);
-
-       return
-               watch_message_parse_string(&p, end, path_r) &&
-               watch_message_parse_string(&p, end, token_r);
-}
-
-static int
-process_request(struct xenbus_dev_data *d)
-{
-       struct xenbus_dev_request *req;
-       struct xenbus_dev_transaction *trans;
-       struct xenbus_dev_watch *watch_free = 0, *watch;
-       const char *wpath, *wtoken;
-       int err;
-
-       DPRINTF(("/dev/xen/xenbus: request, type=%d\n",
-                d->wbuf.msg.type));
-
-       req = xbd_malloc(sizeof(*req));
-       if (!req) {
-               err = ENOMEM;
-               goto end;
-       }
-       req->user_id = d->wbuf.msg.req_id;
-       req->req_type = d->wbuf.msg.type;
-
-       switch (d->wbuf.msg.type) {
-       case XS_DIRECTORY:
-       case XS_READ:
-       case XS_GET_PERMS:
-       case XS_GET_DOMAIN_PATH:
-       case XS_IS_DOMAIN_INTRODUCED:
-       case XS_WRITE:
-       case XS_MKDIR:
-       case XS_RM:
-       case XS_SET_PERMS:
-               if (d->wbuf.msg.tx_id) {
-                       if (!find_transaction(d, d->wbuf.msg.tx_id))
-                               WTROUBLE("unknown transaction");
-               }
-               forward_request(d, req);
-               break;
-
-       case XS_TRANSACTION_START:
-               if (d->wbuf.msg.tx_id)
-                       WTROUBLE("nested transaction");
-               req->u.trans = xbd_malloc(sizeof(*req->u.trans));
-               if (!req->u.trans) {
-                       err = ENOMEM;
-                       goto end;
-               }
-               forward_request(d, req);
-               break;
-
-       case XS_TRANSACTION_END:
-               if (!d->wbuf.msg.tx_id)
-                       WTROUBLE("ending zero transaction");
-               req->u.trans = trans = find_transaction(d, d->wbuf.msg.tx_id);
-               if (!trans)
-                       WTROUBLE("ending unknown transaction");
-               LIST_REMOVE(trans, entry); /* prevent more reqs using it */
-               forward_request(d, req);
-               break;
-       case XS_WATCH:
-               if (d->wbuf.msg.tx_id)
-                       WTROUBLE("XS_WATCH with transaction");
-               if (!watch_message_parse(&d->wbuf.msg, &wpath, &wtoken))
-                       WTROUBLE("bad XS_WATCH message");
-
-               watch = watch_free = xbd_malloc(sizeof(*watch));
-               if (!watch) {
-                       err = ENOMEM;
-                       goto end;
-               }
-
-               watch->path = xbd_strdup(wpath);
-               watch->user_token = xbd_strdup(wtoken);
-               if (!watch->path || !watch->user_token) {
-                       err = ENOMEM;
-                       goto end;
-               }
-
-               watch->xb.events = &d->replies;
-               xenbus_watch_prepare(&watch->xb);
-
-               watch_free = 0; /* we are committed */
-               watch->visible_to_user = 0;
-               LIST_INSERT_HEAD(&d->watches, watch, entry);
-               make_watch_request(d, req, d->wbuf.msg.tx_id, watch);
-               break;
-
-       case XS_UNWATCH:
-               if (d->wbuf.msg.tx_id)
-                       WTROUBLE("XS_UNWATCH with transaction");
-               if (!watch_message_parse(&d->wbuf.msg, &wpath, &wtoken))
-                       WTROUBLE("bad XS_WATCH message");
-
-               watch = find_visible_watch(d, wpath, wtoken);
-               if (!watch)
-                       WTROUBLE("unwatch nonexistent watch");
-
-               watch->visible_to_user = 0;
-               make_watch_request(d, req, d->wbuf.msg.tx_id, watch);
-               break;
-
-       default:
-               WTROUBLE("unknown request message type");
-       }
-
-       err = 0;
-end:
-       if (watch_free)
-               free_watch(watch_free);
-       return err;
-}
+#define wbuf      dc.wbuf
+#define wbuf_used dc.wbuf_used
 
 static int
 xenbus_dev_write(struct file *fp, off_t *offset, struct uio *uio,
                 kauth_cred_t cred, int flags)
 {
-       struct xenbus_dev_data *d = fp->f_data;
+       struct rumpxenbus_data_dev *const d = fp->f_data;
+       struct rumpxenbus_data_common *const dc = &d->dc;
        int err;
 
        DPRINTF(("/dev/xen/xenbus: write...\n"));
@@ -407,7 +140,7 @@ xenbus_dev_write(struct file *fp, off_t *offset, struct uio *uio,
                                break;
 
                        if (d->wbuf.msg.len > XENSTORE_PAYLOAD_MAX)
-                               WTROUBLE("too much payload in packet");
+                               WTROUBLE(dc,"too much payload in packet");
 
                        uint32_t packetlen =
                                d->wbuf.msg.len + sizeof(d->wbuf.msg);
@@ -417,7 +150,7 @@ xenbus_dev_write(struct file *fp, off_t *offset, struct uio *uio,
                        if (d->wbuf_used < packetlen)
                                break;
 
-                       err = process_request(d);
+                       err = rumpxenbus_process_request(&d->dc);
 
                        if (d->wbuf_used) {
                                /* Remove from the buffer before checking
@@ -444,219 +177,26 @@ end:
 
 /*----- response and watch event handling (reads from the device) -----*/
 
-static struct xsd_sockmsg*
-process_watch_event(struct xenbus_dev_data *d, struct xenbus_event *event,
-                   struct xenbus_dev_watch *watch,
-                   void (**mfree_r)(void*))
+void rumpxenbus_block_before(struct rumpxenbus_data_common *dc)
 {
-
-       /* We need to make a new XS_WATCH_EVENT message because the
-        * one from xenstored (a) isn't visible to us here and (b)
-        * anyway has the wrong token in it. */
-
-       DPRINTF(("/dev/xen/xenbus: watch event,"
-                " wpath=%s user_token=%s epath=%s xb.token=%s\n",
-                watch->path, watch->user_token,
-                event->path, watch->xb.token));
-
-       /* Define the parts of the message */
-
-#define WATCH_MESSAGE_PART_STRING(PART,x)              \
-       PART(strlen((x)) + 1, memcpy(p, (x), sz))
-
-#define WATCH_MESSAGE_PARTS(PART)                              \
-       PART(sizeof(struct xsd_sockmsg), (void)0)               \
-       WATCH_MESSAGE_PART_STRING(PART,event->path)             \
-       WATCH_MESSAGE_PART_STRING(PART,watch->user_token)
-
-       /* Compute the size */
-
-       size_t totalsz = 0;
-       size_t sz = 0;
-
-#define WATCH_MESSAGE_PART_ADD_SIZE(calcpartsz, fill) \
-       totalsz += (calcpartsz);
-
-       WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD_SIZE);
-
-       DPRINTF(("/dev/xen/xenbus: watch event allocating %lu\n",
-                (unsigned long)totalsz));
-
-       /* Allocate it and fill in the header */
-
-       struct xsd_sockmsg *reply = xbd_malloc(totalsz);
-       if (!reply) {
-               printf("xenbus dev: out of memory for watch event"
-                      " wpath=`%s' epath=`%s'\n",
-                      watch->path, event->path);
-               d->queued_enomem = 1;
-               goto end;
-       }
-
-       bzero(reply, sizeof(*reply));
-       reply->type = XS_WATCH_EVENT;
-       reply->len = totalsz - sizeof(*reply);
-
-       char *p = (void*)reply;
-
-       /* Fill in the rest of the message */
-
-#define WATCH_MESSAGE_PART_ADD(calcpartsz, fill)       \
-       sz = (calcpartsz);                              \
-       fill;                                           \
-       p += sz;
-
-       WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD);
-
-       KASSERT(p == (const char*)reply + totalsz);
-
-       /* Now we are done */
-
-end:
-       xenbus_free(event);
-       *mfree_r = xbd_free;
-       return reply;
-}
-
-/* Returned value is from malloc() */
-static struct xsd_sockmsg*
-process_response(struct xenbus_dev_data *d, struct xenbus_dev_request *req,
-                void (**mfree_r)(void*))
-{
-       struct xenbus_dev_watch *watch;
-       struct xsd_sockmsg *msg = req->xb.reply;
-
-       msg->req_id = req->user_id;
-
-       _Bool error = msg->type == XS_ERROR;
-       KASSERT(error || msg->type == req->req_type);
-
-       DPRINTF(("/dev/xen/xenbus: response, req_type=%d msg->type=%d\n",
-                req->req_type, msg->type));
-
-       switch (req->req_type) {
-
-       case XS_TRANSACTION_START:
-               if (error)
-                       break;
-               KASSERT(msg->len >= 2);
-               KASSERT(!((uint8_t*)(msg+1))[msg->len-1]);
-               req->u.trans->tx_id =
-                       strtoul((char*)&msg + sizeof(*msg),
-                               0, 0);
-               LIST_INSERT_HEAD(&d->transactions, req->u.trans,
-                                entry);
-               break;
-
-       case XS_TRANSACTION_END:
-               xbd_free(req->u.trans);
-               break;
-
-       case XS_WATCH:
-               watch = req->u.watch;
-               if (error)
-                       goto do_unwatch;
-               watch->visible_to_user = 1;
-               break;
-
-       case XS_UNWATCH:
-               KASSERT(!error);
-               watch = req->u.watch;
-       do_unwatch:
-               KASSERT(!watch->visible_to_user);
-               LIST_REMOVE(watch, entry);
-               xenbus_watch_release(&watch->xb);
-               free_watch(watch);
-               break;
-
-       }
-
-       xenbus_id_release(req->xb_id);
-       xbd_free(req);
-       KASSERT(d->outstanding_requests > 0);
-       d->outstanding_requests--;
-
-       *mfree_r = xenbus_free;
-       return msg;
-}
-
-static struct xsd_sockmsg*
-process_event(struct xenbus_dev_data *d, struct xenbus_event *event,
-             void (**mfree_r)(void*))
-{
-       if (event->watch) {
-               struct xenbus_dev_watch *watch =
-                       container_of(event->watch, struct xenbus_dev_watch, xb);
-
-               return process_watch_event(d, event, watch, mfree_r);
-
-       } else {
-               struct xenbus_dev_request *req =
-                       container_of(event, struct xenbus_dev_request, xb);
-
-               return process_response(d, req, mfree_r);
-       }
-
+       struct rumpxenbus_data_dev *d =
+               container_of(dc, struct rumpxenbus_data_dev, dc);
+       mutex_exit(&d->lock);
 }
 
-static struct xsd_sockmsg*
-next_event_msg(struct xenbus_dev_data *d, struct file *fp, int *err_r,
-              void (**mfree_r)(void*))
-/* If !err_r, always blocks and always returns successfully.
- * If !!err_r, will block iff user process read should block:
- * will either return successfully, or set *err_r and return 0.
- *
- * Must be called with d->lock held; may temporarily release it. */
+void rumpxenbus_block_after(struct rumpxenbus_data_common *dc)
 {
-       int nlocks;
-       DEFINE_WAIT(w);
-       spin_lock(&xenbus_req_lock);
-
-       while (STAILQ_EMPTY(&d->replies.events)) {
-               if (err_r) {
-                       if (d->want_restart) {
-                               *err_r = ERESTART;
-                               goto fail;
-                       }
-                       if (fp->f_flag & FNONBLOCK) {
-                               *err_r = EAGAIN;
-                               goto fail;
-                       }
-               }
-
-               DPRINTF(("/dev/xen/xenbus: about to block err_r=%p\n", err_r));
-
-               minios_add_waiter(w, d->replies.waitq);
-               spin_unlock(&xenbus_req_lock);
-               mutex_exit(&d->lock);
-               rumpkern_unsched(&nlocks, 0);
-
-               minios_wait(w);
-
-               rumpkern_sched(nlocks, 0);
-               mutex_enter(&d->lock);
-               spin_lock(&xenbus_req_lock);
-               minios_remove_waiter(w, d->replies.waitq);
-       }
-       struct xenbus_event *event = STAILQ_FIRST(&d->replies.events);
-       STAILQ_REMOVE_HEAD(&d->replies.events, entry);
-
-       spin_unlock(&xenbus_req_lock);
-
-       DPRINTF(("/dev/xen/xenbus: next_event_msg found an event %p\n",event));
-       return process_event(d, event, mfree_r);
-
-fail:
-       DPRINTF(("/dev/xen/xenbus: not blocking, returning %d\n", *err_r));
-       spin_unlock(&xenbus_req_lock);
-       return 0;
+       struct rumpxenbus_data_dev *d =
+               container_of(dc, struct rumpxenbus_data_dev, dc);
+       mutex_enter(&d->lock);
 }
 
 static int
 xenbus_dev_read(struct file *fp, off_t *offset, struct uio *uio,
                kauth_cred_t cred, int flags)
 {
-       struct xenbus_dev_data *d = fp->f_data;
+       struct rumpxenbus_data_dev *const d = fp->f_data;
+       struct rumpxenbus_data_common *const dc = &d->dc;
        size_t org_resid = uio->uio_resid;
        int err;
 
@@ -668,13 +208,13 @@ xenbus_dev_read(struct file *fp, off_t *offset, struct uio *uio,
                         " q.enomem=%d\n",
                         (unsigned long)uio->uio_resid,
                         (unsigned long)org_resid,
-                        d->queued_enomem));
-               if (d->queued_enomem) {
+                        dc->queued_enomem));
+               if (dc->queued_enomem) {
                        if (org_resid != uio->uio_resid)
                                /* return early now; report it next time */
                                break;
                        err = ENOMEM;
-                       d->queued_enomem = 0;
+                       dc->queued_enomem = 0;
                        goto end;
                }
 
@@ -683,11 +223,22 @@ xenbus_dev_read(struct file *fp, off_t *offset, struct uio *uio,
                        break;
 
                if (!d->rmsg) {
-                       d->rmsg = next_event_msg(d, fp, &err, &d->rmsg_free);
+                       int err_if_block = 0;
+                       if (d->want_restart) {
+                               err_if_block = ERESTART;
+                       } else if (fp->f_flag & FNONBLOCK) {
+                               err_if_block = EAGAIN;
+                       }
+
+                       d->rmsg = rumpxenbus_next_event_msg(&d->dc,
+                                                !err_if_block,
+                                                &d->rmsg_free);
+
                        if (!d->rmsg) {
                                if (uio->uio_resid != org_resid)
                                        /* Done something, claim success. */
                                        break;
+                               err = err_if_block;
                                goto end;
                        }
                }
@@ -732,44 +283,37 @@ end:
 #define RBITS (POLLIN  | POLLRDNORM)
 #define WBITS (POLLOUT | POLLWRNORM)
 
-static void
-xenbus_dev_xb_wakeup(struct xenbus_event_queue *queue)
+void rumpxenbus_dev_xb_wakeup(struct rumpxenbus_data_common *dc)
 {
-       /* called with req_lock held */
        DPRINTF(("/dev/xen/xenbus: wakeup\n"));
-       struct xenbus_dev_data *d =
-               container_of(queue, struct xenbus_dev_data, replies);
-       minios_wake_up(&d->replies.waitq);
+       struct rumpxenbus_data_dev *d =
+               container_of(dc, struct rumpxenbus_data_dev, dc);
        selnotify(&d->selinfo, RBITS, NOTE_SUBMIT);
 }
 
 static void
 xenbus_dev_restart(file_t *fp)
 {
-       struct xenbus_dev_data *d = fp->f_data;
+       struct rumpxenbus_data_dev *d = fp->f_data;
 
        DPRINTF(("/dev/xen/xenbus: restart!\n"));
 
        mutex_enter(&d->lock);
-       spin_lock(&xenbus_req_lock);
-
        d->want_restart |= 1;
-       minios_wake_up(&d->replies.waitq);
-
-       spin_unlock(&xenbus_req_lock);
+       rumpxenbus_dev_restart_wakeup(&d->dc);
        mutex_exit(&d->lock);
 }
 
 static int
 xenbus_dev_poll(struct file *fp, int events)
 {
-       struct xenbus_dev_data *d = fp->f_data;
+       struct rumpxenbus_data_dev *const d = fp->f_data;
+       struct rumpxenbus_data_common *const dc = &d->dc;
        int revents = 0;
 
        DPRINTF(("/dev/xen/xenbus: poll events=0%o...\n", events));
 
        mutex_enter(&d->lock);
-       spin_lock(&xenbus_req_lock);
 
        /* always writeable - we don't do proper blocking for writing
         * since this can only wait at most until other requests have
@@ -777,7 +321,7 @@ xenbus_dev_poll(struct file *fp, int events)
        revents |= events & WBITS;
 
        if (events & RBITS)
-               if (d->rmsg || d->queued_enomem || d->want_restart)
+               if (d->rmsg || dc->queued_enomem || d->want_restart)
                        revents |= events & RBITS;
 
        if (!revents) {
@@ -785,7 +329,6 @@ xenbus_dev_poll(struct file *fp, int events)
                        selrecord(curlwp, &d->selinfo);
        }
 
-       spin_unlock(&xenbus_req_lock);
        mutex_exit(&d->lock);
 
        DPRINTF(("/dev/xen/xenbus: poll events=0%o done, revents=0%o\n",
@@ -798,7 +341,7 @@ xenbus_dev_poll(struct file *fp, int events)
 static int
 xenbus_dev_close(struct file *fp)
 {
-       struct xenbus_dev_data *d = fp->f_data;
+       struct rumpxenbus_data_dev *d = fp->f_data;
 
        DPRINTF(("/dev/xen/xenbus: close...\n"));
 
@@ -809,59 +352,11 @@ xenbus_dev_close(struct file *fp)
        xbd_free(d->rmsg);
        d->rmsg = 0;
 
-       for (;;) {
-               DPRINTF(("/dev/xen/xenbus: close loop\n"));
-               /* We need to go round this again and again because
-                * there might be requests in flight.  Eg if the
-                * user has an XS_WATCH in flight we have to wait for it
-                * to be done and then unwatch it again. */
-
-               struct xenbus_dev_watch *watch, *watch_tmp;
-               LIST_FOREACH_SAFE(watch, &d->watches, entry, watch_tmp) {
-                       DPRINTF(("/dev/xen/xenbus: close watch %p %d\n",
-                                watch, watch->visible_to_user));
-                       if (watch->visible_to_user) {
-                               /* mirrors process_request XS_UNWATCH */
-                               watch->destroy.req_type = XS_UNWATCH;
-                               watch->visible_to_user = 0;
-                               make_watch_request(d, &watch->destroy, 0,
-                                                  watch);
-                       }
-               }
-
-               struct xenbus_dev_transaction *trans, *trans_tmp;
-               const struct write_req trans_end_data = { "F", 2 };
-               LIST_FOREACH_SAFE(trans, &d->transactions, entry, trans_tmp) {
-                       DPRINTF(("/dev/xen/xenbus: close transaction"
-                                " %p %"PRIx32"\n",
-                                trans, (unsigned int)trans->tx_id));
-                       /* mirrors process_request XS_TRANSACTION_END */
-                       trans->destroy.req_type = XS_TRANSACTION_END;
-                       trans->destroy.u.trans = trans;
-                       LIST_REMOVE(trans, entry);
-                       make_request(d, &trans->destroy, trans->tx_id,
-                                    &trans_end_data, 1);
-               }
-
-               DPRINTF(("/dev/xen/xenbus: close outstanding=%d\n",
-                        d->outstanding_requests));
-               KASSERT(d->outstanding_requests >= 0);
-               if (!d->outstanding_requests)
-                       break;
-
-               void (*dfree)(void*);
-               struct xsd_sockmsg *discard = next_event_msg(d, fp, 0, &dfree);
-               KASSERT(discard);
-               dfree(discard);
-       }
+       rumpxenbus_dev_user_shutdown(&d->dc);
 
-       KASSERT(!d->outstanding_requests);
        KASSERT(!d->rmsg);
-       KASSERT(LIST_EMPTY(&d->transactions));
-       KASSERT(LIST_EMPTY(&d->watches));
 
-       DPRINTF(("/dev/xen/xenbus: close seldestroy outstanding=%d\n",
-                d->outstanding_requests));
+       DPRINTF(("/dev/xen/xenbus: close seldestroy...\n"));
        seldestroy(&d->selinfo);
        xbd_free(d);
 
@@ -884,21 +379,23 @@ const struct fileops xenbus_dev_fileops = {
 int
 xenbus_dev_open(struct file *fp, void **fdata_r)
 {
-       struct xenbus_dev_data *d;
+       struct rumpxenbus_data_dev *d;
+       int err;
 
        d = xbd_malloc(sizeof(*d));
        if (!d)
                return ENOMEM;
 
+       d->dc.du = 0;
+
+       err = rumpxenbus_dev_user_open(&d->dc);
+       if (err) {
+               xbd_free(d);
+               return err;
+       }
+
        mutex_init(&d->lock, MUTEX_DEFAULT, IPL_HIGH);
-       d->outstanding_requests = 0;
-       LIST_INIT(&d->transactions);
-       LIST_INIT(&d->watches);
-       xenbus_event_queue_init(&d->replies);
-       d->replies.wakeup = xenbus_dev_xb_wakeup;
-       d->queued_enomem = 0;
        d->want_restart = 0;
-       d->wbuf_used = 0;
        d->rmsg = 0;
        d->rmsg_done = 0;
        selinit(&d->selinfo);
diff --git a/platform/xen/librumpxen_xendev/busdev_user.c b/platform/xen/librumpxen_xendev/busdev_user.c
new file mode 100644 (file)
index 0000000..3370cc8
--- /dev/null
@@ -0,0 +1,630 @@
+
+#include <mini-os/os.h>
+#include <mini-os/xenbus.h>
+#include <mini-os/wait.h>
+
+#include <bmk-core/memalloc.h>
+#include <bmk-core/string.h>
+#include <bmk-core/errno.h>
+
+#include <bmk-rumpuser/core_types.h>
+#include <bmk-rumpuser/rumpuser.h>
+
+#include <inttypes.h>
+
+#include "busdev_user.h"
+
+#define xbd_malloc(sz) (bmk_memalloc((sz), 0, BMK_MEMWHO_RUMPKERN))
+
+static inline void xbd_free(void *p) { bmk_memfree(p, BMK_MEMWHO_RUMPKERN); }
+
+#define strcmp bmk_strcmp
+#define strlen bmk_strlen
+#define memchr bmk_memchr
+#define memcpy bmk_memcpy
+#define strtoul bmk_strtoul
+
+#define bzero(p,l) bmk_memset((p),0,(l))
+
+#define KASSERT bmk_assert
+#define assert  bmk_assert
+#define INT_MAX ((int)(~(unsigned int)0 >> 1u))
+
+#define ENOMEM BMK_ENOMEM
+#define EINVAL BMK_EINVAL
+
+#define printf minios_printk
+
+#ifdef RUMP_DEV_XEN_DEBUG
+#define DPRINTF(a) (printf a)
+#else
+#define DPRINTF(a) /* nothing */
+#endif
+
+static char *xbd_strdup(const char *s) {
+       size_t l = strlen(s);
+       char *r = xbd_malloc(l + 1);
+       if (!r) return r;
+       memcpy(r, s, l+1);
+       return r;
+}
+
+/*----- data structures -----*/
+
+struct xenbus_dev_request {
+       struct xenbus_event xb;
+       uint32_t xb_id, user_id;
+       uint32_t req_type;
+       union {
+               struct xenbus_dev_transaction *trans;
+               struct xenbus_dev_watch *watch;
+       } u;
+};
+
+struct xenbus_dev_transaction {
+       LIST_ENTRY(xenbus_dev_transaction) entry;
+       xenbus_transaction_t tx_id;
+       struct xenbus_dev_request destroy;
+};
+
+struct xenbus_dev_watch {
+       struct xenbus_watch xb;
+       LIST_ENTRY(xenbus_dev_watch) entry;
+       struct xsd_sockmsg *wmsg;
+       char *path, *user_token;
+       _Bool visible_to_user;
+       struct xenbus_dev_request destroy;
+};
+
+struct rumpxenbus_data_user {
+       struct rumpxenbus_data_common *c;
+       int outstanding_requests;
+       LIST_HEAD(, xenbus_dev_transaction) transactions;
+       LIST_HEAD(, xenbus_dev_watch) watches;
+       struct xenbus_event_queue replies; /* Entirely unread by user. */
+};
+
+/*----- helpers -----*/
+
+static void
+free_watch(struct xenbus_dev_watch *watch)
+{
+       xbd_free(watch->path);
+       xbd_free(watch->user_token);
+       xbd_free(watch);
+}
+
+static struct xenbus_dev_transaction*
+find_transaction(struct rumpxenbus_data_common *d, xenbus_transaction_t id)
+{
+       struct rumpxenbus_data_user *const du = d->du;
+       struct xenbus_dev_transaction *trans;
+
+       LIST_FOREACH(trans, &du->transactions, entry)
+               if (trans->tx_id == d->wbuf.msg.tx_id)
+                       return trans;
+       /* not found */
+       return 0;
+}
+
+static struct xenbus_dev_watch*
+find_visible_watch(struct rumpxenbus_data_common *d,
+                  const char *path, const char *token)
+{
+       struct rumpxenbus_data_user *const du = d->du;
+       struct xenbus_dev_watch *watch;
+
+       LIST_FOREACH(watch, &du->watches, entry)
+               if (watch->visible_to_user &&
+                   !strcmp(path, watch->path) &&
+                   !strcmp(token, watch->user_token))
+                       return watch;
+       /* not found */
+       return 0;
+}
+
+/*----- request handling (writes to the device) -----*/
+
+static void
+make_request(struct rumpxenbus_data_common *d, struct xenbus_dev_request *req,
+            uint32_t tx_id, const struct write_req *wreqs, int num_wreqs)
+/* Caller should have filled in req->req_id, ->u, and (if needed)
+ * ->user_id.  We deal with ->xb and ->xb_id. */
+{
+       struct rumpxenbus_data_user *const du = d->du;
+
+       req->xb.watch = 0;
+       req->xb_id = xenbus_id_allocate(&du->replies, &req->xb);
+
+       KASSERT(du->outstanding_requests < INT_MAX);
+       du->outstanding_requests++;
+
+       xenbus_xb_write(req->req_type, req->xb_id, tx_id,
+                       wreqs, num_wreqs);
+}
+
+static void
+watch_write_req_string(struct write_req **wreqp, const char *string)
+{
+       struct write_req *wreq = (*wreqp)++;
+       int l = strlen(string);
+       wreq->len = l+1;
+       wreq->data = string;
+}
+
+static void
+make_watch_request(struct rumpxenbus_data_common *d,
+                  struct xenbus_dev_request *req,
+                  uint32_t tx_id, struct xenbus_dev_watch *watch)
+{
+       struct write_req wreqs[2], *wreq = wreqs;
+       watch_write_req_string(&wreq, watch->path);
+       watch_write_req_string(&wreq, watch->xb.token);
+       KASSERT((char*)wreq == (char*)wreqs + sizeof(wreqs));
+
+       req->u.watch = watch;
+       make_request(d, req, tx_id, wreqs, 2);
+}
+
+static void
+forward_request(struct rumpxenbus_data_common *d, struct xenbus_dev_request *req)
+{
+       struct write_req wreq = {
+               d->wbuf.buffer + sizeof(d->wbuf.msg),
+               d->wbuf_used - sizeof(d->wbuf.msg),
+       };
+
+       make_request(d, req, d->wbuf.msg.tx_id, &wreq, 1);
+}
+
+static _Bool
+watch_message_parse_string(const char **p, const char *end,
+                          const char **string_r)
+{
+       const char *nul = memchr(*p, 0, end - *p);
+       if (!nul)
+               return 0;
+
+       *string_r = *p;
+       *p = nul+1;
+
+       return 1;
+}
+
+static _Bool
+watch_message_parse(const struct xsd_sockmsg *msg,
+                   const char **path_r, const char **token_r)
+{
+       const char *begin = (const char*)msg;
+       const char *p = begin + sizeof(*msg);
+       const char *end = p + msg->len;
+       KASSERT(p <= end);
+
+       return
+               watch_message_parse_string(&p, end, path_r) &&
+               watch_message_parse_string(&p, end, token_r);
+}
+
+int
+rumpxenbus_process_request(struct rumpxenbus_data_common *d)
+{
+       struct rumpxenbus_data_user *const du = d->du;
+       struct xenbus_dev_request *req;
+       struct xenbus_dev_transaction *trans;
+       struct xenbus_dev_watch *watch_free = 0, *watch;
+       const char *wpath, *wtoken;
+       int err;
+
+       DPRINTF(("/dev/xen/xenbus: request, type=%d\n",
+                d->wbuf.msg.type));
+
+       req = xbd_malloc(sizeof(*req));
+       if (!req) {
+               err = ENOMEM;
+               goto end;
+       }
+       req->user_id = d->wbuf.msg.req_id;
+       req->req_type = d->wbuf.msg.type;
+
+       switch (d->wbuf.msg.type) {
+       case XS_DIRECTORY:
+       case XS_READ:
+       case XS_GET_PERMS:
+       case XS_GET_DOMAIN_PATH:
+       case XS_IS_DOMAIN_INTRODUCED:
+       case XS_WRITE:
+       case XS_MKDIR:
+       case XS_RM:
+       case XS_SET_PERMS:
+               if (d->wbuf.msg.tx_id) {
+                       if (!find_transaction(d, d->wbuf.msg.tx_id))
+                               WTROUBLE(d,"unknown transaction");
+               }
+               forward_request(d, req);
+               break;
+
+       case XS_TRANSACTION_START:
+               if (d->wbuf.msg.tx_id)
+                       WTROUBLE(d,"nested transaction");
+               req->u.trans = xbd_malloc(sizeof(*req->u.trans));
+               if (!req->u.trans) {
+                       err = ENOMEM;
+                       goto end;
+               }
+               forward_request(d, req);
+               break;
+
+       case XS_TRANSACTION_END:
+               if (!d->wbuf.msg.tx_id)
+                       WTROUBLE(d,"ending zero transaction");
+               req->u.trans = trans = find_transaction(d, d->wbuf.msg.tx_id);
+               if (!trans)
+                       WTROUBLE(d,"ending unknown transaction");
+               LIST_REMOVE(trans, entry); /* prevent more reqs using it */
+               forward_request(d, req);
+               break;
+       case XS_WATCH:
+               if (d->wbuf.msg.tx_id)
+                       WTROUBLE(d,"XS_WATCH with transaction");
+               if (!watch_message_parse(&d->wbuf.msg, &wpath, &wtoken))
+                       WTROUBLE(d,"bad XS_WATCH message");
+
+               watch = watch_free = xbd_malloc(sizeof(*watch));
+               if (!watch) {
+                       err = ENOMEM;
+                       goto end;
+               }
+
+               watch->path = xbd_strdup(wpath);
+               watch->user_token = xbd_strdup(wtoken);
+               if (!watch->path || !watch->user_token) {
+                       err = ENOMEM;
+                       goto end;
+               }
+
+               watch->xb.events = &du->replies;
+               xenbus_watch_prepare(&watch->xb);
+
+               watch_free = 0; /* we are committed */
+               watch->visible_to_user = 0;
+               LIST_INSERT_HEAD(&du->watches, watch, entry);
+               make_watch_request(d, req, d->wbuf.msg.tx_id, watch);
+               break;
+
+       case XS_UNWATCH:
+               if (d->wbuf.msg.tx_id)
+                       WTROUBLE(d,"XS_UNWATCH with transaction");
+               if (!watch_message_parse(&d->wbuf.msg, &wpath, &wtoken))
+                       WTROUBLE(d,"bad XS_WATCH message");
+
+               watch = find_visible_watch(d, wpath, wtoken);
+               if (!watch)
+                       WTROUBLE(d,"unwatch nonexistent watch");
+
+               watch->visible_to_user = 0;
+               make_watch_request(d, req, d->wbuf.msg.tx_id, watch);
+               break;
+
+       default:
+               WTROUBLE(d,"unknown request message type");
+       }
+
+       err = 0;
+end:
+       if (watch_free)
+               free_watch(watch_free);
+       return err;
+}
+
+/*----- response and watch event handling (reads from the device) -----*/
+
+static struct xsd_sockmsg*
+process_watch_event(struct rumpxenbus_data_common *d, struct xenbus_event *event,
+                   struct xenbus_dev_watch *watch,
+                   void (**mfree_r)(void*))
+{
+
+       /* We need to make a new XS_WATCH_EVENT message because the
+        * one from xenstored (a) isn't visible to us here and (b)
+        * anyway has the wrong token in it. */
+
+       DPRINTF(("/dev/xen/xenbus: watch event,"
+                " wpath=%s user_token=%s epath=%s xb.token=%s\n",
+                watch->path, watch->user_token,
+                event->path, watch->xb.token));
+
+       /* Define the parts of the message */
+
+#define WATCH_MESSAGE_PART_STRING(PART,x)              \
+       PART(strlen((x)) + 1, memcpy(p, (x), sz))
+
+#define WATCH_MESSAGE_PARTS(PART)                              \
+       PART(sizeof(struct xsd_sockmsg), (void)0)               \
+       WATCH_MESSAGE_PART_STRING(PART,event->path)             \
+       WATCH_MESSAGE_PART_STRING(PART,watch->user_token)
+
+       /* Compute the size */
+
+       size_t totalsz = 0;
+       size_t sz = 0;
+
+#define WATCH_MESSAGE_PART_ADD_SIZE(calcpartsz, fill) \
+       totalsz += (calcpartsz);
+
+       WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD_SIZE);
+
+       DPRINTF(("/dev/xen/xenbus: watch event allocating %lu\n",
+                (unsigned long)totalsz));
+
+       /* Allocate it and fill in the header */
+
+       struct xsd_sockmsg *reply = xbd_malloc(totalsz);
+       if (!reply) {
+               printf("xenbus dev: out of memory for watch event"
+                      " wpath=`%s' epath=`%s'\n",
+                      watch->path, event->path);
+               d->queued_enomem = 1;
+               goto end;
+       }
+
+       bzero(reply, sizeof(*reply));
+       reply->type = XS_WATCH_EVENT;
+       reply->len = totalsz - sizeof(*reply);
+
+       char *p = (void*)reply;
+
+       /* Fill in the rest of the message */
+
+#define WATCH_MESSAGE_PART_ADD(calcpartsz, fill)       \
+       sz = (calcpartsz);                              \
+       fill;                                           \
+       p += sz;
+
+       WATCH_MESSAGE_PARTS(WATCH_MESSAGE_PART_ADD);
+
+       KASSERT(p == (const char*)reply + totalsz);
+
+       /* Now we are done */
+
+end:
+       xenbus_free(event);
+       *mfree_r = xbd_free;
+       return reply;
+}
+
+/* Returned value is from malloc() */
+static struct xsd_sockmsg*
+process_response(struct rumpxenbus_data_common *d, struct xenbus_dev_request *req,
+                void (**mfree_r)(void*))
+{
+       struct rumpxenbus_data_user *const du = d->du;
+       struct xenbus_dev_watch *watch;
+       struct xsd_sockmsg *msg = req->xb.reply;
+
+       msg->req_id = req->user_id;
+
+       _Bool error = msg->type == XS_ERROR;
+       KASSERT(error || msg->type == req->req_type);
+
+       DPRINTF(("/dev/xen/xenbus: response, req_type=%d msg->type=%d\n",
+                req->req_type, msg->type));
+
+       switch (req->req_type) {
+
+       case XS_TRANSACTION_START:
+               if (error)
+                       break;
+               KASSERT(msg->len >= 2);
+               KASSERT(!((uint8_t*)(msg+1))[msg->len-1]);
+               req->u.trans->tx_id =
+                       strtoul((char*)&msg + sizeof(*msg),
+                               0, 0);
+               LIST_INSERT_HEAD(&du->transactions, req->u.trans,
+                                entry);
+               break;
+
+       case XS_TRANSACTION_END:
+               xbd_free(req->u.trans);
+               break;
+
+       case XS_WATCH:
+               watch = req->u.watch;
+               if (error)
+                       goto do_unwatch;
+               watch->visible_to_user = 1;
+               break;
+
+       case XS_UNWATCH:
+               KASSERT(!error);
+               watch = req->u.watch;
+       do_unwatch:
+               KASSERT(!watch->visible_to_user);
+               LIST_REMOVE(watch, entry);
+               xenbus_watch_release(&watch->xb);
+               free_watch(watch);
+               break;
+
+       }
+
+       xenbus_id_release(req->xb_id);
+       xbd_free(req);
+       KASSERT(du->outstanding_requests > 0);
+       du->outstanding_requests--;
+
+       *mfree_r = xenbus_free;
+       return msg;
+}
+
+static struct xsd_sockmsg*
+process_event(struct rumpxenbus_data_common *d, struct xenbus_event *event,
+             void (**mfree_r)(void*))
+{
+       if (event->watch) {
+               struct xenbus_dev_watch *watch =
+                       container_of(event->watch, struct xenbus_dev_watch, xb);
+
+               return process_watch_event(d, event, watch, mfree_r);
+
+       } else {
+               struct xenbus_dev_request *req =
+                       container_of(event, struct xenbus_dev_request, xb);
+
+               return process_response(d, req, mfree_r);
+       }
+
+}
+
+struct xsd_sockmsg*
+rumpxenbus_next_event_msg(struct rumpxenbus_data_common *dc,
+                        _Bool block,
+                        void (**mfree_r)(void*))
+/* If !!block, always blocks and always returns successfully.
+ * If !block, stores err_r_if_nothing into *err_r rather than blocking.
+
+ * If !!err_r, will block iff user process read should block:
+ * will either return successfully, or set *err_r and return 0.
+ *
+ * Must be called with d->lock held; may temporarily release it
+ * by calling rumpxenbus_block_{before,after}. */
+{
+       struct rumpxenbus_data_user *d = dc->du;
+       int nlocks;
+       DEFINE_WAIT(w);
+       spin_lock(&xenbus_req_lock);
+
+       while (STAILQ_EMPTY(&d->replies.events)) {
+               if (!block)
+                       goto fail;
+
+               DPRINTF(("/dev/xen/xenbus: about to block\n"));
+
+               minios_add_waiter(w, d->replies.waitq);
+               spin_unlock(&xenbus_req_lock);
+               rumpxenbus_block_before(dc);
+               rumpkern_unsched(&nlocks, 0);
+
+               minios_wait(w);
+
+               rumpkern_sched(nlocks, 0);
+               rumpxenbus_block_after(dc);
+               spin_lock(&xenbus_req_lock);
+               minios_remove_waiter(w, d->replies.waitq);
+       }
+       struct xenbus_event *event = STAILQ_FIRST(&d->replies.events);
+       STAILQ_REMOVE_HEAD(&d->replies.events, entry);
+
+       spin_unlock(&xenbus_req_lock);
+
+       DPRINTF(("/dev/xen/xenbus: next_event_msg found an event %p\n",event));
+       return process_event(dc, event, mfree_r);
+
+fail:
+       DPRINTF(("/dev/xen/xenbus: not blocking, returning no event\n"));
+       spin_unlock(&xenbus_req_lock);
+       return 0;
+}
+
+/*----- more exciting reading -----*/
+
+static void
+xenbus_dev_xb_wakeup(struct xenbus_event_queue *queue)
+{
+       /* called with req_lock held */
+       struct rumpxenbus_data_user *d =
+               container_of(queue, struct rumpxenbus_data_user, replies);
+       minios_wake_up(&d->replies.waitq);
+       rumpxenbus_dev_xb_wakeup(d->c);
+}
+
+void
+rumpxenbus_dev_restart_wakeup(struct rumpxenbus_data_common *c)
+{
+       struct rumpxenbus_data_user *d = c->du;
+       spin_lock(&xenbus_req_lock);
+       minios_wake_up(&d->replies.waitq);
+       spin_unlock(&xenbus_req_lock);
+}
+
+void
+rumpxenbus_dev_user_shutdown(struct rumpxenbus_data_common *dc)
+{
+       struct rumpxenbus_data_user *d = dc->du;
+       for (;;) {
+               DPRINTF(("/dev/xen/xenbus: close loop\n"));
+               /* We need to go round this again and again because
+                * there might be requests in flight.  Eg if the
+                * user has an XS_WATCH in flight we have to wait for it
+                * to be done and then unwatch it again. */
+
+               struct xenbus_dev_watch *watch, *watch_tmp;
+               LIST_FOREACH_SAFE(watch, &d->watches, entry, watch_tmp) {
+                       DPRINTF(("/dev/xen/xenbus: close watch %p %d\n",
+                                watch, watch->visible_to_user));
+                       if (watch->visible_to_user) {
+                               /* mirrors process_request XS_UNWATCH */
+                               watch->destroy.req_type = XS_UNWATCH;
+                               watch->visible_to_user = 0;
+                               make_watch_request(dc, &watch->destroy, 0,
+                                                  watch);
+                       }
+               }
+
+               struct xenbus_dev_transaction *trans, *trans_tmp;
+               const struct write_req trans_end_data = { "F", 2 };
+               LIST_FOREACH_SAFE(trans, &d->transactions, entry, trans_tmp) {
+                       DPRINTF(("/dev/xen/xenbus: close transaction"
+                                " %p %"PRIx32"\n",
+                                trans, (unsigned int)trans->tx_id));
+                       /* mirrors process_request XS_TRANSACTION_END */
+                       trans->destroy.req_type = XS_TRANSACTION_END;
+                       trans->destroy.u.trans = trans;
+                       LIST_REMOVE(trans, entry);
+                       make_request(dc, &trans->destroy, trans->tx_id,
+                                    &trans_end_data, 1);
+               }
+
+               DPRINTF(("/dev/xen/xenbus: close outstanding=%d\n",
+                        d->outstanding_requests));
+               KASSERT(d->outstanding_requests >= 0);
+               if (!d->outstanding_requests)
+                       break;
+
+               void (*dfree)(void*);
+
+               struct xsd_sockmsg *discard =
+                       rumpxenbus_next_event_msg(dc, 1, &dfree);
+
+               KASSERT(discard);
+               dfree(discard);
+       }
+
+       KASSERT(!d->outstanding_requests);
+       KASSERT(LIST_EMPTY(&d->transactions));
+       KASSERT(LIST_EMPTY(&d->watches));
+
+       xbd_free(d);
+       dc->du = NULL;
+}
+
+int
+rumpxenbus_dev_user_open(struct rumpxenbus_data_common *dc)
+{
+       assert(!dc->du);
+
+       struct rumpxenbus_data_user *d = dc->du = xbd_malloc(sizeof(*dc->du));
+       if (!d)
+               return ENOMEM;
+
+       d->c = dc;
+       d->outstanding_requests = 0;
+       LIST_INIT(&d->transactions);
+       LIST_INIT(&d->watches);
+       xenbus_event_queue_init(&d->replies);
+       d->replies.wakeup = xenbus_dev_xb_wakeup;
+
+       dc->wbuf_used = 0;
+       dc->queued_enomem = 0;
+
+       return 0;
+}
diff --git a/platform/xen/librumpxen_xendev/busdev_user.h b/platform/xen/librumpxen_xendev/busdev_user.h
new file mode 100644 (file)
index 0000000..6d9610a
--- /dev/null
@@ -0,0 +1,53 @@
+
+#include <xen/io/xs_wire.h>
+
+struct rumpxenbus_data_dev;
+struct rumpxenbus_data_user;
+
+#define BUFFER_SIZE (XENSTORE_PAYLOAD_MAX+sizeof(struct xsd_sockmsg))
+
+struct rumpxenbus_data_common {
+       /* Partially written request(s). */
+       unsigned int wbuf_used;
+       union {
+               struct xsd_sockmsg msg;
+               unsigned char buffer[BUFFER_SIZE];
+       } wbuf;
+
+       _Bool queued_enomem;
+
+       struct rumpxenbus_data_user *du;
+};
+
+/* void __NORETURN__ WTROUBLE(const char *details_without_newline);
+ * assumes:   int err;
+ *            end: */
+#define WTROUBLE(dc,s) do{ rumpxenbus_write_trouble((dc),s); err = EINVAL; goto end; }while(0)
+
+void
+rumpxenbus_write_trouble(struct rumpxenbus_data_common *dc, const char *what);
+
+int
+rumpxenbus_process_request(struct rumpxenbus_data_common *d);
+
+struct xsd_sockmsg*
+rumpxenbus_next_event_msg(struct rumpxenbus_data_common *dc,
+                        _Bool block,
+                        void (**mfree_r)(void*));
+
+void rumpxenbus_block_before(struct rumpxenbus_data_common *dc);
+void rumpxenbus_block_after(struct rumpxenbus_data_common *dc);
+
+void rumpxenbus_dev_xb_wakeup(struct rumpxenbus_data_common *dc);
+void rumpxenbus_dev_restart_wakeup(struct rumpxenbus_data_common *dc);
+
+void
+rumpxenbus_dev_user_shutdown(struct rumpxenbus_data_common *dc);
+int
+rumpxenbus_dev_user_open(struct rumpxenbus_data_common *dc);
+
+/* nicked from NetBSD sys/dev/pci/cxgb/cxgb_adapter.h */
+#ifndef container_of
+#define container_of(p, stype, field) ((stype *)(((uint8_t *)(p)) - offsetof(stype, field)))
+#endif
+
index 16ebd5c7603062ee6a6055c181c3adcc7e8bd265..b9fa78c0f66dec831b2dea0f4992bd3737c2f248 100644 (file)
 #include <sys/poll.h>
 
 
-/* nicked from NetBSD sys/dev/pci/cxgb/cxgb_adapter.h */
-#ifndef container_of
-#define container_of(p, stype, field) ((stype *)(((uint8_t *)(p)) - offsetof(stype, field)))
-#endif
-
 //#define RUMP_DEV_XEN_DEBUG 1
 
 #ifdef RUMP_DEV_XEN_DEBUG