diff options
author | kmacy <kmacy@FreeBSD.org> | 2008-12-29 06:31:03 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2008-12-29 06:31:03 +0000 |
commit | 9198d09682e0ff9e4b99c1a500c60ec311f33516 (patch) | |
tree | 78f4ff4cfc0d598fd6e8ccc01fa628fc8ded089f /sys/xen/xenbus | |
parent | e46dfc4a1843e8da9da2fceed45ebc43d45d62b1 (diff) | |
download | FreeBSD-src-9198d09682e0ff9e4b99c1a500c60ec311f33516.zip FreeBSD-src-9198d09682e0ff9e4b99c1a500c60ec311f33516.tar.gz |
merge 186535, 186537, and 186538 from releng_7_xen
Log:
- merge in latest xenbus from dfr's xenhvm
- fix race condition in xs_read_reply by converting tsleep to mtx_sleep
Log:
unmask evtchn in bind_{virq, ipi}_to_irq
Log:
- remove code for handling case of not being able to sleep
- eliminate tsleep - make sleeps atomic
Diffstat (limited to 'sys/xen/xenbus')
-rw-r--r-- | sys/xen/xenbus/xenbus_client.c | 183 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_comms.c | 317 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_comms.h | 116 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_dev.c | 133 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_probe.c | 118 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_probe_backend.c | 5 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_xs.c | 1307 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbusvar.h | 65 |
8 files changed, 1057 insertions, 1187 deletions
diff --git a/sys/xen/xenbus/xenbus_client.c b/sys/xen/xenbus/xenbus_client.c index d8a1a3f..740d664 100644 --- a/sys/xen/xenbus/xenbus_client.c +++ b/sys/xen/xenbus/xenbus_client.c @@ -44,19 +44,14 @@ __FBSDID("$FreeBSD$"); #include <sys/libkern.h> #include <machine/xen/xen-os.h> -#include <machine/xen/evtchn.h> +#include <xen/hypervisor.h> +#include <xen/evtchn.h> #include <xen/gnttab.h> #include <xen/xenbus/xenbusvar.h> #include <machine/stdarg.h> - -#define EXPORT_SYMBOL(x) -#define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK) -#define kfree(ptr) free(ptr, M_DEVBUF) -#define BUG_ON PANIC_IF - - -const char *xenbus_strstate(XenbusState state) +const char * +xenbus_strstate(XenbusState state) { static const char *const name[] = { [ XenbusStateUnknown ] = "Unknown", @@ -67,121 +62,108 @@ const char *xenbus_strstate(XenbusState state) [ XenbusStateClosing ] = "Closing", [ XenbusStateClosed ] = "Closed", }; - return (state < (XenbusStateClosed + 1)) ? name[state] : "INVALID"; + + return ((state < (XenbusStateClosed + 1)) ? name[state] : "INVALID"); } int -xenbus_watch_path(device_t dev, char *path, - struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, - const char **, unsigned int)) +xenbus_watch_path(device_t dev, char *path, struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, const char **, unsigned int)) { - int err; + int error; watch->node = path; watch->callback = callback; - err = register_xenbus_watch(watch); + error = register_xenbus_watch(watch); - if (err) { + if (error) { watch->node = NULL; watch->callback = NULL; - xenbus_dev_fatal(dev, err, "adding watch on %s", path); + xenbus_dev_fatal(dev, error, "adding watch on %s", path); } - return err; + return (error); } -EXPORT_SYMBOL(xenbus_watch_path); - -int xenbus_watch_path2(device_t dev, const char *path, - const char *path2, struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, - const char **, unsigned int)) +int +xenbus_watch_path2(device_t dev, const char *path, + const char *path2, struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, const char **, unsigned int)) { - int err; - char *state = - kmalloc(strlen(path) + 1 + strlen(path2) + 1, GFP_KERNEL); - if (!state) { - xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); - return -ENOMEM; - } + int error; + char *state = malloc(strlen(path) + 1 + strlen(path2) + 1, + M_DEVBUF, M_WAITOK); + strcpy(state, path); strcat(state, "/"); strcat(state, path2); - err = xenbus_watch_path(dev, state, watch, callback); - - if (err) { - kfree(state); + error = xenbus_watch_path(dev, state, watch, callback); + if (error) { + free(state, M_DEVBUF); } - return err; + + return (error); } -EXPORT_SYMBOL(xenbus_watch_path2); /** * Return the path to the error node for the given device, or NULL on failure. * If the value returned is non-NULL, then it is the caller's to kfree. */ -static char *error_path(device_t dev) +static char * +error_path(device_t dev) { - char *path_buffer = kmalloc(strlen("error/") - + strlen(xenbus_get_node(dev)) + - 1, GFP_KERNEL); - if (path_buffer == NULL) { - return NULL; - } + char *path_buffer = malloc(strlen("error/") + + strlen(xenbus_get_node(dev)) + 1, M_DEVBUF, M_WAITOK); strcpy(path_buffer, "error/"); strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); - return path_buffer; + return (path_buffer); } -static void _dev_error(device_t dev, int err, const char *fmt, - va_list ap) +static void +_dev_error(device_t dev, int err, const char *fmt, va_list ap) { int ret; unsigned int len; char *printf_buffer = NULL, *path_buffer = NULL; #define PRINTF_BUFFER_SIZE 4096 - printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); - if (printf_buffer == NULL) - goto fail; + printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK); - len = sprintf(printf_buffer, "%i ", -err); + len = sprintf(printf_buffer, "%i ", err); ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); - BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1); + KASSERT(len + ret <= PRINTF_BUFFER_SIZE-1, ("xenbus error message too big")); #if 0 dev_err(&dev->dev, "%s\n", printf_buffer); #endif path_buffer = error_path(dev); if (path_buffer == NULL) { - printk("xenbus: failed to write error node for %s (%s)\n", + printf("xenbus: failed to write error node for %s (%s)\n", xenbus_get_node(dev), printf_buffer); goto fail; } if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { - printk("xenbus: failed to write error node for %s (%s)\n", + printf("xenbus: failed to write error node for %s (%s)\n", xenbus_get_node(dev), printf_buffer); goto fail; } fail: if (printf_buffer) - kfree(printf_buffer); + free(printf_buffer, M_DEVBUF); if (path_buffer) - kfree(path_buffer); + free(path_buffer, M_DEVBUF); } - -void xenbus_dev_error(device_t dev, int err, const char *fmt, - ...) +void +xenbus_dev_error(device_t dev, int err, const char *fmt, ...) { va_list ap; @@ -189,11 +171,9 @@ void xenbus_dev_error(device_t dev, int err, const char *fmt, _dev_error(dev, err, fmt, ap); va_end(ap); } -EXPORT_SYMBOL(xenbus_dev_error); - -void xenbus_dev_fatal(device_t dev, int err, const char *fmt, - ...) +void +xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...) { va_list ap; @@ -203,21 +183,26 @@ void xenbus_dev_fatal(device_t dev, int err, const char *fmt, xenbus_set_state(dev, XenbusStateClosing); } -EXPORT_SYMBOL(xenbus_dev_fatal); - -int xenbus_grant_ring(device_t dev, unsigned long ring_mfn) +int +xenbus_grant_ring(device_t dev, unsigned long ring_mfn, int *refp) { - int err = gnttab_grant_foreign_access( - xenbus_get_otherend_id(dev), ring_mfn, 0); - if (err < 0) - xenbus_dev_fatal(dev, err, "granting access to ring page"); - return err; -} -EXPORT_SYMBOL(xenbus_grant_ring); + int error; + grant_ref_t ref; + + error = gnttab_grant_foreign_access( + xenbus_get_otherend_id(dev), ring_mfn, 0, &ref); + if (error) { + xenbus_dev_fatal(dev, error, "granting access to ring page"); + return (error); + } + *refp = ref; + return (0); +} -int xenbus_alloc_evtchn(device_t dev, int *port) +int +xenbus_alloc_evtchn(device_t dev, int *port) { struct evtchn_alloc_unbound alloc_unbound; int err; @@ -228,16 +213,16 @@ int xenbus_alloc_evtchn(device_t dev, int *port) err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); - if (err) - xenbus_dev_fatal(dev, err, "allocating event channel"); - else - *port = alloc_unbound.port; - return err; + if (err) { + xenbus_dev_fatal(dev, -err, "allocating event channel"); + return (-err); + } + *port = alloc_unbound.port; + return (0); } -EXPORT_SYMBOL(xenbus_alloc_evtchn); - -int xenbus_free_evtchn(device_t dev, int port) +int +xenbus_free_evtchn(device_t dev, int port) { struct evtchn_close close; int err; @@ -245,32 +230,22 @@ int xenbus_free_evtchn(device_t dev, int port) close.port = port; err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); - if (err) - xenbus_dev_error(dev, err, "freeing event channel %d", port); - return err; + if (err) { + xenbus_dev_error(dev, -err, "freeing event channel %d", port); + return (-err); + } + return (0); } -EXPORT_SYMBOL(xenbus_free_evtchn); - -XenbusState xenbus_read_driver_state(const char *path) +XenbusState +xenbus_read_driver_state(const char *path) { XenbusState result; + int error; - int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); - if (err) + error = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); + if (error) result = XenbusStateClosed; - return result; + return (result); } -EXPORT_SYMBOL(xenbus_read_driver_state); - - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/sys/xen/xenbus/xenbus_comms.c b/sys/xen/xenbus/xenbus_comms.c index 90f0ea9..2f03955 100644 --- a/sys/xen/xenbus/xenbus_comms.c +++ b/sys/xen/xenbus/xenbus_comms.c @@ -33,217 +33,194 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/bus.h> -#include <sys/time.h> -#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/syslog.h> -#include <sys/proc.h> -#include <sys/kernel.h> #include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> -#include <machine/xen/evtchn.h> -#include <machine/xen/xen_intr.h> -#include <xen/xenbus/xenbus_comms.h> -#include <xen/interface/io/xs_wire.h> +#include <xen/hypervisor.h> -static int xenbus_irq; +#include <xen/xen_intr.h> +#include <xen/evtchn.h> +#include <xen/interface/io/xs_wire.h> +#include <xen/xenbus/xenbus_comms.h> -extern void xenbus_probe(void *); -extern int xenstored_ready; -#if 0 -static DECLARE_WORK(probe_work, xenbus_probe, NULL); -#endif -int xb_wait; -extern char *xen_store; -#define wake_up wakeup -#define xb_waitq xb_wait -#define pr_debug(a,b,c) +static unsigned int xenstore_irq; -static inline struct xenstore_domain_interface *xenstore_domain_interface(void) +static inline struct xenstore_domain_interface * +xenstore_domain_interface(void) { - return (struct xenstore_domain_interface *)xen_store; + + return (struct xenstore_domain_interface *)xen_store; } static void -wake_waiting(void * arg __attribute__((unused))) +xb_intr(void * arg __attribute__((unused))) { -#if 0 - if (unlikely(xenstored_ready == 0)) { - xenstored_ready = 1; - schedule_work(&probe_work); - } -#endif - wakeup(&xb_wait); -} -static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) -{ - return ((prod - cons) <= XENSTORE_RING_SIZE); + wakeup(xen_store); } -static void *get_output_chunk(XENSTORE_RING_IDX cons, - XENSTORE_RING_IDX prod, - char *buf, uint32_t *len) +static int +xb_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) { - *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); + return ((prod - cons) <= XENSTORE_RING_SIZE); } -int xb_write(const void *tdata, unsigned len) +static void * +xb_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, + char *buf, uint32_t *len) { - struct xenstore_domain_interface *intf = xenstore_domain_interface(); - XENSTORE_RING_IDX cons, prod; - const char *data = (const char *)tdata; - - while (len != 0) { - void *dst; - unsigned int avail; - - wait_event_interruptible(&xb_waitq, - (intf->req_prod - intf->req_cons) != - XENSTORE_RING_SIZE); - - /* Read indexes, then verify. */ - cons = intf->req_cons; - prod = intf->req_prod; - mb(); - if (!check_indexes(cons, prod)) { - intf->req_cons = intf->req_prod = 0; - return -EIO; - } - - dst = get_output_chunk(cons, prod, intf->req, &avail); - if (avail == 0) - continue; - if (avail > len) - avail = len; - mb(); - - memcpy(dst, data, avail); - data += avail; - len -= avail; - - /* Other side must not see new header until data is there. */ - wmb(); - intf->req_prod += avail; - /* This implies mb() before other side sees interrupt. */ - notify_remote_via_evtchn(xen_start_info->store_evtchn); - } - - return 0; + *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)); } -#ifdef notyet -int xb_data_to_read(void) +static const void * +xb_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, + const char *buf, uint32_t *len) { - struct xenstore_domain_interface *intf = xen_store_interface; - return (intf->rsp_cons != intf->rsp_prod); -} -int xb_wait_for_data_to_read(void) -{ - return wait_event_interruptible(xb_waitq, xb_data_to_read()); + *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); + if ((prod - cons) < *len) + *len = prod - cons; + return (buf + MASK_XENSTORE_IDX(cons)); } -#endif - -int xb_read(void *tdata, unsigned len) +int +xb_write(const void *tdata, unsigned len, struct lock_object *lock) { - struct xenstore_domain_interface *intf = xenstore_domain_interface(); - XENSTORE_RING_IDX cons, prod; - char *data = (char *)tdata; - - while (len != 0) { - unsigned int avail; - const char *src; - - wait_event_interruptible(&xb_waitq, - intf->rsp_cons != intf->rsp_prod); - - /* Read indexes, then verify. */ - cons = intf->rsp_cons; - prod = intf->rsp_prod; - if (!check_indexes(cons, prod)) { - intf->rsp_cons = intf->rsp_prod = 0; - return -EIO; - } - - src = get_input_chunk(cons, prod, intf->rsp, &avail); - if (avail == 0) - continue; - if (avail > len) - avail = len; - - /* We must read header before we read data. */ - rmb(); + struct xenstore_domain_interface *intf = xenstore_domain_interface(); + XENSTORE_RING_IDX cons, prod; + const char *data = (const char *)tdata; + int error; + + while (len != 0) { + void *dst; + unsigned int avail; + + while ((intf->req_prod - intf->req_cons) + == XENSTORE_RING_SIZE) { + error = _sleep(intf, + lock, + PCATCH, "xbwrite", hz/10); + if (error && error != EWOULDBLOCK) + return (error); + } - memcpy(data, src, avail); - data += avail; - len -= avail; + /* Read indexes, then verify. */ + cons = intf->req_cons; + prod = intf->req_prod; + mb(); + if (!xb_check_indexes(cons, prod)) { + intf->req_cons = intf->req_prod = 0; + return (EIO); + } - /* Other side must not see free space until we've copied out */ - mb(); - intf->rsp_cons += avail; + dst = xb_get_output_chunk(cons, prod, intf->req, &avail); + if (avail == 0) + continue; + if (avail > len) + avail = len; + mb(); + + memcpy(dst, data, avail); + data += avail; + len -= avail; - pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); + /* Other side must not see new header until data is there. */ + wmb(); + intf->req_prod += avail; - /* Implies mb(): they will see new header. */ - notify_remote_via_evtchn(xen_start_info->store_evtchn); - } + /* This implies mb() before other side sees interrupt. */ + notify_remote_via_evtchn(xen_store_evtchn); + } - return 0; + return (0); } -/* Set up interrupt handler off store event channel. */ -int xb_init_comms(void) +int +xb_read(void *tdata, unsigned len, struct lock_object *lock) { - struct xenstore_domain_interface *intf = xenstore_domain_interface(); - int err; - - if (intf->rsp_prod != intf->rsp_cons) { - log(LOG_WARNING, "XENBUS response ring is not quiescent " - "(%08x:%08x): fixing up\n", - intf->rsp_cons, intf->rsp_prod); - intf->rsp_cons = intf->rsp_prod; + struct xenstore_domain_interface *intf = xenstore_domain_interface(); + XENSTORE_RING_IDX cons, prod; + char *data = (char *)tdata; + int error; + + while (len != 0) { + unsigned int avail; + const char *src; + + while (intf->rsp_cons == intf->rsp_prod) { + error = _sleep(intf, lock, + PCATCH, "xbread", hz/10); + if (error && error != EWOULDBLOCK) + return (error); } + + /* Read indexes, then verify. */ + cons = intf->rsp_cons; + prod = intf->rsp_prod; + if (!xb_check_indexes(cons, prod)) { + intf->rsp_cons = intf->rsp_prod = 0; + return (EIO); + } + + src = xb_get_input_chunk(cons, prod, intf->rsp, &avail); + if (avail == 0) + continue; + if (avail > len) + avail = len; - if (xenbus_irq) - unbind_from_irqhandler(xenbus_irq, &xb_waitq); + /* We must read header before we read data. */ + rmb(); - err = bind_caller_port_to_irqhandler( - xen_start_info->store_evtchn, - "xenbus", wake_waiting, NULL, INTR_TYPE_NET, NULL); - if (err <= 0) { - log(LOG_WARNING, "XENBUS request irq failed %i\n", err); - return err; - } + memcpy(data, src, avail); + data += avail; + len -= avail; + + /* Other side must not see free space until we've copied out */ + mb(); + intf->rsp_cons += avail; - xenbus_irq = err; + /* Implies mb(): they will see new header. */ + notify_remote_via_evtchn(xen_store_evtchn); + } - return 0; + return (0); } -/* - * Local variables: - * c-file-style: "bsd" - * indent-tabs-mode: t - * c-indent-level: 4 - * c-basic-offset: 8 - * tab-width: 4 - * End: - */ +/* Set up interrupt handler off store event channel. */ +int +xb_init_comms(void) +{ + struct xenstore_domain_interface *intf = xenstore_domain_interface(); + int error; + + if (intf->rsp_prod != intf->rsp_cons) { + log(LOG_WARNING, "XENBUS response ring is not quiescent " + "(%08x:%08x): fixing up\n", + intf->rsp_cons, intf->rsp_prod); + intf->rsp_cons = intf->rsp_prod; + } + + if (xenstore_irq) + unbind_from_irqhandler(xenstore_irq); + + error = bind_caller_port_to_irqhandler( + xen_store_evtchn, "xenbus", + xb_intr, NULL, INTR_TYPE_NET, &xenstore_irq); + if (error) { + log(LOG_WARNING, "XENBUS request irq failed %i\n", error); + return (error); + } + + return (0); +} diff --git a/sys/xen/xenbus/xenbus_comms.h b/sys/xen/xenbus/xenbus_comms.h index 94a57dc..fa47331 100644 --- a/sys/xen/xenbus/xenbus_comms.h +++ b/sys/xen/xenbus/xenbus_comms.h @@ -30,123 +30,19 @@ #ifndef _XENBUS_COMMS_H #define _XENBUS_COMMS_H +struct sx; +extern int xen_store_evtchn; +extern char *xen_store; + int xs_init(void); int xb_init_comms(void); /* Low level routines. */ -int xb_write(const void *data, unsigned len); -int xb_read(void *data, unsigned len); -int xs_input_avail(void); -extern int xb_waitq; +int xb_write(const void *data, unsigned len, struct lock_object *); +int xb_read(void *data, unsigned len, struct lock_object *); extern int xenbus_running; -#define __wait_event_interruptible(wchan, condition, ret) \ -do { \ - for (;;) { \ - if (xenbus_running == 0) { \ - break; \ - } \ - if (condition) \ - break; \ - if ((ret = !tsleep(wchan, PWAIT | PCATCH, "waitev", hz/10))) \ - break; \ - } \ -} while (0) - - -#define wait_event_interruptible(wchan, condition) \ -({ \ - int __ret = 0; \ - if (!(condition)) \ - __wait_event_interruptible(wchan, condition, __ret); \ - __ret; \ -}) - - - -#define DECLARE_MUTEX(lock) struct sema lock -#define semaphore sema -#define rw_semaphore sema - -#define down sema_wait -#define up sema_post -#define down_read sema_wait -#define up_read sema_post -#define down_write sema_wait -#define up_write sema_post - -/** - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - - -/* - * XXX - * - */ - -#define GFP_KERNEL 1 -#define EXPORT_SYMBOL(x) -#define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK) -#define kfree(ptr) free((void *)(uintptr_t)ptr, M_DEVBUF) -#define BUG_ON PANIC_IF -#define semaphore sema -#define rw_semaphore sema -#define DEFINE_SPINLOCK(lock) struct mtx lock -#define DECLARE_MUTEX(lock) struct sema lock -#define u32 uint32_t -#define list_del(head, ent) TAILQ_REMOVE(head, ent, list) -#define simple_strtoul strtoul -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -#define list_empty TAILQ_EMPTY -#define wake_up wakeup -#define BUS_ID_SIZE 128 - -struct xen_bus_type -{ - char *root; - unsigned int levels; - int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); - int (*probe)(const char *type, const char *dir); - struct xendev_list_head *bus; - int error; -#if 0 - struct bus_type bus; - struct device dev; -#endif -}; - - -#if 0 - -void dev_changed(const char *node, struct xen_bus_type *bus); - -int -read_otherend_details(struct xenbus_device *xendev, char *id_node, - char *path_node); -#endif - char *kasprintf(const char *fmt, ...); - - #endif /* _XENBUS_COMMS_H */ - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/sys/xen/xenbus/xenbus_dev.c b/sys/xen/xenbus/xenbus_dev.c index 52e0b67..ac3f103 100644 --- a/sys/xen/xenbus/xenbus_dev.c +++ b/sys/xen/xenbus/xenbus_dev.c @@ -45,19 +45,10 @@ __FBSDID("$FreeBSD$"); #include <sys/conf.h> #include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> +#include <xen/hypervisor.h> #include <xen/xenbus/xenbusvar.h> #include <xen/xenbus/xenbus_comms.h> -#define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK) -#define BUG_ON PANIC_IF -#define semaphore sema -#define rw_semaphore sema -#define DEFINE_SPINLOCK(lock) struct mtx lock -#define DECLARE_MUTEX(lock) struct sema lock -#define u32 uint32_t -#define simple_strtoul strtoul - struct xenbus_dev_transaction { LIST_ENTRY(xenbus_dev_transaction) list; struct xenbus_transaction handle; @@ -78,62 +69,65 @@ struct xenbus_dev_data { #define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) char read_buffer[PAGE_SIZE]; unsigned int read_cons, read_prod; - int read_waitq; }; -#if 0 -static struct proc_dir_entry *xenbus_dev_intf; -#endif + static int xenbus_dev_read(struct cdev *dev, struct uio *uio, int ioflag) { - int i = 0; + int error; struct xenbus_dev_data *u = dev->si_drv1; - if (wait_event_interruptible(&u->read_waitq, - u->read_prod != u->read_cons)) - return EINTR; + while (u->read_prod == u->read_cons) { + error = tsleep(u, PCATCH, "xbdread", hz/10); + if (error && error != EWOULDBLOCK) + return (error); + } - for (i = 0; i < uio->uio_iov[0].iov_len; i++) { + while (uio->uio_resid > 0) { if (u->read_cons == u->read_prod) break; - copyout(&u->read_buffer[MASK_READ_IDX(u->read_cons)], (char *)uio->uio_iov[0].iov_base+i, 1); + error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], + 1, uio); + if (error) + return (error); u->read_cons++; - uio->uio_resid--; } - return 0; + return (0); } -static void queue_reply(struct xenbus_dev_data *u, - char *data, unsigned int len) +static void +queue_reply(struct xenbus_dev_data *u, char *data, unsigned int len) { int i; for (i = 0; i < len; i++, u->read_prod++) u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; - BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer)); + KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), + ("xenstore reply too big")); - wakeup(&u->read_waitq); + wakeup(u); } static int xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag) { - int err = 0; + int error; struct xenbus_dev_data *u = dev->si_drv1; struct xenbus_dev_transaction *trans; void *reply; - int len = uio->uio_iov[0].iov_len; + int len = uio->uio_resid; if ((len + u->len) > sizeof(u->u.buffer)) - return EINVAL; + return (EINVAL); - if (copyin(u->u.buffer + u->len, uio->uio_iov[0].iov_base, len) != 0) - return EFAULT; + error = uiomove(u->u.buffer + u->len, len, uio); + if (error) + return (error); u->len += len; if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) - return len; + return (0); switch (u->u.msg.type) { case XS_TRANSACTION_START: @@ -147,67 +141,59 @@ xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag) case XS_MKDIR: case XS_RM: case XS_SET_PERMS: - reply = xenbus_dev_request_and_reply(&u->u.msg); - if (IS_ERR(reply)) { - err = PTR_ERR(reply); - } else { + error = xenbus_dev_request_and_reply(&u->u.msg, &reply); + if (!error) { if (u->u.msg.type == XS_TRANSACTION_START) { - trans = kmalloc(sizeof(*trans), GFP_KERNEL); - trans->handle.id = simple_strtoul(reply, NULL, 0); + trans = malloc(sizeof(*trans), M_DEVBUF, + M_WAITOK); + trans->handle.id = strtoul(reply, NULL, 0); LIST_INSERT_HEAD(&u->transactions, trans, list); } else if (u->u.msg.type == XS_TRANSACTION_END) { - LIST_FOREACH(trans, &u->transactions, - list) - if (trans->handle.id == - u->u.msg.tx_id) + LIST_FOREACH(trans, &u->transactions, list) + if (trans->handle.id == u->u.msg.tx_id) break; #if 0 /* XXX does this mean the list is empty? */ BUG_ON(&trans->list == &u->transactions); #endif LIST_REMOVE(trans, list); - kfree(trans); + free(trans, M_DEVBUF); } queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); queue_reply(u, (char *)reply, u->u.msg.len); - kfree(reply); + free(reply, M_DEVBUF); } break; default: - err = EINVAL; + error = EINVAL; break; } - if (err == 0) { + if (error == 0) u->len = 0; - err = len; - } - return err; + return (error); } -static int xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +static int +xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct xenbus_dev_data *u; - if (xen_start_info->store_evtchn == 0) - return ENOENT; + if (xen_store_evtchn == 0) + return (ENOENT); #if 0 /* XXX figure out if equiv needed */ nonseekable_open(inode, filp); #endif - u = kmalloc(sizeof(*u), GFP_KERNEL); - if (u == NULL) - return ENOMEM; - - memset(u, 0, sizeof(*u)); + u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK|M_ZERO); LIST_INIT(&u->transactions); - dev->si_drv1 = u; - return 0; + return (0); } -static int xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) +static int +xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct xenbus_dev_data *u = dev->si_drv1; struct xenbus_dev_transaction *trans, *tmp; @@ -215,11 +201,11 @@ static int xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thr LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { xenbus_transaction_end(trans->handle, 1); LIST_REMOVE(trans, list); - kfree(trans); + free(trans, M_DEVBUF); } - kfree(u); - return 0; + free(u, M_DEVBUF); + return (0); } static struct cdevsw xenbus_dev_cdevsw = { @@ -234,21 +220,10 @@ static struct cdevsw xenbus_dev_cdevsw = { static int xenbus_dev_sysinit(void) { - make_dev(&xenbus_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, "xenbus"); + make_dev(&xenbus_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, + "xen/xenbus"); - return 0; + return (0); } -SYSINIT(xenbus_dev_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, xenbus_dev_sysinit, NULL); -/* SYSINIT NEEDED XXX */ - - - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ +SYSINIT(xenbus_dev_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, + xenbus_dev_sysinit, NULL); diff --git a/sys/xen/xenbus/xenbus_probe.c b/sys/xen/xenbus/xenbus_probe.c index e57e6e3..3d2cb4b 100644 --- a/sys/xen/xenbus/xenbus_probe.c +++ b/sys/xen/xenbus/xenbus_probe.c @@ -88,9 +88,7 @@ kasprintf(const char *fmt, ...) len = vsnprintf(dummy, 0, fmt, ap); va_end(ap); - p = kmalloc(len + 1, GFP_KERNEL); - if (!p) - return NULL; + p = malloc(len + 1, M_DEVBUF, M_WAITOK); va_start(ap, fmt); vsprintf(p, fmt, ap); va_end(ap); @@ -187,6 +185,7 @@ xenbus_add_device(device_t dev, const char *bus, struct xenbus_device_ivars *ivars; enum xenbus_state state; char *statepath; + int error; ivars = malloc(sizeof(struct xenbus_device_ivars), M_DEVBUF, M_ZERO|M_WAITOK); @@ -217,17 +216,19 @@ xenbus_add_device(device_t dev, const char *bus, /* * Find the backend details */ - xenbus_gather(XBT_NIL, ivars->xd_node, + error = xenbus_gather(XBT_NIL, ivars->xd_node, "backend-id", "%i", &ivars->xd_otherend_id, "backend", NULL, &ivars->xd_otherend_path, NULL); + if (error) + return (error); sx_init(&ivars->xd_lock, "xdlock"); ivars->xd_type = strdup(type, M_DEVBUF); ivars->xd_state = XenbusStateInitialising; statepath = malloc(strlen(ivars->xd_otherend_path) - + strlen("/state") + 1, M_DEVBUF, M_NOWAIT); + + strlen("/state") + 1, M_DEVBUF, M_WAITOK); sprintf(statepath, "%s/state", ivars->xd_otherend_path); ivars->xd_otherend_watch.node = statepath; @@ -245,10 +246,11 @@ xenbus_enumerate_type(device_t dev, const char *bus, const char *type) { char **dir; unsigned int i, count; + int error; - dir = xenbus_directory(XBT_NIL, bus, type, &count); - if (IS_ERR(dir)) - return (EINVAL); + error = xenbus_directory(XBT_NIL, bus, type, &count, &dir); + if (error) + return (error); for (i = 0; i < count; i++) xenbus_add_device(dev, bus, type, dir[i]); @@ -262,10 +264,11 @@ xenbus_enumerate_bus(device_t dev, const char *bus) { char **dir; unsigned int i, count; + int error; - dir = xenbus_directory(XBT_NIL, bus, "", &count); - if (IS_ERR(dir)) - return (EINVAL); + error = xenbus_directory(XBT_NIL, bus, "", &count, &dir); + if (error) + return (error); for (i = 0; i < count; i++) { xenbus_enumerate_type(dev, bus, dir[i]); } @@ -386,28 +389,90 @@ xenbus_attach(device_t dev) return (0); } -static void +static int xenbus_suspend(device_t dev) { + int error; + DPRINTK(""); - panic("implement me"); -#if 0 - bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); - bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev); -#endif + + error = bus_generic_suspend(dev); + if (error) + return (error); + xs_suspend(); + + return (0); } -static void +static int xenbus_resume(device_t dev) { + device_t *kids; + struct xenbus_device_ivars *ivars; + int i, count, error; + char *statepath; + xb_init_comms(); xs_resume(); - panic("implement me"); + + /* + * We must re-examine each device and find the new path for + * its backend. + */ + if (device_get_children(dev, &kids, &count) == 0) { + for (i = 0; i < count; i++) { + if (device_get_state(kids[i]) == DS_NOTPRESENT) + continue; + + ivars = device_get_ivars(kids[i]); + + unregister_xenbus_watch( + &ivars->xd_otherend_watch); + ivars->xd_state = XenbusStateInitialising; + + /* + * Find the new backend details and + * re-register our watch. + */ + free(ivars->xd_otherend_path, M_DEVBUF); + error = xenbus_gather(XBT_NIL, ivars->xd_node, + "backend-id", "%i", &ivars->xd_otherend_id, + "backend", NULL, &ivars->xd_otherend_path, + NULL); + if (error) + return (error); + + DEVICE_RESUME(kids[i]); + + statepath = malloc(strlen(ivars->xd_otherend_path) + + strlen("/state") + 1, M_DEVBUF, M_WAITOK); + sprintf(statepath, "%s/state", ivars->xd_otherend_path); + + free(ivars->xd_otherend_watch.node, M_DEVBUF); + ivars->xd_otherend_watch.node = statepath; + register_xenbus_watch( + &ivars->xd_otherend_watch); + #if 0 - bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); - bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); -#endif + /* + * Can't do this yet since we are running in + * the xenwatch thread and if we sleep here, + * we will stop delivering watch notifications + * and the device will never come back online. + */ + sx_xlock(&ivars->xd_lock); + while (ivars->xd_state != XenbusStateClosed + && ivars->xd_state != XenbusStateConnected) + sx_sleep(&ivars->xd_state, &ivars->xd_lock, + 0, "xdresume", 0); + sx_xunlock(&ivars->xd_lock); +#endif + } + free(kids, M_TEMP); + } + + return (0); } static int @@ -433,9 +498,11 @@ xenbus_read_ivar(device_t dev, device_t child, int index, case XENBUS_IVAR_NODE: *result = (uintptr_t) ivars->xd_node; return (0); + case XENBUS_IVAR_TYPE: *result = (uintptr_t) ivars->xd_type; return (0); + case XENBUS_IVAR_STATE: *result = (uintptr_t) ivars->xd_state; return (0); @@ -468,8 +535,8 @@ xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) goto out; error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state", - "%d", &currstate); - if (error < 0) + NULL, "%d", &currstate); + if (error) goto out; error = xenbus_printf(XBT_NIL, ivars->xd_node, "state", @@ -494,15 +561,14 @@ xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) */ return (EINVAL); } + return (ENOENT); } SYSCTL_DECL(_dev); SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); -#if 0 SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, ""); SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, ""); -#endif static device_method_t xenbus_methods[] = { /* Device interface */ diff --git a/sys/xen/xenbus/xenbus_probe_backend.c b/sys/xen/xenbus/xenbus_probe_backend.c index af83fe6..20cc49f 100644 --- a/sys/xen/xenbus/xenbus_probe_backend.c +++ b/sys/xen/xenbus/xenbus_probe_backend.c @@ -57,10 +57,11 @@ __FBSDID("$FreeBSD$"); #include <sys/sx.h> #include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> -#include <machine/xen/evtchn.h> +#include <xen/hypervisor.h> +#include <machine/xen/xenbus.h> #include <machine/stdarg.h> +#include <xen/evtchn.h> #include <xen/xenbus/xenbus_comms.h> #define BUG_ON PANIC_IF diff --git a/sys/xen/xenbus/xenbus_xs.c b/sys/xen/xenbus/xenbus_xs.c index 332a509..9e0f779 100644 --- a/sys/xen/xenbus/xenbus_xs.c +++ b/sys/xen/xenbus/xenbus_xs.c @@ -33,91 +33,77 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/types.h> -#include <sys/cdefs.h> -#include <sys/unistd.h> -#include <sys/errno.h> #include <sys/uio.h> #include <sys/kernel.h> -#include <sys/time.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/sx.h> -#include <sys/sema.h> #include <sys/syslog.h> #include <sys/malloc.h> -#include <sys/libkern.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/kthread.h> +#include <sys/unistd.h> #include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> +#include <xen/hypervisor.h> #include <machine/stdarg.h> #include <xen/xenbus/xenbusvar.h> #include <xen/xenbus/xenbus_comms.h> -static int xs_process_msg(enum xsd_sockmsg_type *type); +#include <xen/interface/hvm/params.h> -#define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK) -#define BUG_ON PANIC_IF -#define DEFINE_SPINLOCK(lock) struct mtx lock -#define u32 uint32_t -#define list_del(head, ent) TAILQ_REMOVE(head, ent, list) -#define simple_strtoul strtoul -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -#define list_empty TAILQ_EMPTY +#include <vm/vm.h> +#include <vm/pmap.h> + +static int xs_process_msg(enum xsd_sockmsg_type *type); -#define streq(a, b) (strcmp((a), (b)) == 0) int xenwatch_running = 0; int xenbus_running = 0; - -struct kvec { - const void *iov_base; - size_t iov_len; -}; +int xen_store_evtchn; struct xs_stored_msg { - TAILQ_ENTRY(xs_stored_msg) list; - - struct xsd_sockmsg hdr; - - union { - /* Queued replies. */ - struct { - char *body; - } reply; - - /* Queued watch events. */ - struct { - struct xenbus_watch *handle; - char **vec; - unsigned int vec_size; - } watch; - } u; + TAILQ_ENTRY(xs_stored_msg) list; + + struct xsd_sockmsg hdr; + + union { + /* Queued replies. */ + struct { + char *body; + } reply; + + /* Queued watch events. */ + struct { + struct xenbus_watch *handle; + char **vec; + unsigned int vec_size; + } watch; + } u; }; struct xs_handle { - /* A list of replies. Currently only one will ever be outstanding. */ - TAILQ_HEAD(xs_handle_list, xs_stored_msg) reply_list; - struct mtx reply_lock; - int reply_waitq; + /* A list of replies. Currently only one will ever be outstanding. */ + TAILQ_HEAD(xs_handle_list, xs_stored_msg) reply_list; + struct mtx reply_lock; + int reply_waitq; - /* One request at a time. */ - struct sx request_mutex; + /* One request at a time. */ + struct sx request_mutex; - /* Protect transactions against save/restore. */ - struct sx suspend_mutex; + /* Protect transactions against save/restore. */ + struct sx suspend_mutex; }; static struct xs_handle xs_state; /* List of registered watches, and a lock to protect it. */ static LIST_HEAD(watch_list_head, xenbus_watch) watches; -static DEFINE_SPINLOCK(watches_lock); +static struct mtx watches_lock; /* List of pending watch callback events, and a lock to protect it. */ static TAILQ_HEAD(event_list_head, xs_stored_msg) watch_events; -static DEFINE_SPINLOCK(watch_events_lock); +static struct mtx watch_events_lock; + /* * Details of the xenwatch callback kernel thread. The thread waits on the * watch_events_waitq for work to do (queued on watch_events list). When it @@ -128,831 +114,814 @@ static pid_t xenwatch_pid; struct sx xenwatch_mutex; static int watch_events_waitq; -static int get_error(const char *errorstring) +#define xsd_error_count (sizeof(xsd_errors) / sizeof(xsd_errors[0])) + +static int +xs_get_error(const char *errorstring) { - unsigned int i; + unsigned int i; - for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) { - if (i == ARRAY_SIZE(xsd_errors) - 1) { - log(LOG_WARNING, "XENBUS xen store gave: unknown error %s", - errorstring); - return EINVAL; - } - } - return xsd_errors[i].errnum; + for (i = 0; i < xsd_error_count; i++) { + if (!strcmp(errorstring, xsd_errors[i].errstring)) + return (xsd_errors[i].errnum); + } + log(LOG_WARNING, "XENBUS xen store gave: unknown error %s", + errorstring); + return (EINVAL); } -extern void idle_block(void); extern void kdb_backtrace(void); -static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) +static int +xs_read_reply(enum xsd_sockmsg_type *type, unsigned int *len, void **result) { - struct xs_stored_msg *msg; - char *body; - int i, err; - enum xsd_sockmsg_type itype = *type; - - printf("read_reply "); - if (xenbus_running == 0) { - /* - * Give other domain time to run :-/ - */ - for (i = 0; i < 1000000 && (xenbus_running == 0); i++) { - err = xs_process_msg(type); - - if ((err == 0) - && (*type != XS_WATCH_EVENT)) - break; - - HYPERVISOR_yield(); + struct xs_stored_msg *msg; + char *body; + int error; + + mtx_lock(&xs_state.reply_lock); + + while (TAILQ_EMPTY(&xs_state.reply_list)) { + while (TAILQ_EMPTY(&xs_state.reply_list)) { + error = mtx_sleep(&xs_state.reply_waitq, + &xs_state.reply_lock, + PCATCH, "xswait", hz/10); + if (error && error != EWOULDBLOCK) { + mtx_unlock(&xs_state.reply_lock); + return (error); } - if (list_empty(&xs_state.reply_list)) { - printf("giving up and returning an error type=%d\n", - *type); - kdb_backtrace(); - return (ERR_PTR(-1)); - } + } + } - mtx_lock(&xs_state.reply_lock); - if (xenbus_running) { - while (list_empty(&xs_state.reply_list)) { - mtx_unlock(&xs_state.reply_lock); - wait_event_interruptible(&xs_state.reply_waitq, - !list_empty(&xs_state.reply_list)); - - mtx_lock(&xs_state.reply_lock); - } - } - msg = TAILQ_FIRST(&xs_state.reply_list); - list_del(&xs_state.reply_list, msg); + msg = TAILQ_FIRST(&xs_state.reply_list); + TAILQ_REMOVE(&xs_state.reply_list, msg, list); - mtx_unlock(&xs_state.reply_lock); + mtx_unlock(&xs_state.reply_lock); - printf("itype=%d htype=%d ", itype, msg->hdr.type); - *type = msg->hdr.type; - if (len) - *len = msg->hdr.len; - body = msg->u.reply.body; + *type = msg->hdr.type; + if (len) + *len = msg->hdr.len; + body = msg->u.reply.body; - kfree(msg); - if (len) - printf("len=%d\n", *len); - else - printf("len=NULL\n"); - return body; + free(msg, M_DEVBUF); + *result = body; + return (0); } #if 0 /* Emergency write. UNUSED*/ void xenbus_debug_write(const char *str, unsigned int count) { - struct xsd_sockmsg msg = { 0 }; + struct xsd_sockmsg msg = { 0 }; - msg.type = XS_DEBUG; - msg.len = sizeof("print") + count + 1; + msg.type = XS_DEBUG; + msg.len = sizeof("print") + count + 1; - sx_xlock(&xs_state.request_mutex); - xb_write(&msg, sizeof(msg)); - xb_write("print", sizeof("print")); - xb_write(str, count); - xb_write("", 1); - sx_xunlock(&xs_state.request_mutex); + sx_xlock(&xs_state.request_mutex); + xb_write(&msg, sizeof(msg)); + xb_write("print", sizeof("print")); + xb_write(str, count); + xb_write("", 1); + sx_xunlock(&xs_state.request_mutex); } #endif -void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) + +int +xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result) { - void *ret; - struct xsd_sockmsg req_msg = *msg; - int err; + struct xsd_sockmsg req_msg = *msg; + int error; - if (req_msg.type == XS_TRANSACTION_START) - sx_slock(&xs_state.suspend_mutex); + if (req_msg.type == XS_TRANSACTION_START) + sx_slock(&xs_state.suspend_mutex); - sx_xlock(&xs_state.request_mutex); + sx_xlock(&xs_state.request_mutex); - err = xb_write(msg, sizeof(*msg) + msg->len); - if (err) { - msg->type = XS_ERROR; - ret = ERR_PTR(err); - } else { - ret = read_reply(&msg->type, &msg->len); - } + error = xb_write(msg, sizeof(*msg) + msg->len, &xs_state.request_mutex.lock_object); + if (error) { + msg->type = XS_ERROR; + } else { + error = xs_read_reply(&msg->type, &msg->len, result); + } - sx_xunlock(&xs_state.request_mutex); + sx_xunlock(&xs_state.request_mutex); - if ((msg->type == XS_TRANSACTION_END) || - ((req_msg.type == XS_TRANSACTION_START) && - (msg->type == XS_ERROR))) - sx_sunlock(&xs_state.suspend_mutex); + if ((msg->type == XS_TRANSACTION_END) || + ((req_msg.type == XS_TRANSACTION_START) && + (msg->type == XS_ERROR))) + sx_sunlock(&xs_state.suspend_mutex); - return ret; + return (error); } -static int xenwatch_inline; - -/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ -static void *xs_talkv(struct xenbus_transaction t, - enum xsd_sockmsg_type type, - const struct kvec *iovec, - unsigned int num_vecs, - unsigned int *len) +/* + * Send message to xs. The reply is returned in *result and should be + * fred with free(*result, M_DEVBUF). Return zero on success or an + * error code on failure. + */ +static int +xs_talkv(struct xenbus_transaction t, enum xsd_sockmsg_type type, + const struct iovec *iovec, unsigned int num_vecs, + unsigned int *len, void **result) { - struct xsd_sockmsg msg; - void *ret = NULL; - unsigned int i; - int err; - - msg.tx_id = t.id; - msg.req_id = 0; - msg.type = type; - msg.len = 0; - for (i = 0; i < num_vecs; i++) - msg.len += iovec[i].iov_len; - - printf("xs_talkv "); - - sx_xlock(&xs_state.request_mutex); - - err = xb_write(&msg, sizeof(msg)); - if (err) { - sx_xunlock(&xs_state.request_mutex); - printf("xs_talkv failed %d\n", err); - return ERR_PTR(err); - } - - for (i = 0; i < num_vecs; i++) { - err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; - if (err) { - sx_xunlock(&xs_state.request_mutex); - printf("xs_talkv failed %d\n", err); - return ERR_PTR(err); - } + struct xsd_sockmsg msg; + void *ret = NULL; + unsigned int i; + int error; + + msg.tx_id = t.id; + msg.req_id = 0; + msg.type = type; + msg.len = 0; + for (i = 0; i < num_vecs; i++) + msg.len += iovec[i].iov_len; + + sx_xlock(&xs_state.request_mutex); + + error = xb_write(&msg, sizeof(msg), &xs_state.request_mutex.lock_object); + if (error) { + sx_xunlock(&xs_state.request_mutex); + printf("xs_talkv failed %d\n", error); + return (error); + } + + for (i = 0; i < num_vecs; i++) { + error = xb_write(iovec[i].iov_base, iovec[i].iov_len, &xs_state.request_mutex.lock_object); + if (error) { + sx_xunlock(&xs_state.request_mutex); + printf("xs_talkv failed %d\n", error); + return (error); } + } - ret = read_reply(&msg.type, len); + error = xs_read_reply(&msg.type, len, &ret); - sx_xunlock(&xs_state.request_mutex); + sx_xunlock(&xs_state.request_mutex); - if (IS_ERR(ret)) - return ret; + if (error) + return (error); - if (msg.type == XS_ERROR) { - err = get_error(ret); - kfree(ret); - return ERR_PTR(-err); - } + if (msg.type == XS_ERROR) { + error = xs_get_error(ret); + free(ret, M_DEVBUF); + return (error); + } - if ((xenwatch_running == 0) && (xenwatch_inline == 0)) { - xenwatch_inline = 1; - while (!TAILQ_EMPTY(&watch_events) - && xenwatch_running == 0) { +#if 0 + if ((xenwatch_running == 0) && (xenwatch_inline == 0)) { + xenwatch_inline = 1; + while (!TAILQ_EMPTY(&watch_events) + && xenwatch_running == 0) { - struct xs_stored_msg *wmsg = TAILQ_FIRST(&watch_events); - list_del(&watch_events, wmsg); - printf("handling %p ...", wmsg->u.watch.handle->callback); + struct xs_stored_msg *wmsg = TAILQ_FIRST(&watch_events); + TAILQ_REMOVE(&watch_events, wmsg, list); - wmsg->u.watch.handle->callback( - wmsg->u.watch.handle, - (const char **)wmsg->u.watch.vec, - wmsg->u.watch.vec_size); - printf("... %p done\n", wmsg->u.watch.handle->callback); - kfree(wmsg->u.watch.vec); - kfree(wmsg); - } - xenwatch_inline = 0; + wmsg->u.watch.handle->callback( + wmsg->u.watch.handle, + (const char **)wmsg->u.watch.vec, + wmsg->u.watch.vec_size); + free(wmsg->u.watch.vec, M_DEVBUF); + free(wmsg, M_DEVBUF); } - BUG_ON(msg.type != type); + xenwatch_inline = 0; + } +#endif + KASSERT(msg.type == type, ("bad xenstore message type")); - return ret; + if (result) + *result = ret; + else + free(ret, M_DEVBUF); + + return (0); } /* Simplified version of xs_talkv: single message. */ -static void *xs_single(struct xenbus_transaction t, - enum xsd_sockmsg_type type, - const char *string, - unsigned int *len) +static int +xs_single(struct xenbus_transaction t, enum xsd_sockmsg_type type, + const char *string, unsigned int *len, void **result) { - struct kvec iovec; + struct iovec iovec; - printf("xs_single %s ", string); - iovec.iov_base = (const void *)string; - iovec.iov_len = strlen(string) + 1; - return xs_talkv(t, type, &iovec, 1, len); -} + iovec.iov_base = (void *)(uintptr_t) string; + iovec.iov_len = strlen(string) + 1; -/* Many commands only need an ack, don't care what it says. */ -static int xs_error(char *reply) -{ - if (IS_ERR(reply)) - return PTR_ERR(reply); - kfree(reply); - return 0; + return (xs_talkv(t, type, &iovec, 1, len, result)); } -static unsigned int count_strings(const char *strings, unsigned int len) +static unsigned int +count_strings(const char *strings, unsigned int len) { - unsigned int num; - const char *p; + unsigned int num; + const char *p; - for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) - num++; + for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) + num++; - return num; + return num; } /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ -static char *join(const char *dir, const char *name) +static char * +join(const char *dir, const char *name) { - char *buffer; + char *buffer; - buffer = kmalloc(strlen(dir) + strlen("/") + strlen(name) + 1, - GFP_KERNEL); - if (buffer == NULL) - return ERR_PTR(-ENOMEM); + buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1, + M_DEVBUF, M_WAITOK); - strcpy(buffer, dir); - if (!streq(name, "")) { - strcat(buffer, "/"); - strcat(buffer, name); - } + strcpy(buffer, dir); + if (strcmp(name, "")) { + strcat(buffer, "/"); + strcat(buffer, name); + } - return buffer; + return (buffer); } -static char **split(char *strings, unsigned int len, unsigned int *num) +static char ** +split(char *strings, unsigned int len, unsigned int *num) { - char *p, **ret; + char *p, **ret; - /* Count the strings. */ - *num = count_strings(strings, len) + 1; + /* Count the strings. */ + *num = count_strings(strings, len) + 1; - /* Transfer to one big alloc for easy freeing. */ - ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); - if (!ret) { - kfree(strings); - return ERR_PTR(-ENOMEM); - } - memcpy(&ret[*num], strings, len); - kfree(strings); + /* Transfer to one big alloc for easy freeing. */ + ret = malloc(*num * sizeof(char *) + len, M_DEVBUF, M_WAITOK); + memcpy(&ret[*num], strings, len); + free(strings, M_DEVBUF); - strings = (char *)&ret[*num]; - for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) - ret[(*num)++] = p; + strings = (char *)&ret[*num]; + for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) + ret[(*num)++] = p; - ret[*num] = strings + len; + ret[*num] = strings + len; - return ret; + return ret; } -char **xenbus_directory(struct xenbus_transaction t, - const char *dir, const char *node, unsigned int *num) +/* + * Return the contents of a directory in *result which should be freed + * with free(*result, M_DEVBUF). + */ +int +xenbus_directory(struct xenbus_transaction t, const char *dir, + const char *node, unsigned int *num, char ***result) { - char *strings, *path; - unsigned int len = 0; - - path = join(dir, node); - if (IS_ERR(path)) - return (char **)path; + char *strings, *path; + unsigned int len = 0; + int error; - strings = xs_single(t, XS_DIRECTORY, path, &len); - kfree(path); - if (IS_ERR(strings)) - return (char **)strings; + path = join(dir, node); + error = xs_single(t, XS_DIRECTORY, path, &len, (void **) &strings); + free(path, M_DEVBUF); + if (error) + return (error); - return split(strings, len, num); + *result = split(strings, len, num); + return (0); } -EXPORT_SYMBOL(xenbus_directory); -/* Check if a path exists. Return 1 if it does. */ -int xenbus_exists(struct xenbus_transaction t, - const char *dir, const char *node) +/* + * Check if a path exists. Return 1 if it does. + */ +int +xenbus_exists(struct xenbus_transaction t, const char *dir, const char *node) { - char **d; - int dir_n; + char **d; + int error, dir_n; - d = xenbus_directory(t, dir, node, &dir_n); - if (IS_ERR(d)) - return 0; - kfree(d); - return 1; + error = xenbus_directory(t, dir, node, &dir_n, &d); + if (error) + return (0); + free(d, M_DEVBUF); + return (1); } -EXPORT_SYMBOL(xenbus_exists); -/* Get the value of a single file. - * Returns a kmalloced value: call free() on it after use. - * len indicates length in bytes. +/* + * Get the value of a single file. Returns the contents in *result + * which should be freed with free(*result, M_DEVBUF) after use. + * The length of the value in bytes is returned in *len. */ -void *xenbus_read(struct xenbus_transaction t, - const char *dir, const char *node, unsigned int *len) +int +xenbus_read(struct xenbus_transaction t, const char *dir, const char *node, + unsigned int *len, void **result) { - char *path; - void *ret; - - path = join(dir, node); - if (IS_ERR(path)) - return (void *)path; + char *path; + void *ret; + int error; - printf("xs_read "); - ret = xs_single(t, XS_READ, path, len); - kfree(path); - return ret; + path = join(dir, node); + error = xs_single(t, XS_READ, path, len, &ret); + free(path, M_DEVBUF); + if (error) + return (error); + *result = ret; + return (0); } -EXPORT_SYMBOL(xenbus_read); -/* Write the value of a single file. - * Returns -err on failure. +/* + * Write the value of a single file. Returns error on failure. */ -int xenbus_write(struct xenbus_transaction t, - const char *dir, const char *node, const char *string) +int +xenbus_write(struct xenbus_transaction t, const char *dir, const char *node, + const char *string) { - char *path; - struct kvec iovec[2]; - int ret; + char *path; + struct iovec iovec[2]; + int error; + + path = join(dir, node); - path = join(dir, node); - if (IS_ERR(path)) - return PTR_ERR(path); + iovec[0].iov_base = (void *)(uintptr_t) path; + iovec[0].iov_len = strlen(path) + 1; + iovec[1].iov_base = (void *)(uintptr_t) string; + iovec[1].iov_len = strlen(string); - iovec[0].iov_base = path; - iovec[0].iov_len = strlen(path) + 1; - iovec[1].iov_base = string; - iovec[1].iov_len = strlen(string); + error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL); + free(path, M_DEVBUF); - printf("xenbus_write dir=%s val=%s ", dir, string); - ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); - kfree(path); - return ret; + return (error); } -EXPORT_SYMBOL(xenbus_write); -/* Create a new directory. */ -int xenbus_mkdir(struct xenbus_transaction t, - const char *dir, const char *node) +/* + * Create a new directory. + */ +int +xenbus_mkdir(struct xenbus_transaction t, const char *dir, const char *node) { - char *path; - int ret; + char *path; + int ret; - path = join(dir, node); - if (IS_ERR(path)) - return PTR_ERR(path); + path = join(dir, node); + ret = xs_single(t, XS_MKDIR, path, NULL, NULL); + free(path, M_DEVBUF); - ret = xs_error(xs_single(t, XS_MKDIR, path, NULL)); - kfree(path); - return ret; + return (ret); } -EXPORT_SYMBOL(xenbus_mkdir); -/* Destroy a file or directory (directories must be empty). */ -int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) +/* + * Destroy a file or directory (directories must be empty). + */ +int +xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) { - char *path; - int ret; + char *path; + int ret; - path = join(dir, node); - if (IS_ERR(path)) - return PTR_ERR(path); + path = join(dir, node); + ret = xs_single(t, XS_RM, path, NULL, NULL); + free(path, M_DEVBUF); - ret = xs_error(xs_single(t, XS_RM, path, NULL)); - kfree(path); - return ret; + return (ret); } -EXPORT_SYMBOL(xenbus_rm); -/* Start a transaction: changes by others will not be seen during this +/* + * Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. */ -int xenbus_transaction_start(struct xenbus_transaction *t) +int +xenbus_transaction_start(struct xenbus_transaction *t) { - char *id_str; + char *id_str; + int error; - sx_slock(&xs_state.suspend_mutex); - id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); - if (IS_ERR(id_str)) { - sx_sunlock(&xs_state.suspend_mutex); - return PTR_ERR(id_str); - } + sx_slock(&xs_state.suspend_mutex); + error = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL, + (void **) &id_str); + if (error) { + sx_sunlock(&xs_state.suspend_mutex); + return (error); + } - t->id = simple_strtoul(id_str, NULL, 0); - kfree(id_str); + t->id = strtoul(id_str, NULL, 0); + free(id_str, M_DEVBUF); - return 0; + return (0); } -EXPORT_SYMBOL(xenbus_transaction_start); -/* End a transaction. - * If abandon is true, transaction is discarded instead of committed. +/* + * End a transaction. If abandon is true, transaction is discarded + * instead of committed. */ int xenbus_transaction_end(struct xenbus_transaction t, int abort) { - char abortstr[2]; - int err; + char abortstr[2]; + int error; - if (abort) - strcpy(abortstr, "F"); - else - strcpy(abortstr, "T"); + if (abort) + strcpy(abortstr, "F"); + else + strcpy(abortstr, "T"); - printf("xenbus_transaction_end "); - err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); + error = xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL); - sx_sunlock(&xs_state.suspend_mutex); + sx_sunlock(&xs_state.suspend_mutex); - return err; + return (error); } -EXPORT_SYMBOL(xenbus_transaction_end); -/* Single read and scanf: returns -errno or num scanned. */ -int xenbus_scanf(struct xenbus_transaction t, - const char *dir, const char *node, const char *fmt, ...) +/* Single read and scanf: returns zero or errno. */ +int +xenbus_scanf(struct xenbus_transaction t, + const char *dir, const char *node, int *scancountp, const char *fmt, ...) { - va_list ap; - int ret; - char *val; - - val = xenbus_read(t, dir, node, NULL); - if (IS_ERR(val)) - return PTR_ERR(val); - - va_start(ap, fmt); - ret = vsscanf(val, fmt, ap); - va_end(ap); - kfree(val); - /* Distinctive errno. */ - if (ret == 0) - return -ERANGE; - return ret; -} -EXPORT_SYMBOL(xenbus_scanf); - -/* Single printf and write: returns -errno or 0. */ -int xenbus_printf(struct xenbus_transaction t, - const char *dir, const char *node, const char *fmt, ...) + va_list ap; + int error, ns; + char *val; + + error = xenbus_read(t, dir, node, NULL, (void **) &val); + if (error) + return (error); + + va_start(ap, fmt); + ns = vsscanf(val, fmt, ap); + va_end(ap); + free(val, M_DEVBUF); + /* Distinctive errno. */ + if (ns == 0) + return (ERANGE); + if (scancountp) + *scancountp = ns; + return (0); +} + +/* Single printf and write: returns zero or errno. */ +int +xenbus_printf(struct xenbus_transaction t, + const char *dir, const char *node, const char *fmt, ...) { - va_list ap; - int ret; + va_list ap; + int error, ret; #define PRINTF_BUFFER_SIZE 4096 - char *printf_buffer; + char *printf_buffer; - printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); - if (printf_buffer == NULL) - return -ENOMEM; + printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK); - va_start(ap, fmt); - ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); - va_end(ap); + va_start(ap, fmt); + ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); + va_end(ap); - BUG_ON(ret > PRINTF_BUFFER_SIZE-1); - ret = xenbus_write(t, dir, node, printf_buffer); + KASSERT(ret <= PRINTF_BUFFER_SIZE-1, ("xenbus_printf: message too large")); + error = xenbus_write(t, dir, node, printf_buffer); - kfree(printf_buffer); + free(printf_buffer, M_DEVBUF); - return ret; + return (error); } -EXPORT_SYMBOL(xenbus_printf); /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ -int xenbus_gather(struct xenbus_transaction t, const char *dir, ...) +int +xenbus_gather(struct xenbus_transaction t, const char *dir, ...) { - va_list ap; - const char *name; - int i, ret = 0; + va_list ap; + const char *name; + int error, i; - for (i = 0; i < 10000; i++) - HYPERVISOR_yield(); + for (i = 0; i < 10000; i++) + HYPERVISOR_yield(); - printf("gather "); - va_start(ap, dir); - while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { - const char *fmt = va_arg(ap, char *); - void *result = va_arg(ap, void *); - char *p; - - p = xenbus_read(t, dir, name, NULL); - if (IS_ERR(p)) { - ret = PTR_ERR(p); - break; - } - printf(" %s ", p); - if (fmt) { - if (sscanf(p, fmt, result) == 0) - ret = -EINVAL; - kfree(p); - } else - *(char **)result = p; - } - va_end(ap); - printf("\n"); - return ret; -} -EXPORT_SYMBOL(xenbus_gather); - -static int xs_watch(const char *path, const char *token) + va_start(ap, dir); + error = 0; + while (error == 0 && (name = va_arg(ap, char *)) != NULL) { + const char *fmt = va_arg(ap, char *); + void *result = va_arg(ap, void *); + char *p; + + error = xenbus_read(t, dir, name, NULL, (void **) &p); + if (error) + break; + + if (fmt) { + if (sscanf(p, fmt, result) == 0) + error = EINVAL; + free(p, M_DEVBUF); + } else + *(char **)result = p; + } + va_end(ap); + + return (error); +} + +static int +xs_watch(const char *path, const char *token) { - struct kvec iov[2]; + struct iovec iov[2]; - iov[0].iov_base = path; - iov[0].iov_len = strlen(path) + 1; - iov[1].iov_base = token; - iov[1].iov_len = strlen(token) + 1; + iov[0].iov_base = (void *)(uintptr_t) path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (void *)(uintptr_t) token; + iov[1].iov_len = strlen(token) + 1; - return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov, - ARRAY_SIZE(iov), NULL)); + return (xs_talkv(XBT_NIL, XS_WATCH, iov, 2, NULL, NULL)); } -static int xs_unwatch(const char *path, const char *token) +static int +xs_unwatch(const char *path, const char *token) { - struct kvec iov[2]; + struct iovec iov[2]; - iov[0].iov_base = path; - iov[0].iov_len = strlen(path) + 1; - iov[1].iov_base = token; - iov[1].iov_len = strlen(token) + 1; + iov[0].iov_base = (void *)(uintptr_t) path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (void *)(uintptr_t) token; + iov[1].iov_len = strlen(token) + 1; - return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov, - ARRAY_SIZE(iov), NULL)); + return (xs_talkv(XBT_NIL, XS_UNWATCH, iov, 2, NULL, NULL)); } -static struct xenbus_watch *find_watch(const char *token) +static struct xenbus_watch * +find_watch(const char *token) { - struct xenbus_watch *i, *cmp; + struct xenbus_watch *i, *cmp; - cmp = (void *)simple_strtoul(token, NULL, 16); + cmp = (void *)strtoul(token, NULL, 16); - LIST_FOREACH(i, &watches, list) - if (i == cmp) - return i; + LIST_FOREACH(i, &watches, list) + if (i == cmp) + return (i); - return NULL; + return (NULL); } /* Register callback to watch this node. */ -int register_xenbus_watch(struct xenbus_watch *watch) +int +register_xenbus_watch(struct xenbus_watch *watch) { - /* Pointer in ascii is the token. */ - char token[sizeof(watch) * 2 + 1]; - int err; + /* Pointer in ascii is the token. */ + char token[sizeof(watch) * 2 + 1]; + int error; - sprintf(token, "%lX", (long)watch); + sprintf(token, "%lX", (long)watch); - sx_slock(&xs_state.suspend_mutex); + sx_slock(&xs_state.suspend_mutex); - mtx_lock(&watches_lock); - BUG_ON(find_watch(token) != NULL); - LIST_INSERT_HEAD(&watches, watch, list); - mtx_unlock(&watches_lock); + mtx_lock(&watches_lock); + KASSERT(find_watch(token) == NULL, ("watch already registered")); + LIST_INSERT_HEAD(&watches, watch, list); + mtx_unlock(&watches_lock); - err = xs_watch(watch->node, token); + error = xs_watch(watch->node, token); - /* Ignore errors due to multiple registration. */ - if ((err != 0) && (err != -EEXIST)) { - mtx_lock(&watches_lock); - LIST_REMOVE(watch, list); - mtx_unlock(&watches_lock); - } + /* Ignore errors due to multiple registration. */ + if (error == EEXIST) { + mtx_lock(&watches_lock); + LIST_REMOVE(watch, list); + mtx_unlock(&watches_lock); + } - sx_sunlock(&xs_state.suspend_mutex); + sx_sunlock(&xs_state.suspend_mutex); - return err; + return (error); } -EXPORT_SYMBOL(register_xenbus_watch); -void unregister_xenbus_watch(struct xenbus_watch *watch) +void +unregister_xenbus_watch(struct xenbus_watch *watch) { - struct xs_stored_msg *msg, *tmp; - char token[sizeof(watch) * 2 + 1]; - int err; + struct xs_stored_msg *msg, *tmp; + char token[sizeof(watch) * 2 + 1]; + int error; - sprintf(token, "%lX", (long)watch); + sprintf(token, "%lX", (long)watch); - sx_slock(&xs_state.suspend_mutex); - - mtx_lock(&watches_lock); - BUG_ON(!find_watch(token)); - LIST_REMOVE(watch, list); - mtx_unlock(&watches_lock); + sx_slock(&xs_state.suspend_mutex); + + mtx_lock(&watches_lock); + KASSERT(find_watch(token), ("watch not registered")); + LIST_REMOVE(watch, list); + mtx_unlock(&watches_lock); + + error = xs_unwatch(watch->node, token); + if (error) + log(LOG_WARNING, "XENBUS Failed to release watch %s: %i\n", + watch->node, error); + + sx_sunlock(&xs_state.suspend_mutex); + + /* Cancel pending watch events. */ + mtx_lock(&watch_events_lock); + TAILQ_FOREACH_SAFE(msg, &watch_events, list, tmp) { + if (msg->u.watch.handle != watch) + continue; + TAILQ_REMOVE(&watch_events, msg, list); + free(msg->u.watch.vec, M_DEVBUF); + free(msg, M_DEVBUF); + } + mtx_unlock(&watch_events_lock); + + /* Flush any currently-executing callback, unless we are it. :-) */ + if (curproc->p_pid != xenwatch_pid) { + sx_xlock(&xenwatch_mutex); + sx_xunlock(&xenwatch_mutex); + } +} + +void +xs_suspend(void) +{ - err = xs_unwatch(watch->node, token); - if (err) - log(LOG_WARNING, "XENBUS Failed to release watch %s: %i\n", - watch->node, err); + sx_xlock(&xs_state.suspend_mutex); + sx_xlock(&xs_state.request_mutex); +} - sx_sunlock(&xs_state.suspend_mutex); +void +xs_resume(void) +{ + struct xenbus_watch *watch; + char token[sizeof(watch) * 2 + 1]; - /* Cancel pending watch events. */ - mtx_lock(&watch_events_lock); - TAILQ_FOREACH_SAFE(msg, &watch_events, list, tmp) { - if (msg->u.watch.handle != watch) - continue; - list_del(&watch_events, msg); - kfree(msg->u.watch.vec); - kfree(msg); - } - mtx_unlock(&watch_events_lock); + sx_xunlock(&xs_state.request_mutex); - /* Flush any currently-executing callback, unless we are it. :-) */ - if (curproc->p_pid != xenwatch_pid) { - sx_xlock(&xenwatch_mutex); - sx_xunlock(&xenwatch_mutex); - } -} -EXPORT_SYMBOL(unregister_xenbus_watch); + /* No need for watches_lock: the suspend_mutex is sufficient. */ + LIST_FOREACH(watch, &watches, list) { + sprintf(token, "%lX", (long)watch); + xs_watch(watch->node, token); + } -void xs_suspend(void) -{ - sx_xlock(&xs_state.suspend_mutex); - sx_xlock(&xs_state.request_mutex); + sx_xunlock(&xs_state.suspend_mutex); } -void xs_resume(void) +static void +xenwatch_thread(void *unused) { - struct xenbus_watch *watch; - char token[sizeof(watch) * 2 + 1]; + struct xs_stored_msg *msg; - sx_xunlock(&xs_state.request_mutex); + for (;;) { - /* No need for watches_lock: the suspend_mutex is sufficient. */ - LIST_FOREACH(watch, &watches, list) { - sprintf(token, "%lX", (long)watch); - xs_watch(watch->node, token); - } + mtx_lock(&watch_events_lock); + while (TAILQ_EMPTY(&watch_events)) + mtx_sleep(&watch_events_waitq, + &watch_events_lock, + PWAIT | PCATCH, "waitev", hz/10); - sx_xunlock(&xs_state.suspend_mutex); -} + mtx_unlock(&watch_events_lock); + sx_xlock(&xenwatch_mutex); -static void xenwatch_thread(void *unused) -{ - struct xs_stored_msg *msg; + mtx_lock(&watch_events_lock); + msg = TAILQ_FIRST(&watch_events); + if (msg) + TAILQ_REMOVE(&watch_events, msg, list); + mtx_unlock(&watch_events_lock); - DELAY(100000); - while (xenwatch_inline) { - printf("xenwatch inline still running\n"); - DELAY(100000); + if (msg != NULL) { + msg->u.watch.handle->callback( + msg->u.watch.handle, + (const char **)msg->u.watch.vec, + msg->u.watch.vec_size); + free(msg->u.watch.vec, M_DEVBUF); + free(msg, M_DEVBUF); } - - - for (;;) { - - while (list_empty(&watch_events)) - tsleep(&watch_events_waitq, - PWAIT | PCATCH, "waitev", hz/10); - - sx_xlock(&xenwatch_mutex); - - mtx_lock(&watch_events_lock); - msg = TAILQ_FIRST(&watch_events); - if (msg) - list_del(&watch_events, msg); - mtx_unlock(&watch_events_lock); - - if (msg != NULL) { - msg->u.watch.handle->callback( - msg->u.watch.handle, - (const char **)msg->u.watch.vec, - msg->u.watch.vec_size); - kfree(msg->u.watch.vec); - kfree(msg); - } - sx_xunlock(&xenwatch_mutex); - } + sx_xunlock(&xenwatch_mutex); + } } -static int xs_process_msg(enum xsd_sockmsg_type *type) +static int +xs_process_msg(enum xsd_sockmsg_type *type) { - struct xs_stored_msg *msg; - char *body; - int err; - - msg = kmalloc(sizeof(*msg), GFP_KERNEL); - if (msg == NULL) - return -ENOMEM; - - err = xb_read(&msg->hdr, sizeof(msg->hdr)); - if (err) { - kfree(msg); - return err; - } - - body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); - if (body == NULL) { - kfree(msg); - return -ENOMEM; - } + struct xs_stored_msg *msg; + char *body; + int error; - err = xb_read(body, msg->hdr.len); - if (err) { - kfree(body); - kfree(msg); - return err; - } - body[msg->hdr.len] = '\0'; - - *type = msg->hdr.type; - if (msg->hdr.type == XS_WATCH_EVENT) { - msg->u.watch.vec = split(body, msg->hdr.len, - &msg->u.watch.vec_size); - if (IS_ERR(msg->u.watch.vec)) { - kfree(msg); - return PTR_ERR(msg->u.watch.vec); - } + msg = malloc(sizeof(*msg), M_DEVBUF, M_WAITOK); + mtx_lock(&xs_state.reply_lock); + error = xb_read(&msg->hdr, sizeof(msg->hdr), &xs_state.reply_lock.lock_object); + mtx_unlock(&xs_state.reply_lock); + if (error) { + free(msg, M_DEVBUF); + return (error); + } + + body = malloc(msg->hdr.len + 1, M_DEVBUF, M_WAITOK); + mtx_lock(&xs_state.reply_lock); + error = xb_read(body, msg->hdr.len, &xs_state.reply_lock.lock_object); + mtx_unlock(&xs_state.reply_lock); + if (error) { + free(body, M_DEVBUF); + free(msg, M_DEVBUF); + return (error); + } + body[msg->hdr.len] = '\0'; + + *type = msg->hdr.type; + if (msg->hdr.type == XS_WATCH_EVENT) { + msg->u.watch.vec = split(body, msg->hdr.len, + &msg->u.watch.vec_size); - mtx_lock(&watches_lock); - msg->u.watch.handle = find_watch( - msg->u.watch.vec[XS_WATCH_TOKEN]); - if (msg->u.watch.handle != NULL) { - mtx_lock(&watch_events_lock); - TAILQ_INSERT_TAIL(&watch_events, msg, list); - wakeup(&watch_events_waitq); - mtx_unlock(&watch_events_lock); - } else { - kfree(msg->u.watch.vec); - kfree(msg); - } - mtx_unlock(&watches_lock); + mtx_lock(&watches_lock); + msg->u.watch.handle = find_watch( + msg->u.watch.vec[XS_WATCH_TOKEN]); + if (msg->u.watch.handle != NULL) { + mtx_lock(&watch_events_lock); + TAILQ_INSERT_TAIL(&watch_events, msg, list); + wakeup(&watch_events_waitq); + mtx_unlock(&watch_events_lock); } else { - printf("event=%d ", *type); - msg->u.reply.body = body; - mtx_lock(&xs_state.reply_lock); - TAILQ_INSERT_TAIL(&xs_state.reply_list, msg, list); - wakeup(&xs_state.reply_waitq); - mtx_unlock(&xs_state.reply_lock); + free(msg->u.watch.vec, M_DEVBUF); + free(msg, M_DEVBUF); } - if (*type == XS_WATCH_EVENT) - printf("\n"); + mtx_unlock(&watches_lock); + } else { + msg->u.reply.body = body; + mtx_lock(&xs_state.reply_lock); + TAILQ_INSERT_TAIL(&xs_state.reply_list, msg, list); + wakeup(&xs_state.reply_waitq); + mtx_unlock(&xs_state.reply_lock); + } - return 0; + return 0; } -static void xenbus_thread(void *unused) +static void +xenbus_thread(void *unused) { - int err; - enum xsd_sockmsg_type type; + int error; + enum xsd_sockmsg_type type; + xenbus_running = 1; - DELAY(10000); - xenbus_running = 1; - pause("xenbus", hz/10); + for (;;) { + error = xs_process_msg(&type); + if (error) + printf("XENBUS error %d while reading message\n", + error); + } +} - for (;;) { - err = xs_process_msg(&type); - if (err) - printf("XENBUS error %d while reading " - "message\n", err); +#ifdef XENHVM +static unsigned long xen_store_mfn; +char *xen_store; - } +static inline unsigned long +hvm_get_parameter(int index) +{ + struct xen_hvm_param xhv; + int error; + + xhv.domid = DOMID_SELF; + xhv.index = index; + error = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (error) { + printf("hvm_get_parameter: failed to get %d, error %d\n", + index, error); + return (0); + } + return (xhv.value); } -int xs_init(void) +#endif + +int +xs_init(void) { - int err; - struct proc *p; + int error; + struct proc *p; + +#ifdef XENHVM + xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); + xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); + xen_store = pmap_mapdev(xen_store_mfn * PAGE_SIZE, PAGE_SIZE); +#else + xen_store_evtchn = xen_start_info->store_evtchn; +#endif - TAILQ_INIT(&xs_state.reply_list); - TAILQ_INIT(&watch_events); - sx_init(&xenwatch_mutex, "xenwatch"); + TAILQ_INIT(&xs_state.reply_list); + TAILQ_INIT(&watch_events); + sx_init(&xenwatch_mutex, "xenwatch"); - mtx_init(&xs_state.reply_lock, "state reply", NULL, MTX_DEF); - sx_init(&xs_state.request_mutex, "xenstore request"); - sx_init(&xs_state.suspend_mutex, "xenstore suspend"); + mtx_init(&xs_state.reply_lock, "state reply", NULL, MTX_DEF); + sx_init(&xs_state.request_mutex, "xenstore request"); + sx_init(&xs_state.suspend_mutex, "xenstore suspend"); #if 0 - mtx_init(&xs_state.suspend_mutex, "xenstore suspend", NULL, MTX_DEF); - sema_init(&xs_state.request_mutex, 1, "xenstore request"); - sema_init(&xenwatch_mutex, 1, "xenwatch"); + mtx_init(&xs_state.suspend_mutex, "xenstore suspend", NULL, MTX_DEF); + sema_init(&xs_state.request_mutex, 1, "xenstore request"); + sema_init(&xenwatch_mutex, 1, "xenwatch"); #endif - mtx_init(&watches_lock, "watches", NULL, MTX_DEF); - mtx_init(&watch_events_lock, "watch events", NULL, MTX_DEF); + mtx_init(&watches_lock, "watches", NULL, MTX_DEF); + mtx_init(&watch_events_lock, "watch events", NULL, MTX_DEF); - /* Initialize the shared memory rings to talk to xenstored */ - err = xb_init_comms(); - if (err) - return err; - - err = kproc_create(xenwatch_thread, NULL, &p, - RFHIGHPID, 0, "xenwatch"); - if (err) - return err; - xenwatch_pid = p->p_pid; - - err = kproc_create(xenbus_thread, NULL, NULL, - RFHIGHPID, 0, "xenbus"); + /* Initialize the shared memory rings to talk to xenstored */ + error = xb_init_comms(); + if (error) + return (error); + + xenwatch_running = 1; + error = kproc_create(xenwatch_thread, NULL, &p, + RFHIGHPID, 0, "xenwatch"); + if (error) + return (error); + xenwatch_pid = p->p_pid; + + error = kproc_create(xenbus_thread, NULL, NULL, + RFHIGHPID, 0, "xenbus"); - return err; + return (error); } - - -/* - * Local variables: - * c-file-style: "bsd" - * indent-tabs-mode: t - * c-indent-level: 4 - * c-basic-offset: 8 - * tab-width: 4 - * End: - */ diff --git a/sys/xen/xenbus/xenbusvar.h b/sys/xen/xenbus/xenbusvar.h index 1331c43..6511664 100644 --- a/sys/xen/xenbus/xenbusvar.h +++ b/sys/xen/xenbus/xenbusvar.h @@ -103,32 +103,37 @@ struct xenbus_transaction #define XBT_NIL ((struct xenbus_transaction) { 0 }) -char **xenbus_directory(struct xenbus_transaction t, - const char *dir, const char *node, unsigned int *num); -void *xenbus_read(struct xenbus_transaction t, - const char *dir, const char *node, unsigned int *len); -int xenbus_write(struct xenbus_transaction t, - const char *dir, const char *node, const char *string); -int xenbus_mkdir(struct xenbus_transaction t, - const char *dir, const char *node); -int xenbus_exists(struct xenbus_transaction t, - const char *dir, const char *node); +int xenbus_directory(struct xenbus_transaction t, const char *dir, + const char *node, unsigned int *num, char ***result); +int xenbus_read(struct xenbus_transaction t, const char *dir, + const char *node, unsigned int *len, void **result); +int xenbus_write(struct xenbus_transaction t, const char *dir, + const char *node, const char *string); +int xenbus_mkdir(struct xenbus_transaction t, const char *dir, + const char *node); +int xenbus_exists(struct xenbus_transaction t, const char *dir, + const char *node); int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node); int xenbus_transaction_start(struct xenbus_transaction *t); int xenbus_transaction_end(struct xenbus_transaction t, int abort); -/* Single read and scanf: returns -errno or num scanned if > 0. */ +/* + * Single read and scanf: returns errno or zero. If scancountp is + * non-null, then number of items scanned is returned in *scanncountp. + */ int xenbus_scanf(struct xenbus_transaction t, - const char *dir, const char *node, const char *fmt, ...) - __attribute__((format(scanf, 4, 5))); + const char *dir, const char *node, int *scancountp, const char *fmt, ...) + __attribute__((format(scanf, 5, 6))); -/* Single printf and write: returns -errno or 0. */ +/* Single printf and write: returns errno or 0. */ int xenbus_printf(struct xenbus_transaction t, const char *dir, const char *node, const char *fmt, ...) __attribute__((format(printf, 4, 5))); -/* Generic read function: NULL-terminated triples of name, - * sprintf-style type string, and pointer. Returns 0 or errno.*/ +/* + * Generic read function: NULL-terminated triples of name, + * sprintf-style type string, and pointer. Returns 0 or errno. + */ int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); /* notifer routines for when the xenstore comes up */ @@ -142,7 +147,9 @@ void xs_suspend(void); void xs_resume(void); /* Used by xenbus_dev to borrow kernel's store connection. */ -void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); +int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result); + +#if 0 #define XENBUS_IS_ERR_READ(str) ({ \ if (!IS_ERR(str) && strlen(str) == 0) { \ @@ -152,12 +159,15 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); IS_ERR(str); \ }) -#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE) +#endif + +#define XENBUS_EXIST_ERR(err) ((err) == ENOENT || (err) == ERANGE) + /** * Register a watch on the given path, using the given xenbus_watch structure * for storage, and the given callback function as the callback. Return 0 on - * success, or -errno on error. On success, the given path will be saved as + * success, or errno on error. On success, the given path will be saved as * watch->node, and remains the caller's to free. On error, watch->node will * be NULL, the device will switch to XenbusStateClosing, and the error will * be saved in the store. @@ -171,7 +181,7 @@ int xenbus_watch_path(device_t dev, char *path, /** * Register a watch on the given path/path2, using the given xenbus_watch * structure for storage, and the given callback function as the callback. - * Return 0 on success, or -errno on error. On success, the watched path + * Return 0 on success, or errno on error. On success, the watched path * (path/path2) will be saved as watch->node, and becomes the caller's to * kfree(). On error, watch->node will be NULL, so the caller has nothing to * free, the device will switch to XenbusStateClosing, and the error will be @@ -186,7 +196,7 @@ int xenbus_watch_path2(device_t dev, const char *path, /** * Advertise in the store a change of the given driver to the given new_state. * which case this is performed inside its own transaction. Return 0 on - * success, or -errno on error. On error, the device will switch to + * success, or errno on error. On error, the device will switch to * XenbusStateClosing, and the error will be saved in the store. */ int xenbus_switch_state(device_t dev, @@ -194,16 +204,17 @@ int xenbus_switch_state(device_t dev, /** - * Grant access to the given ring_mfn to the peer of the given device. Return - * 0 on success, or -errno on error. On error, the device will switch to - * XenbusStateClosing, and the error will be saved in the store. + * Grant access to the given ring_mfn to the peer of the given device. + * Return 0 on success, or errno on error. On error, the device will + * switch to XenbusStateClosing, and the error will be saved in the + * store. The grant ring reference is returned in *refp. */ -int xenbus_grant_ring(device_t dev, unsigned long ring_mfn); +int xenbus_grant_ring(device_t dev, unsigned long ring_mfn, int *refp); /** * Allocate an event channel for the given xenbus_device, assigning the newly - * created local port to *port. Return 0 on success, or -errno on error. On + * created local port to *port. Return 0 on success, or errno on error. On * error, the device will switch to XenbusStateClosing, and the error will be * saved in the store. */ @@ -211,7 +222,7 @@ int xenbus_alloc_evtchn(device_t dev, int *port); /** - * Free an existing event channel. Returns 0 on success or -errno on error. + * Free an existing event channel. Returns 0 on success or errno on error. */ int xenbus_free_evtchn(device_t dev, int port); |