Adapt for NetBSD and add glue for config(9). Enough to get guest domain

virtual devices probed and attached, domain0 and xenstore watch needs to
be done.
This commit is contained in:
bouyer 2006-03-06 20:21:35 +00:00
parent 71e3b5b4c8
commit 1604640823
7 changed files with 1019 additions and 724 deletions

View File

@ -1,8 +0,0 @@
obj-y += xenbus.o
xenbus-objs =
xenbus-objs += xenbus_client.o
xenbus-objs += xenbus_comms.o
xenbus-objs += xenbus_xs.o
xenbus-objs += xenbus_probe.o
xenbus-objs += xenbus_dev.o

View File

@ -1,3 +1,4 @@
/* $NetBSD: xenbus_client.c,v 1.2 2006/03/06 20:21:35 bouyer Exp $ */
/******************************************************************************
* Client-facing interface for the Xenbus driver. In other words, the
* interface between the Xenbus and the device-specific code, be it the
@ -27,6 +28,8 @@
* IN THE SOFTWARE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: xenbus_client.c,v 1.2 2006/03/06 20:21:35 bouyer Exp $");
#if 0
#define DPRINTK(fmt, args...) \
@ -35,13 +38,21 @@
#define DPRINTK(fmt, args...) ((void)0)
#endif
#include <sys/types.h>
#include <sys/null.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <asm-xen/evtchn.h>
#include <asm-xen/gnttab.h>
#include <asm-xen/xenbus.h>
#include <machine/stdarg.h>
#include <machine/evtchn.h>
#include <machine/xenbus.h>
#include <machine/granttables.h>
int xenbus_watch_path(struct xenbus_device *dev, const char *path,
int
xenbus_watch_path(struct xenbus_device *dev, char *path,
struct xenbus_watch *watch,
void (*callback)(struct xenbus_watch *,
const char **, unsigned int))
@ -61,20 +72,20 @@ int xenbus_watch_path(struct xenbus_device *dev, const char *path,
return err;
}
EXPORT_SYMBOL(xenbus_watch_path);
int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
int
xenbus_watch_path2(struct xenbus_device *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);
malloc(strlen(path) + 1 + strlen(path2) + 1, M_DEVBUF,
M_NOWAIT);
if (!state) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
return -ENOMEM;
xenbus_dev_fatal(dev, ENOMEM, "allocating path for watch");
return ENOMEM;
}
strcpy(state, path);
strcat(state, "/");
@ -83,14 +94,14 @@ int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
err = xenbus_watch_path(dev, state, watch, callback);
if (err) {
kfree(state);
free(state, M_DEVBUF);
}
return err;
}
EXPORT_SYMBOL(xenbus_watch_path2);
int xenbus_switch_state(struct xenbus_device *dev,
int
xenbus_switch_state(struct xenbus_device *dev,
struct xenbus_transaction *xbt,
XenbusState state)
{
@ -104,42 +115,43 @@ int xenbus_switch_state(struct xenbus_device *dev,
int current_state;
int err = xenbus_scanf(xbt, dev->nodename, "state", "%d",
int err = xenbus_scanf(xbt, dev->xbusd_path, "state", "%d",
&current_state);
if ((err == 1 && (XenbusState)current_state == state) ||
err == -ENOENT)
err == 0)
return 0;
err = xenbus_printf(xbt, dev->nodename, "state", "%d", state);
err = xenbus_printf(xbt, dev->xbusd_path, "state", "%d", state);
if (err) {
xenbus_dev_fatal(dev, err, "writing new state");
return err;
}
return 0;
}
EXPORT_SYMBOL(xenbus_switch_state);
/**
* 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(struct xenbus_device *dev)
static char *
error_path(struct xenbus_device *dev)
{
char *path_buffer = kmalloc(strlen("error/") + strlen(dev->nodename) +
1, GFP_KERNEL);
char *path_buffer = malloc(strlen("error/") + strlen(dev->xbusd_path) +
1, M_DEVBUF, M_NOWAIT);
if (path_buffer == NULL) {
return NULL;
}
strcpy(path_buffer, "error/");
strcpy(path_buffer + strlen("error/"), dev->nodename);
strcpy(path_buffer + strlen("error/"), dev->xbusd_path);
return path_buffer;
}
void _dev_error(struct xenbus_device *dev, int err, const char *fmt,
static void
_dev_error(struct xenbus_device *dev, int err, const char *fmt,
va_list ap)
{
int ret;
@ -147,39 +159,40 @@ void _dev_error(struct xenbus_device *dev, int err, const char *fmt,
char *printf_buffer = NULL, *path_buffer = NULL;
#define PRINTF_BUFFER_SIZE 4096
printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
if (printf_buffer == NULL)
goto fail;
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);
dev->has_error = 1;
KASSERT(len + ret < PRINTF_BUFFER_SIZE);
dev->xbusd_has_error = 1;
path_buffer = error_path(dev);
if (path_buffer == NULL) {
printk("xenbus: failed to write error node for %s (%s)\n",
dev->nodename, printf_buffer);
dev->xbusd_path, printf_buffer);
goto fail;
}
if (xenbus_write(NULL, path_buffer, "error", printf_buffer) != 0) {
printk("xenbus: failed to write error node for %s (%s)\n",
dev->nodename, printf_buffer);
dev->xbusd_path, 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(struct xenbus_device *dev, int err, const char *fmt,
void
xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
...)
{
va_list ap;
@ -188,10 +201,10 @@ void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
_dev_error(dev, err, fmt, ap);
va_end(ap);
}
EXPORT_SYMBOL(xenbus_dev_error);
void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
void
xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
...)
{
va_list ap;
@ -202,25 +215,27 @@ void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
xenbus_switch_state(dev, NULL, XenbusStateClosing);
}
EXPORT_SYMBOL(xenbus_dev_fatal);
int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
int
xenbus_grant_ring(struct xenbus_device *dev, paddr_t ring_pa,
grant_ref_t *entryp)
{
int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
if (err < 0)
int err = xengnt_grant_access(dev->xbusd_otherend_id, ring_pa,
0, entryp);
if (err != 0)
xenbus_dev_fatal(dev, err, "granting access to ring page");
return err;
}
EXPORT_SYMBOL(xenbus_grant_ring);
int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
int
xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
{
evtchn_op_t op = {
.cmd = EVTCHNOP_alloc_unbound,
.u.alloc_unbound.dom = DOMID_SELF,
.u.alloc_unbound.remote_dom = dev->otherend_id };
.u.alloc_unbound.remote_dom = dev->xbusd_otherend_id };
int err = HYPERVISOR_event_channel_op(&op);
if (err)
@ -229,10 +244,10 @@ int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
*port = op.u.alloc_unbound.port;
return err;
}
EXPORT_SYMBOL(xenbus_alloc_evtchn);
XenbusState xenbus_read_driver_state(const char *path)
XenbusState
xenbus_read_driver_state(const char *path)
{
XenbusState result;
@ -242,7 +257,6 @@ XenbusState xenbus_read_driver_state(const char *path)
return result;
}
EXPORT_SYMBOL(xenbus_read_driver_state);
/*

View File

@ -1,3 +1,4 @@
/* $NetBSD: xenbus_comms.c,v 1.2 2006/03/06 20:21:35 bouyer Exp $ */
/******************************************************************************
* xenbus_comms.c
*
@ -27,45 +28,70 @@
* IN THE SOFTWARE.
*/
#include <asm/hypervisor.h>
#include <asm-xen/evtchn.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/err.h>
#include <asm-xen/xenbus.h>
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: xenbus_comms.c,v 1.2 2006/03/06 20:21:35 bouyer Exp $");
#include <sys/types.h>
#include <sys/null.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <machine/hypervisor.h>
#include <machine/evtchn.h>
#include <machine/xenbus.h>
#include "xenbus_comms.h"
static int xenbus_irq;
#undef XENDEBUG
#ifdef XENDEBUG
#define XENPRINTF(x) printf x
#else
#define XENPRINTF(x)
#endif
struct xenstore_domain_interface *xenstore_interface;
static int xenbus_irq = 0;
extern void xenbus_probe(void *);
extern int xenstored_ready;
static DECLARE_WORK(probe_work, xenbus_probe, NULL);
// static DECLARE_WORK(probe_work, xenbus_probe, NULL);
DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
static int wake_waiting(void *);
static int check_indexes(XENSTORE_RING_IDX, XENSTORE_RING_IDX);
static void * get_output_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
char *, uint32_t *);
static const void * get_input_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
const char *, uint32_t *);
static inline struct xenstore_domain_interface *xenstore_domain_interface(void)
static inline struct xenstore_domain_interface *
xenstore_domain_interface(void)
{
return mfn_to_virt(xen_start_info->store_mfn);
return xenstore_interface;
}
static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
static int
wake_waiting(void *arg)
{
if (unlikely(xenstored_ready == 0)) {
if (__predict_false(xenstored_ready == 0)) {
xenstored_ready = 1;
schedule_work(&probe_work);
// XXX implement schedule_work(&probe_work);
}
wake_up(&xb_waitq);
return IRQ_HANDLED;
wakeup(&xenstore_interface);
return 1;
}
static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
static int
check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
{
return ((prod - cons) <= XENSTORE_RING_SIZE);
}
static void *get_output_chunk(XENSTORE_RING_IDX cons,
static void *
get_output_chunk(XENSTORE_RING_IDX cons,
XENSTORE_RING_IDX prod,
char *buf, uint32_t *len)
{
@ -75,7 +101,8 @@ static void *get_output_chunk(XENSTORE_RING_IDX cons,
return buf + MASK_XENSTORE_IDX(prod);
}
static const void *get_input_chunk(XENSTORE_RING_IDX cons,
static const void *
get_input_chunk(XENSTORE_RING_IDX cons,
XENSTORE_RING_IDX prod,
const char *buf, uint32_t *len)
{
@ -85,25 +112,32 @@ static const void *get_input_chunk(XENSTORE_RING_IDX cons,
return buf + MASK_XENSTORE_IDX(cons);
}
int xb_write(const void *data, unsigned len)
int
xb_write(const void *data, unsigned len)
{
struct xenstore_domain_interface *intf = xenstore_domain_interface();
XENSTORE_RING_IDX cons, prod;
int s = spltty();
while (len != 0) {
void *dst;
unsigned int avail;
wait_event_interruptible(xb_waitq,
(intf->req_prod - intf->req_cons) !=
XENSTORE_RING_SIZE);
while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) {
XENPRINTF(("xb_write tsleep\n"));
tsleep(&xenstore_interface, PRIBIO, "wrst", 0);
XENPRINTF(("xb_write tsleep done\n"));
}
/* Read indexes, then verify. */
cons = intf->req_cons;
prod = intf->req_prod;
mb();
if (!check_indexes(cons, prod))
return -EIO;
x86_lfence();
if (!check_indexes(cons, prod)) {
splx(s);
return EIO;
}
dst = get_output_chunk(cons, prod, intf->req, &avail);
if (avail == 0)
@ -112,38 +146,45 @@ int xb_write(const void *data, unsigned len)
avail = len;
memcpy(dst, data, avail);
data += avail;
data = (const char *)data + avail;
len -= avail;
/* Other side must not see new header until data is there. */
wmb();
x86_lfence();
intf->req_prod += avail;
x86_lfence();
/* This implies mb() before other side sees interrupt. */
notify_remote_via_evtchn(xen_start_info->store_evtchn);
hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
}
splx(s);
return 0;
}
int xb_read(void *data, unsigned len)
int
xb_read(void *data, unsigned len)
{
struct xenstore_domain_interface *intf = xenstore_domain_interface();
XENSTORE_RING_IDX cons, prod;
int s = spltty();
while (len != 0) {
unsigned int avail;
const char *src;
wait_event_interruptible(xb_waitq,
intf->rsp_cons != intf->rsp_prod);
while (intf->rsp_cons == intf->rsp_prod)
tsleep(&xenstore_interface, PRIBIO, "rdst", 0);
/* Read indexes, then verify. */
cons = intf->rsp_cons;
prod = intf->rsp_prod;
mb();
if (!check_indexes(cons, prod))
return -EIO;
x86_lfence();
if (!check_indexes(cons, prod)) {
XENPRINTF(("xb_read EIO\n"));
splx(s);
return EIO;
}
src = get_input_chunk(cons, prod, intf->rsp, &avail);
if (avail == 0)
@ -152,43 +193,45 @@ int xb_read(void *data, unsigned len)
avail = len;
/* We must read header before we read data. */
rmb();
x86_lfence();
memcpy(data, src, avail);
data += avail;
data = (char *)data + avail;
len -= avail;
/* Other side must not see free space until we've copied out */
mb();
x86_lfence();
intf->rsp_cons += avail;
x86_lfence();
pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
XENPRINTF(("Finished read of %i bytes (%i to go)\n",
avail, len));
/* Implies mb(): they will see new header. */
notify_remote_via_evtchn(xen_start_info->store_evtchn);
hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
}
splx(s);
return 0;
}
/* Set up interrupt handler off store event channel. */
int xb_init_comms(void)
int
xb_init_comms(struct device *dev)
{
int err;
if (xenbus_irq)
unbind_from_irqhandler(xenbus_irq, &xb_waitq);
event_remove_handler(xenbus_irq, wake_waiting, NULL);
err = bind_evtchn_to_irqhandler(
xen_start_info->store_evtchn, wake_waiting,
0, "xenbus", &xb_waitq);
if (err <= 0) {
printk(KERN_ERR "XENBUS request irq failed %i\n", err);
err = event_set_handler(xen_start_info.store_evtchn, wake_waiting,
NULL, IPL_TTY, "xenbus");
if (err) {
printf("XENBUS request irq failed %i\n", err);
return err;
}
xenbus_irq = err;
xenbus_irq = xen_start_info.store_evtchn;
printf("%s: using event channel %d\n", dev->dv_xname, xenbus_irq);
hypervisor_enable_event(xenbus_irq);
return 0;
}

View File

@ -1,3 +1,4 @@
/* $NetBSD: xenbus_comms.h,v 1.2 2006/03/06 20:21:35 bouyer Exp $ */
/*
* Private include for xenbus communications.
*
@ -28,14 +29,14 @@
#ifndef _XENBUS_COMMS_H
#define _XENBUS_COMMS_H
void xenbus_kernfs_init(void);
int xs_init(void);
int xb_init_comms(void);
int xb_init_comms(struct device *dev);
/* Low level routines. */
int xb_write(const void *data, unsigned len);
int xb_read(void *data, unsigned len);
int xs_input_avail(void);
extern wait_queue_head_t xb_waitq;
#endif /* _XENBUS_COMMS_H */

View File

@ -1,3 +1,4 @@
/* $NetBSD: xenbus_dev.c,v 1.2 2006/03/06 20:21:35 bouyer Exp $ */
/*
* xenbus_dev.c
*
@ -29,69 +30,128 @@
* IN THE SOFTWARE.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/uio.h>
#include <linux/notifier.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.2 2006/03/06 20:21:35 bouyer Exp $");
#include "opt_xen.h"
#include <sys/types.h>
#include <sys/null.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/tree.h>
#include <sys/vnode.h>
#include <miscfs/specfs/specdev.h>
#include <miscfs/kernfs/kernfs.h>
#include <machine/kernfs_machdep.h>
#include <machine/hypervisor.h>
#include <machine/xenbus.h>
#include "xenbus_comms.h"
#include <asm/uaccess.h>
#include <asm/hypervisor.h>
#include <asm-xen/xenbus.h>
#include <asm-xen/xen_proc.h>
#include <asm/hypervisor.h>
static int xenbus_dev_read(void *);
static int xenbus_dev_write(void *);
static int xenbus_dev_open(void *);
static int xenbus_dev_close(void *);
struct xenbus_dev_transaction {
struct list_head list;
SLIST_ENTRY(xenbus_dev_transaction) trans_next;
struct xenbus_transaction *handle;
};
#define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
#define PRIVCMD_MODE (S_IRUSR | S_IWUSR)
static const struct kernfs_fileop xenbus_fileops[] = {
{ .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open },
{ .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close },
{ .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read },
{ .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write },
};
void
xenbus_kernfs_init()
{
kernfs_entry_t *dkt;
kfstype kfst;
kfst = KERNFS_ALLOCTYPE(xenbus_fileops);
KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG,
PRIVCMD_MODE);
kernfs_addentry(kernxen_pkt, dkt);
}
struct xenbus_dev_data {
#define BUFFER_SIZE (PAGE_SIZE)
#define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1))
/* In-progress transaction. */
struct list_head transactions;
SLIST_HEAD(, xenbus_dev_transaction) transactions;
/* Partial request. */
unsigned int len;
union {
struct xsd_sockmsg msg;
char buffer[PAGE_SIZE];
char buffer[BUFFER_SIZE];
} u;
/* Response queue. */
#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
char read_buffer[PAGE_SIZE];
char read_buffer[BUFFER_SIZE];
unsigned int read_cons, read_prod;
wait_queue_head_t read_waitq;
};
static struct proc_dir_entry *xenbus_dev_intf;
static ssize_t xenbus_dev_read(struct file *filp,
char __user *ubuf,
size_t len, loff_t *ppos)
static int
xenbus_dev_read(void *v)
{
struct xenbus_dev_data *u = filp->private_data;
int i;
struct vop_read_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
struct ucred *a_cred;
} */ *ap = v;
struct kernfs_node *kfs = VTOKERN(ap->a_vp);
struct uio *uio = ap->a_uio;
struct xenbus_dev_data *u = kfs->kfs_v;
int err;
off_t offset;
int s = spltty();
if (wait_event_interruptible(u->read_waitq,
u->read_prod != u->read_cons))
return -EINTR;
for (i = 0; i < len; i++) {
if (u->read_cons == u->read_prod)
break;
put_user(u->read_buffer[MASK_READ_IDX(u->read_cons)], ubuf+i);
u->read_cons++;
while (u->read_prod == u->read_cons) {
err = tsleep(u, PRIBIO | PCATCH, "xbrd", 0);
if (err)
goto end;
}
if (uio->uio_offset != 0) {
err = EINVAL;
goto end;
}
offset = 0;
return i;
if (u->read_cons > u->read_prod) {
err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
0U - u->read_cons, uio);
if (err)
goto end;
u->read_cons += uio->uio_offset;
offset = uio->uio_offset;
}
err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
u->read_prod - u->read_cons, uio);
if (err == 0)
u->read_cons += uio->uio_offset - offset;
end:
splx(s);
return err;
}
static void queue_reply(struct xenbus_dev_data *u,
static void
queue_reply(struct xenbus_dev_data *u,
char *data, unsigned int len)
{
int i;
@ -99,29 +159,43 @@ static void queue_reply(struct xenbus_dev_data *u,
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));
wake_up(&u->read_waitq);
wakeup(&u);
}
static ssize_t xenbus_dev_write(struct file *filp,
const char __user *ubuf,
size_t len, loff_t *ppos)
static int
xenbus_dev_write(void *v)
{
struct xenbus_dev_data *u = filp->private_data;
struct vop_write_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
struct ucred *a_cred;
} */ *ap = v;
struct kernfs_node *kfs = VTOKERN(ap->a_vp);
struct uio *uio = ap->a_uio;
struct xenbus_dev_data *u = kfs->kfs_v;
struct xenbus_dev_transaction *trans;
void *reply;
int err = 0;
int err;
size_t size;
if ((len + u->len) > sizeof(u->u.buffer))
return -EINVAL;
if (uio->uio_offset < 0)
return EINVAL;
size = uio->uio_resid;
if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0)
return -EFAULT;
if ((size + u->len) > sizeof(u->u.buffer))
return EINVAL;
u->len += len;
err = uiomove(u->u.buffer + u->len, sizeof(u->u.buffer) - u->len, uio);
if (err)
return err;
u->len += size;
if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
return len;
return 0;
switch (u->u.msg.type) {
case XS_TRANSACTION_START:
@ -135,101 +209,100 @@ static ssize_t xenbus_dev_write(struct file *filp,
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 {
err = xenbus_dev_request_and_reply(&u->u.msg, &reply);
if (err == 0) {
if (u->u.msg.type == XS_TRANSACTION_START) {
trans = kmalloc(sizeof(*trans), GFP_KERNEL);
trans = malloc(sizeof(*trans), M_DEVBUF,
M_WAITOK);
trans->handle = (struct xenbus_transaction *)
simple_strtoul(reply, NULL, 0);
list_add(&trans->list, &u->transactions);
strtoul(reply, NULL, 0);
SLIST_INSERT_HEAD(&u->transactions,
trans, trans_next);
} else if (u->u.msg.type == XS_TRANSACTION_END) {
list_for_each_entry(trans, &u->transactions,
list)
SLIST_FOREACH(trans, &u->transactions,
trans_next) {
if ((unsigned long)trans->handle ==
(unsigned long)u->u.msg.tx_id)
break;
BUG_ON(&trans->list == &u->transactions);
list_del(&trans->list);
kfree(trans);
}
KASSERT(trans != NULL);
SLIST_REMOVE(&u->transactions, trans,
xenbus_dev_transaction, trans_next);
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;
err = EINVAL;
break;
}
if (err == 0) {
u->len = 0;
err = len;
}
return err;
}
static int xenbus_dev_open(struct inode *inode, struct file *filp)
static int
xenbus_dev_open(void *v)
{
struct vop_open_args /* {
struct vnode *a_vp;
int a_mode;
struct ucred *a_cred;
struct lwp *a_l;
} */ *ap = v;
struct kernfs_node *kfs = VTOKERN(ap->a_vp);
struct xenbus_dev_data *u;
if (xen_start_info->store_evtchn == 0)
return -ENOENT;
if (xen_start_info.store_evtchn == 0)
return ENOENT;
nonseekable_open(inode, filp);
u = kmalloc(sizeof(*u), GFP_KERNEL);
u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK);
if (u == NULL)
return -ENOMEM;
return ENOMEM;
memset(u, 0, sizeof(*u));
INIT_LIST_HEAD(&u->transactions);
init_waitqueue_head(&u->read_waitq);
SLIST_INIT(&u->transactions);
filp->private_data = u;
kfs->kfs_v = u;
return 0;
}
static int xenbus_dev_release(struct inode *inode, struct file *filp)
static int
xenbus_dev_close(void *v)
{
struct xenbus_dev_data *u = filp->private_data;
struct xenbus_dev_transaction *trans, *tmp;
struct vop_close_args /* {
struct vnode *a_vp;
int a_fflag;
struct ucred *a_cred;
struct lwp *a_l;
} */ *ap = v;
struct kernfs_node *kfs = VTOKERN(ap->a_vp);
list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
struct xenbus_dev_data *u = kfs->kfs_v;
struct xenbus_dev_transaction *trans;
while (!SLIST_EMPTY(&u->transactions)) {
trans = SLIST_FIRST(&u->transactions);
xenbus_transaction_end(trans->handle, 1);
list_del(&trans->list);
kfree(trans);
SLIST_REMOVE_HEAD(&u->transactions, trans_next);
free(trans, M_DEVBUF);
}
kfree(u);
free(u, M_DEVBUF);
kfs->kfs_v = NULL;
return 0;
}
static struct file_operations xenbus_dev_file_ops = {
.read = xenbus_dev_read,
.write = xenbus_dev_write,
.open = xenbus_dev_open,
.release = xenbus_dev_release,
};
static int __init
xenbus_dev_init(void)
{
xenbus_dev_intf = create_xen_proc_entry("xenbus", 0400);
if (xenbus_dev_intf)
xenbus_dev_intf->proc_fops = &xenbus_dev_file_ops;
return 0;
}
__initcall(xenbus_dev_init);
/*
* Local variables:
* c-file-style: "linux"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff