From: Jean Guyader Date: Thu, 19 Nov 2009 17:57:31 +0000 (+0000) Subject: Upgrade v2v with different char device that got different semantics. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=ba15381ae3234b5a33d0cdba4f64ee75d8be3646;p=xenclient%2Flinux-2.6.27-pq.git Upgrade v2v with different char device that got different semantics. --- diff --git a/master/v2v-dev b/master/v2v-dev index c8cdce0..21dd14b 100644 --- a/master/v2v-dev +++ b/master/v2v-dev @@ -1,9 +1,9 @@ diff --git a/drivers/xen/v2v/Kconfig b/drivers/xen/v2v/Kconfig -index 5966234..b3b6ef4 100644 +index dd48eaf..de67567 100644 --- a/drivers/xen/v2v/Kconfig +++ b/drivers/xen/v2v/Kconfig @@ -22,3 +22,10 @@ config XEN_V2V_DRV - default n + default n help Sample for Xen V2V interdomain communication services. + @@ -14,22 +14,22 @@ index 5966234..b3b6ef4 100644 + help + Xen V2V char device for userland v2v. diff --git a/drivers/xen/v2v/Makefile b/drivers/xen/v2v/Makefile -index f3442d9..5230cd6 100644 +index 8e35e62..50201b1 100644 --- a/drivers/xen/v2v/Makefile +++ b/drivers/xen/v2v/Makefile -@@ -4,5 +4,6 @@ +@@ -4,5 +4,6 @@ obj-$(CONFIG_XEN_V2V_DRV) += v2vdrv.o - v2vdrv-objs = + v2vdrv-objs = v2vdrv-objs += v2vsamp.o v2vops.o +obj-$(CONFIG_XEN_V2V_DEV) += v2vdev.o ccflags-$(CONFIG_XEN_V2V_DEBUG) += -DDEBUG diff --git a/drivers/xen/v2v/v2vdev.c b/drivers/xen/v2v/v2vdev.c new file mode 100644 -index 0000000..adfc6c8 +index 0000000..9a42523 --- /dev/null +++ b/drivers/xen/v2v/v2vdev.c -@@ -0,0 +1,511 @@ +@@ -0,0 +1,909 @@ +/****************************************************************************** + * drivers/xen/v2v/v2vdev.c + * @@ -45,7 +45,7 @@ index 0000000..adfc6c8 + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this source filp (the "Software"), to deal in the Software without ++ * of this source f (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to @@ -83,461 +83,859 @@ index 0000000..adfc6c8 +#include +#include + ++#define V2V_STREAM_MSGSIZE 2048 ++ +#define V2VLISTEN(len) _IOC(_IOC_WRITE, 'V', 0x01, len) +#define V2VCONNECT(len) _IOC(_IOC_WRITE, 'V', 0x02, len) + -+#define MIN(_x_, _y_) ((_x_) < (_y_) ? (_x_) : (_y_)) -+ -+#define DPRINTK(fmt, args...) \ -+ printk("V2V-DEV (%s:%d) "fmt, \ -+ __FUNCTION__, __LINE__, ##args) -+#define IPRINTK(fmt, args...) \ -+ printk(KERN_INFO "V2V-DEV: "fmt, ##args) -+#define WPRINTK(fmt, args...) \ -+ printk(KERN_WARNING "V2V-DEV: "fmt, ##args) ++#define L_READ 0 ++#define L_WRITE 1 ++#define L_CONNECT 2 + -+struct v2vdev_context -+{ -+ int connected; ++#define MIN(a, b) ((a) < (b) ? (a) : (b)) + -+ void *buff; -+ char *data_ptr; -+ size_t buff_size; -+ size_t data_len; ++#define FISH do { printk(KERN_ERR "%s:%s:%d\n", __FILE__,__PRETTY_FUNCTION__,__LINE__ ); } while (1==0) + ++enum v2vdev_state ++{ ++ V2VDEV_UNKNOWN, ++ V2VDEV_UNBOUND, ++ V2VDEV_LISTEN, ++ V2VDEV_CONNECT, ++ V2VDEV_CONNECTED, ++ V2VDEV_DISCONNECTED ++}; + -+ int last_err; -+ int listenner; -+ struct v2v_channel *channel; ++struct v2vdev_buf ++{ ++ void *buf; ++ char *ptr; ++ int len; ++ int pending; +}; + -+#if 0 -+#define DUMP_CTX(a) dump_ctx(__func__, __LINE__, a) -+static void dump_ctx(const char *func, int line, struct v2vdev_context *ctx) ++ ++struct v2vdev +{ -+ printk(KERN_ERR "%s:%d conn=%d buff=%p bsize=%d dptr=%p dlen=%d err=%d\n", -+ func, line, ctx->connected,ctx->buff,ctx->buff_size,ctx->data_ptr, -+ ctx->data_len,ctx->last_err); -+} -+#endif -+#define DUMP_CTX(a) ((void)0) ++ struct v2v_channel *channel; ++ ++ enum v2vdev_state state; ++ ++ struct v2vdev_buf *read_buf; ++ //struct v2vdev_buf *write_buf; ++ ++ int recv_blocked; ++ int send_blocked; ++ ++}; + ++/* Utils */ + +static void +hexdump (char *prefix, void *_d, int len) +{ -+ uint8_t *d = (uint8_t *) _d; -+ int i, j, k; -+ int e; ++ uint8_t *d = (uint8_t *) _d; ++ int i, j, k; ++ int e; + -+ printk (KERN_INFO "%s %d bytes from %p\n", prefix, len, d); ++ printk (KERN_INFO "%s %d bytes from %p\n", prefix, len, d); + -+ if (!d || len<0) -+ return; ++ if (!d || len < 0) ++ return; + -+ e = len + 15; -+ e &= ~15; ++ e = len + 15; ++ e &= ~15; + -+ for (i = 0; i < e; i += 16) ++ for (i = 0; i < e; i += 16) + { -+ printk ("%s %05x:", prefix, i); -+ for (j = 0; j < 16; ++j) ++ printk ("%s %05x:", prefix, i); ++ for (j = 0; j < 16; ++j) + { -+ k = i + j; ++ k = i + j; + -+ if (k < len) -+ printk ("%02x", d[k]); -+ else -+ printk (" "); ++ if (k < len) ++ printk ("%02x", d[k]); ++ else ++ printk (" "); + } + -+ printk(" "); -+ for (j = 0; j < 16; ++j) ++ printk (" "); ++ for (j = 0; j < 16; ++j) + { -+ k = i + j; -+ if (k < len) ++ k = i + j; ++ if (k < len) + { -+ uint8_t c = d[k]; -+ if (c < 33) -+ c = '.'; -+ if (c > 126) -+ c = '.'; -+ printk ("%c", c); ++ uint8_t c = d[k]; ++ if (c < 33) ++ c = '.'; ++ if (c > 126) ++ c = '.'; ++ printk ("%c", c); + } + } -+ printk ("\n"); ++ printk ("\n"); + } +} + -+static int v2v_receive_in_queue(struct v2vdev_context *ctx) ++/* buffer */ ++ ++static inline int ++buffer_pending (struct v2vdev_buf *b) +{ -+ return v2v_get_wake_reason(ctx->channel, V2V_WAKE_REASON_ANY) == V2V_WAKE_REASON_RECEIVE; ++ return b->pending; +} + -+static int v2vdev_message_get(struct v2vdev_context *ctx) ++static inline int ++buffer_set_len (struct v2vdev_buf *b, size_t size) +{ -+ volatile void *buff; -+ ssize_t size = 0; -+ unsigned vtype, vflags; ++ BUG_ON (b->pending); + ++ if (size > b->len) ++ { ++ b->len = size; ++ if (b->buf) ++ { ++ b->buf = krealloc (b->buf, size, GFP_KERNEL); ++ } ++ else ++ { ++ b->buf = kmalloc (size, GFP_KERNEL); ++ } + -+ if (!ctx->connected) { -+ ctx->last_err=-ENOTCONN; -+ return ctx->last_err; ++ if (!b->buf) ++ { ++ b->len = 0; ++ return -ENOMEM; ++ } + } ++ return 0; ++} + -+ if (ctx->data_len) { -+ DPRINTK(KERN_ERR "****** data_len not zero in v2vdev_message_get\n"); -+ return 0; -+ } ++static inline void ++buffer_consume (struct v2vdev_buf *b, size_t bytes) ++{ ++ BUG_ON (b->pending < bytes); ++ b->pending -= bytes; ++ b->ptr += bytes; ++} + ++static inline void ++buffer_consume_all (struct v2vdev_buf *b) ++{ ++ b->pending = 0; ++ b->ptr = b->buf; ++} + -+ vtype = vflags = 0; -+ ctx->last_err = v2v_nc2_get_message(ctx->channel, -+ (const volatile void **)&buff, &size, -+ &vtype, &vflags); ++static int ++buffer_copy_in (struct v2vdev_buf *b, void *ptr, size_t size) ++{ ++ int err; ++ err = buffer_set_len (b, size); ++ if (err) ++ return err; + -+ if (ctx->last_err) { -+ if (ctx->last_err==-ENODATA) -+ ctx->last_err=0; -+ return ctx->last_err; -+ } ++ memcpy (b->buf, ptr, size); ++ b->pending = size; ++ b->ptr = b->buf; + -+ hexdump("<", (void *) buff, size); ++ return 0; ++} + -+ if (size>ctx->buff_size) { -+ ctx->buff_size=size; -+ ctx->buff = krealloc(ctx->buff, ctx->buff_size, GFP_KERNEL); -+ } ++static void ++buffer_free (struct v2vdev_buf *b) ++{ ++ if (b->buf) ++ kfree (b->buf); ++ kfree (b); ++} + -+ memcpy(ctx->buff, (void *)buff, size); -+ ctx->data_len=size; -+ ctx->data_ptr=ctx->buff; -+ //if (ctx->data_len > 2) ctx->data_len -=2; ++static struct v2vdev_buf * ++buffer_new (void) ++{ ++ struct v2vdev_buf *ret = kmalloc (sizeof (struct v2vdev_buf), GFP_KERNEL); + ++ if (!ret) ++ return ret; + -+ v2v_nc2_finish_message(ctx->channel); -+ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_RECEIVE); ++ ret->buf = NULL; ++ ret->ptr = NULL; ++ ret->len = 0; ++ ret->pending = 0; + -+ return ctx->last_err; ++ return ret; +} + -+static int v2vdev_wait_connected(struct v2vdev_context *ctx) ++ ++ ++ ++ ++void ++v2vdev_update_state (struct v2vdev *c, int check_state) +{ -+ struct v2v_wait *wait_state; -+ u8 reasons_mask = V2V_WAKE_REASON_CONTROL; -+ int err; -+ enum v2v_endpoint_state state; ++ enum v2v_endpoint_state state; ++ ++ if (!c->channel) ++ { ++ c->state = V2VDEV_UNBOUND; ++ return; ++ } + -+ while (!ctx->connected) ++ ++ ++ while (v2v_get_wake_reason (c->channel, V2V_WAKE_REASON_CONTROL)) ++ check_state++; ++ ++ while (v2v_get_wake_reason (c->channel, V2V_WAKE_REASON_SEND)) ++ c->send_blocked = 0; ++ ++ while (v2v_get_wake_reason (c->channel, V2V_WAKE_REASON_RECEIVE)) ++ c->recv_blocked = 0; ++ ++ ++ if (check_state) + { -+ wait_state = v2v_get_wait_state(ctx->channel); -+ DPRINTK("wait event ....\n"); -+ wait_event(wait_state->wait_event, -+ atomic_xchg(&wait_state->wait_condition, 0) == 1); -+ v2v_get_wake_reason(ctx->channel, reasons_mask); -+ -+ err = v2v_get_remote_state(ctx->channel, &state); -+ if (err) ++ if (v2v_get_remote_state (c->channel, &state) != 0) + { -+ DPRINTK("failure in v2v_get_remote_state() - err: %d\n", err); -+ ctx->connected = 0;; -+ v2v_disconnect(ctx->channel); -+ return err; ++ c->state = V2VDEV_UNKNOWN; ++ } ++ else ++ { ++ switch (state) ++ { ++ ++ case v2v_state_unready: ++ c->state = V2VDEV_CONNECT; ++ break; ++ ++ case v2v_state_listening: ++ c->state = V2VDEV_LISTEN; ++ break; ++ ++ case v2v_state_connected: ++ c->state = V2VDEV_CONNECTED; ++ break; ++ ++ case v2v_state_disconnecting: ++ case v2v_state_disconnected: ++ case v2v_state_crashed: ++ c->state = V2VDEV_DISCONNECTED; ++ break; ++ default: ++ c->state = V2VDEV_LISTEN; ++ break; ++ } + } -+ DPRINTK("endpoint state: %s\n", v2v_endpoint_state_name(state)); -+ ctx->connected = state == v2v_state_connected; + } -+ return 0; +} + -+static int v2vdev_listen(struct v2vdev_context *ctx, -+ const char __user *user_path, size_t size) ++static void ++v2vdev_wait (struct v2vdev *c) ++{ ++ struct v2v_wait *wait_state; ++ ++ ++ wait_state = v2v_get_wait_state (c->channel); ++ wait_event_interruptible (wait_state->wait_event, ++ atomic_xchg (&wait_state->wait_condition, ++ 0) == 1); ++ ++ v2vdev_update_state (c, 0); ++} ++ ++ ++static int ++v2vdev_loop_check (struct v2vdev *c, int where, int *err) +{ -+ int err; -+ char path[1024]; + -+ if (copy_from_user(path, user_path, size) != 0) -+ return -EINVAL; -+ path[size] = 0; ++ if (signal_pending (current)) ++ { ++ *err = -EINTR; ++ return 1; ++ } + -+ err = v2v_listen(path, &ctx->channel, 0, 0, 0); -+ if (err) ++ switch (c->state) + { -+ DPRINTK("failure in v2v_listen() - error: %d\n", err); -+ return err; ++ case V2VDEV_CONNECTED: ++ return 0; ++ case V2VDEV_UNBOUND: ++ case V2VDEV_LISTEN: ++ case V2VDEV_CONNECT: ++ if (where == L_CONNECT) ++ return 0; ++ *err = -ENOTCONN; ++ break; ++ case V2VDEV_UNKNOWN: ++ *err = -EIO; ++ break; ++ case V2VDEV_DISCONNECTED: ++ *err = (where == L_WRITE) ? -EPIPE : 0; ++ break; + } -+ BUG_ON(ctx->channel == NULL); + -+ ctx->listenner = 1; ++ return 1; + -+ return 0; +} + -+static int v2vdev_connect(struct v2vdev_context *ctx, -+ const char __user *user_path, size_t size) ++static int ++v2vdev_receive_to_buf (struct v2vdev *c) +{ -+ char path[1024]; -+ int err; ++ volatile void *msg; ++ ssize_t msg_len = 0; ++ unsigned msg_type = 0; ++ unsigned msg_flags = 0; ++ int err; + -+ if (copy_from_user(path, user_path, size) != 0) -+ return -EINVAL; -+ path[size] = 0; ++ BUG_ON (buffer_pending (c->read_buf)); + -+ DPRINTK("connect on %s\n", path); + -+ err = v2v_connect(path, &ctx->channel, 0); -+ if (err) ++ err = v2v_nc2_get_message (c->channel, ++ (const volatile void **) &msg, &msg_len, ++ &msg_type, &msg_flags); ++ ++ switch (err) + { -+ DPRINTK("failure in connect() - err: %d\n", err); -+ return err; ++ case 0: ++ ++ err = buffer_copy_in (c->read_buf, (void *) msg, msg_len); ++ v2v_nc2_finish_message (c->channel); ++ ++ return err; ++ case -ENODATA: ++ c->recv_blocked = 1; ++ return -EAGAIN; ++ default: ++ return err; + } + -+ err = v2vdev_wait_connected(ctx); -+ if (err) ++ return err; ++} ++ ++ ++static ssize_t ++v2vdev_read_dgram (struct file *f, char __user * buf, ++ size_t count, loff_t * ppos) ++{ ++ struct v2vdev *c = f->private_data; ++ int nonblock = f->f_flags & O_NONBLOCK; ++ ++ int n; ++ int err; ++ ++ if (!access_ok (VERIFY_WRITE, buf, count)) ++ return -EFAULT; ++ ++ v2vdev_update_state (c, 0); ++ ++ while (1) + { -+ DPRINTK("failure in wait_connected() - error: %d\n", err); ++ if (v2vdev_loop_check (c, L_READ, &err)) + return err; ++ ++ //FIXME - we could optimize by checking recv_blocked here and not doing the read ++ ++ if (!buffer_pending (c->read_buf)) ++ { ++ ++ err = v2vdev_receive_to_buf (c); ++ ++ switch (err) ++ { ++ case -EAGAIN: ++ if (nonblock) ++ return -EAGAIN; ++ ++ v2vdev_wait (c); ++ break; ++ case 0: ++ break; ++ default: ++ return err; ++ } ++ ++ } ++ ++ n = MIN (count, buffer_pending (c->read_buf)); ++ ++ if (!n) ++ continue; ++ ++ if (copy_to_user (buf, c->read_buf->buf, n)) ++ return -EFAULT; ++ ++ buffer_consume_all (c->read_buf); ++ ++ return n; ++ + } -+ return 0; ++ ++ return 0; +} + -+static ssize_t v2vdev_read(struct file *filp, char __user *buf, -+ size_t count, loff_t *ppos) ++ ++static ssize_t ++v2vdev_write_dgram (struct file *f, const char __user * buf, ++ size_t count, loff_t * ppos) +{ -+ struct v2vdev_context *ctx = filp->private_data; -+ struct v2v_wait *wait_state; -+ size_t red=0; -+ size_t n; -+ int nonblock=filp->f_flags & O_NONBLOCK; -+ u8 reasons_mask = V2V_WAKE_REASON_CONTROL | V2V_WAKE_REASON_RECEIVE; -+ u8 reason; -+ enum v2v_endpoint_state state; -+ -+ DUMP_CTX(ctx); -+ if (!ctx->connected) -+ return -ENOTCONN; -+ -+ while (count) { -+ -+ if (!ctx->data_len) { -+ -+ if (ctx->last_err) -+ return ctx->last_err; -+ -+ if (nonblock && !v2v_receive_in_queue(ctx)) { -+ DPRINTK("v2vdev_read needed got %d/%d\n",red,count+red); -+ return red ? red:-EAGAIN; -+ } -+ -+ wait_state = v2v_get_wait_state(ctx->channel); -+ wait_event(wait_state->wait_event, -+ atomic_xchg(&wait_state->wait_condition, 0) == 1); -+ reason = v2v_get_wake_reason(ctx->channel, reasons_mask); -+ if (reason & V2V_WAKE_REASON_CONTROL) -+ { -+ if (v2v_get_remote_state(ctx->channel, &state) == 0 && -+ state != v2v_state_connected) -+ { -+ ctx->connected = 0; -+ v2v_disconnect(ctx->channel); -+ return 0; -+ } -+ } -+ v2vdev_message_get(ctx); -+ } -+ DUMP_CTX(ctx); -+ -+ n=MIN(count,ctx->data_len); -+ -+ if (n) { -+ if (copy_to_user(buf, ctx->data_ptr, n)) -+ return -EFAULT; -+ red+=n; -+ count-=n; -+ ctx->data_ptr+=n; -+ ctx->data_len-=n; -+ buf+=n; -+ -+ DUMP_CTX(ctx); ++ struct v2vdev *c = f->private_data; ++ int nonblock = f->f_flags & O_NONBLOCK; ++ ++ volatile void *msg; ++ int err; ++ ++ if (!access_ok (VERIFY_READ, buf, count)) ++ return -EFAULT; ++ ++ v2vdev_update_state (c, 0); ++ ++ while (1) ++ { ++ ++ if (v2vdev_loop_check (c, L_WRITE, &err)) ++ return err; ++ ++ //FIXME - we could optimize by checking send_blocked here and not doing the write ++ ++ ++ err = v2v_nc2_prep_message (c->channel, count, 1, 0, &msg); ++ ++ switch (err) ++ { ++ case 0: ++ err = copy_from_user ((void *) msg, buf, count); ++ v2v_nc2_send_messages (c->channel); ++ ++ return err ? -EFAULT : count; ++ case -EAGAIN: ++ c->send_blocked = 1; ++ ++ if (nonblock) ++ return -EAGAIN; ++ ++ break; ++ case -EINVAL: ++ return -EMSGSIZE; ++ default: ++ return err; + } -+ } -+ -+ DPRINTK("v2vdev_read needed got %d/%d\n",red,red); + -+ return red; ++ v2vdev_wait (c); ++ } ++ return 0; +} + -+static ssize_t v2vdev_write(struct file *filp, const char __user *buf, -+ size_t count, loff_t *ppos) ++ ++ ++ ++static ssize_t ++v2vdev_read_stream (struct file *f, char __user * buf, ++ size_t count, loff_t * ppos) +{ -+ struct v2vdev_context *ctx = filp->private_data; -+ volatile void *msg; -+ int err; -+ -+ DUMP_CTX(ctx); -+ if (!ctx->connected) -+ return -ENOTCONN; -+ -+ err = v2v_nc2_prep_message(ctx->channel, count, 1, 0, &msg); -+ if (err) ++ struct v2vdev *c = f->private_data; ++ int nonblock = f->f_flags & O_NONBLOCK; ++ size_t red = 0; ++ size_t n; ++ int err; ++ ++ if (!access_ok (VERIFY_WRITE, buf, count)) ++ return -EFAULT; ++ ++ v2vdev_update_state (c, 0); ++ ++ while (count) + { -+ DPRINTK("failure in v2v_nc2_prep_message() - error: %d\n", err); -+ return -EIO; -+ } ++ if (v2vdev_loop_check (c, L_READ, &err)) ++ return red ? red : err; + -+ if (copy_from_user((void *)msg, buf, count)) -+ return -EFAULT; -+ -+ hexdump(">", (void *) msg, count); -+ v2v_nc2_send_messages(ctx->channel); -+ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_SEND); -+ return count; -+} ++ if (!buffer_pending (c->read_buf)) ++ { + -+static long v2vdev_ioctl(struct file *filp, -+ unsigned int cmd, unsigned long arg) -+{ -+ int rc; -+ void __user *p = (void __user *)arg; -+ struct v2vdev_context *ctx = filp->private_data; -+ -+ rc = -ENOSYS; -+ switch (cmd) { -+ default: -+ if (_IOC_TYPE(cmd) != 'V') -+ return -ENOTTY; ++ err = v2vdev_receive_to_buf (c); + -+ if (_IOC_DIR(cmd) == _IOC_WRITE) ++ switch (err) + { -+ if ((_IOC_NR(cmd) == _IOC_NR(V2VLISTEN(0)))) -+ rc = v2vdev_listen(ctx, p, _IOC_SIZE(cmd)); -+ if ((_IOC_NR(cmd) == _IOC_NR(V2VCONNECT(0)))) -+ rc = v2vdev_connect(ctx, p, _IOC_SIZE(cmd)); ++ case -EAGAIN: ++ if (nonblock) ++ return red ? red : -EAGAIN; ++ ++ v2vdev_wait (c); ++ break; ++ case 0: ++ break; ++ default: ++ return red ? red : err; + } -+ break; ++ ++ } ++ ++ n = MIN (count, buffer_pending (c->read_buf)); ++ ++ if (!n) ++ continue; ++ ++ if (copy_to_user (buf, c->read_buf->ptr, n)) ++ return -EFAULT; ++ ++ red += n; ++ count -= n; ++ buf += n; ++ ++ buffer_consume (c->read_buf, n); ++ + } -+ return rc; -+} + -+static int v2vdev_open(struct inode *inode, struct file *filp) -+{ -+ struct v2vdev_context *ctx; + -+ ctx = kmalloc(sizeof (struct v2vdev_context), GFP_KERNEL); -+ memset(ctx, 0, sizeof (struct v2vdev_context)); -+ filp->private_data = ctx; -+ return 0; ++ return red; +} + -+static int v2vdev_release(struct inode *inode, struct file *filp) ++#if 0 ++static ssize_t ++not_v2vdev_read_stream (struct file *f, char __user * buf, ++ size_t count, loff_t * ppos) +{ -+ struct v2vdev_context *ctx = filp->private_data; -+ -+ DPRINTK("Release device\n"); -+ if (ctx->connected) -+ v2v_disconnect(ctx->channel); -+ if (ctx->buff) -+ kfree(ctx->buff); -+ kfree(filp->private_data); -+ return 0; ++ ssize_t ret; ++ ++ printk (KERN_ERR "v2v_read_stream(...\n"); ++ ret = wrap_v2vdev_read_stream (f, buf, count, ppos); ++ printk (KERN_ERR "v2v_read_stream(%p,%p,%d,%p)=%d\n", f, buf, count, ppos, ++ ret); ++ if (ret > 0) ++ hexdump ("<", buf, ret); ++ return ret; +} ++#endif + -+static unsigned int v2vdev_poll(struct file *filp, poll_table *wait) ++ ++static ssize_t ++v2vdev_write_stream (struct file *f, const char __user * buf, ++ size_t count, loff_t * ppos) +{ -+ unsigned int mask = 0; -+ struct v2vdev_context *ctx = filp->private_data; -+ struct v2v_wait *wait_state; -+ u8 reasons_mask = V2V_WAKE_REASON_CONTROL; -+ u8 reason; -+ int err; -+ enum v2v_endpoint_state state; -+ -+ wait_state = v2v_get_wait_state(ctx->channel); -+ poll_wait(filp, &wait_state->wait_event, wait); -+ -+ if (ctx->connected) -+ reasons_mask |= V2V_WAKE_REASON_RECEIVE; -+ -+ reason = v2v_get_wake_reason(ctx->channel, reasons_mask); -+ if (reason & V2V_WAKE_REASON_CONTROL) ++ struct v2vdev *c = f->private_data; ++ int nonblock = f->f_flags & O_NONBLOCK; ++ size_t writ = 0; ++ size_t n; ++ ++ volatile void *msg; ++ int err; ++ ++ ++ if (!access_ok (VERIFY_WRITE, buf, count)) ++ return -EFAULT; ++ ++ v2vdev_update_state (c, 0); ++ ++ ++ while (count) + { -+ if (!ctx->connected) { -+ err = v2v_get_remote_state(ctx->channel, &state); -+ if (ctx->listenner && (err == 0 && state == v2v_state_connected) && -+ v2v_accept(ctx->channel, 1) == 0) -+ { -+ v2vdev_wait_connected(ctx); -+ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_SEND); -+ DPRINTK("connected !\n"); -+ return 0; -+ } -+ } -+ else ++ if (v2vdev_loop_check (c, L_WRITE, &err)) ++ return writ ? writ : err; ++ ++ if (!nonblock) ++ n = MIN (count, V2V_STREAM_MSGSIZE); ++ else ++ n = count; ++ ++ err = v2v_nc2_prep_message (c->channel, n, 1, 0, &msg); ++ ++ switch (err) + { -+ err = v2v_get_remote_state(ctx->channel, &state); -+ if (err == 0 && ctx->connected && state != v2v_state_connected) -+ { -+ DPRINTK("Remote end %s, v2v_disconnect\n", v2v_endpoint_state_name(state)); -+ ctx->connected = 0; -+ v2v_disconnect(ctx->channel); -+ return POLLIN | POLLRDNORM; -+ } ++ case 0: ++ ++ err = copy_from_user ((void *) msg, buf, n); ++ v2v_nc2_send_messages (c->channel); ++ ++ if (err) ++ return -EFAULT; ++ ++ count -= n; ++ buf += n; ++ writ += n; ++ ++ break; ++ case -EAGAIN: ++ if (nonblock) ++ return writ ? writ : -EAGAIN; ++ c->send_blocked = 1; ++ //printk(KERN_ERR"write block start\n"); ++ v2vdev_wait (c); ++ //printk(KERN_ERR"write block end\n"); ++ break; ++ case -EINVAL: ++ return -EMSGSIZE; ++ default: ++ return writ ? writ : err; + } ++ + } -+ else if (reason & V2V_WAKE_REASON_RECEIVE) ++ ++ return writ; ++} ++ ++#if 0 ++static ssize_t ++not_v2vdev_write_stream (struct file *f, const char __user * buf, ++ size_t count, loff_t * ppos) ++{ ++ ssize_t ret; ++ printk (KERN_ERR "v2v_write_stream(...\n"); ++ ret = wrap_v2vdev_write_stream (f, buf, count, ppos); ++ printk (KERN_ERR "v2v_write_stream(%p,%p,%d,%p)=%d\n", f, buf, count, ppos, ++ ret); ++ if (count > 0) ++ hexdump (">", buf, count); ++ return ret; ++} ++#endif ++ ++ ++static int ++v2vdev_listen (struct file *f, const char __user * user_path, size_t size) ++{ ++ struct v2vdev *c = f->private_data; ++ int err; ++ char path[1024]; ++ ++ //FIXME - check for approriate state first ++ ++ if (size > (sizeof (path) + 1)) ++ return -EINVAL; ++ ++ if (copy_from_user (path, user_path, size)) ++ return -EFAULT; ++ ++ path[size] = 0; ++ ++ err = v2v_listen (path, &c->channel, 0, 0, 0); ++ if (err) ++ return err; ++ ++ BUG_ON (c->channel == NULL); ++ ++ v2vdev_update_state (c, 0); ++ ++ return 0; ++} ++ ++static int ++v2vdev_connect (struct file *f, const char __user * user_path, size_t size) ++{ ++ int nonblock = f->f_flags & O_NONBLOCK; ++ struct v2vdev *c = f->private_data; ++ int err; ++ char path[1024]; ++ ++ //FIXME - check for approriate state first ++ ++ if (size > (sizeof (path) + 1)) ++ return -EINVAL; ++ ++ if (copy_from_user (path, user_path, size)) ++ return -EFAULT; ++ ++ path[size] = 0; ++ ++ err = v2v_connect (path, &c->channel, 0); ++ if (err) ++ return err; ++ ++ BUG_ON (c->channel == NULL); ++ ++ v2vdev_update_state (c, 0); ++ ++ if (nonblock) ++ return -EINPROGRESS; ++ ++ while (c->state != V2VDEV_CONNECTED) + { -+ DUMP_CTX(ctx); -+ v2vdev_message_get(ctx); ++ if (v2vdev_loop_check (c, L_CONNECT, &err)) ++ return err; ++ ++ v2vdev_wait (c); + } + -+ if (ctx->data_len) -+ mask = POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++ ++static long ++v2vdev_ioctl (struct file *f, unsigned int cmd, unsigned long arg) ++{ ++ void __user *p = (void __user *) arg; ++ int len = _IOC_SIZE (cmd); ++ int rc = -ENOTTY; ++ ++ if (_IOC_TYPE (cmd) != 'V') ++ return rc; ++ ++ ++ if (_IOC_DIR (cmd) != _IOC_WRITE) ++ return rc; ++ ++ ++ switch (_IOC_NR (cmd)) ++ { ++ case _IOC_NR (V2VLISTEN (0)): ++ rc = v2vdev_listen (f, p, len); ++ break; ++ case _IOC_NR (V2VCONNECT (0)): ++ rc = v2vdev_connect (f, p, len); ++ break; ++ } ++ return rc; ++} + ++static unsigned int ++v2vdev_poll (struct file *f, poll_table * pt) ++{ ++ struct v2vdev *c = f->private_data; ++ unsigned int mask = 0; ++ struct v2v_wait *wait_state; + ++ if (!c->channel) + return mask; ++ ++ v2vdev_update_state (c, 0); ++ ++ ++ switch (c->state) ++ { ++ case V2VDEV_UNKNOWN: ++ case V2VDEV_UNBOUND: ++ case V2VDEV_LISTEN: ++ case V2VDEV_CONNECT: ++ break; ++ case V2VDEV_CONNECTED: ++ if (!c->recv_blocked && !buffer_pending (c->read_buf)) ++ v2vdev_receive_to_buf (c); ++ ++ if (buffer_pending (c->read_buf)) ++ mask |= POLLIN | POLLRDNORM; ++ if (!c->send_blocked) ++ mask |= POLLOUT | POLLWRNORM; ++ break; ++ case V2VDEV_DISCONNECTED: ++ mask |= POLLIN | POLLRDNORM; ++ break; ++ } ++ wait_state = v2v_get_wait_state (c->channel); ++ poll_wait (f, &wait_state->wait_event, pt); ++ ++ return mask; ++} ++ ++ ++ ++static int ++v2vdev_open (struct inode *inode, struct file *f) ++{ ++ struct v2vdev *c; ++ ++ c = kmalloc (sizeof (struct v2vdev), GFP_KERNEL); ++ if (!c) ++ return -ENOMEM; ++ ++ memset (c, 0, sizeof (struct v2vdev)); ++ ++ c->read_buf = buffer_new (); ++ if (!c->read_buf) ++ { ++ kfree (c); ++ return -ENOMEM; ++ } ++ ++ f->private_data = c; ++ ++ return 0; ++} ++ ++static int ++v2vdev_release (struct inode *inode, struct file *f) ++{ ++ struct v2vdev *c = f->private_data; ++ ++ ++ //FIXME - race ++ if (c->state == V2VDEV_CONNECTED) ++ v2v_disconnect (c->channel); ++ ++ if (c->read_buf) ++ buffer_free (c->read_buf); ++ ++ kfree (c); ++ return 0; +} + -+static const struct file_operations v2vdev_fops = { -+ .owner = THIS_MODULE, -+ .write = v2vdev_write, -+ .read = v2vdev_read, -+ .unlocked_ioctl = v2vdev_ioctl, -+ .open = v2vdev_open, -+ .release = v2vdev_release, -+ .poll = v2vdev_poll, ++ ++ ++static const struct file_operations v2vdev_fops_dgram = { ++ .owner = THIS_MODULE, ++ .write = v2vdev_write_dgram, ++ .read = v2vdev_read_dgram, ++ .unlocked_ioctl = v2vdev_ioctl, ++ .open = v2vdev_open, ++ .release = v2vdev_release, ++ .poll = v2vdev_poll, ++}; ++ ++ ++static struct miscdevice v2vdev_miscdev_dgram = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "v2v_dgram", ++ .fops = &v2vdev_fops_dgram, ++}; ++ ++static const struct file_operations v2vdev_fops_stream = { ++ .owner = THIS_MODULE, ++ .write = v2vdev_write_stream, ++ .read = v2vdev_read_stream, ++ .unlocked_ioctl = v2vdev_ioctl, ++ .open = v2vdev_open, ++ .release = v2vdev_release, ++ .poll = v2vdev_poll, +}; + -+static struct miscdevice v2vdev_miscdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "v2v", -+ .fops = &v2vdev_fops, ++static struct miscdevice v2vdev_miscdev_stream = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "v2v_stream", ++ .fops = &v2vdev_fops_stream, +}; + -+static int __init v2vdev_init(void) ++ ++static int __init ++v2vdev_init (void) +{ -+ int err = 0; ++ int err = 0; + -+ if (!is_running_on_xen()) -+ return -ENODEV; ++ if (!is_running_on_xen ()) ++ return -ENODEV; + -+ err = misc_register(&v2vdev_miscdev); -+ if (err != 0) { -+ DPRINTK(KERN_ALERT "Could not register /dev/v2v\n"); -+ return err; ++ err = misc_register (&v2vdev_miscdev_stream); ++ if (err != 0) ++ { ++ printk (KERN_ERR "Could not register /dev/v2v_stream\n"); ++ return err; + } -+ -+ DPRINTK("Xen V2V device installed.\n"); + -+ return 0; ++ err = misc_register (&v2vdev_miscdev_dgram); ++ if (err != 0) ++ { ++ misc_deregister (&v2vdev_miscdev_stream); ++ printk (KERN_ERR "Could not register /dev/v2v_dgram\n"); ++ return err; ++ } ++ ++ printk (KERN_INFO "Xen V2V device installed.\n"); ++ ++ return 0; +} + -+static void __exit v2vdev_cleanup(void) ++static void __exit ++v2vdev_cleanup (void) +{ -+ misc_deregister(&v2vdev_miscdev); ++ misc_deregister (&v2vdev_miscdev_dgram); ++ misc_deregister (&v2vdev_miscdev_stream); +} + -+module_init(v2vdev_init); -+module_exit(v2vdev_cleanup); ++module_init (v2vdev_init); ++module_exit (v2vdev_cleanup); + -+MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_LICENSE ("Dual BSD/GPL");