From: Jean Guyader Date: Fri, 6 Nov 2009 14:03:40 +0000 (+0000) Subject: Update v2vdev. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=e41e3a5dd4b3fdd3acb5cde2796c3f3aa9b19767;p=xenclient%2Flinux-2.6.27-pq.git Update v2vdev. - Handle connect/disconnect. - do the v2v_accept inside _poll - modify _read to have a more posix sementic. --- diff --git a/master/v2v-dev b/master/v2v-dev index 5b4a425..866d633 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..e56706d 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,27 +14,28 @@ 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..c390314 100644 --- a/drivers/xen/v2v/Makefile +++ b/drivers/xen/v2v/Makefile -@@ -1,5 +1,6 @@ +@@ -5,4 +5,7 @@ obj-$(CONFIG_XEN_V2V_DRV) += v2vdrv.o + v2vdrv-objs = + v2vdrv-objs += v2vsamp.o v2vops.o - obj-$(CONFIG_XEN_V2V) += v2v.o v2vutl.o - obj-$(CONFIG_XEN_V2V_DRV) += v2vdrv.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..c7afdf3 +index 0000000..39d0a84 --- /dev/null +++ b/drivers/xen/v2v/v2vdev.c -@@ -0,0 +1,400 @@ +@@ -0,0 +1,511 @@ +/****************************************************************************** + * drivers/xen/v2v/v2vdev.c + * + * V2V broker. -+ * ++ * + * Copyright (c) 2009 Jean Guyader + * Copyright (c) 2009 Citrix Systems, Inc. + * @@ -85,32 +86,52 @@ index 0000000..c7afdf3 + +#define V2VLISTEN(len) _IOC(_IOC_WRITE, 'V', 0x01, len) +#define V2VCONNECT(len) _IOC(_IOC_WRITE, 'V', 0x02, len) -+#define V2VTYPE _IOC(_IOC_WRITE, 'V', 0x03, int) + -+#define MIN(_x_, _y_) ((_x_) > (_y_) ? (_x_) : (_y_)) ++#define MIN(_x_, _y_) ((_x_) < (_y_) ? (_x_) : (_y_)) + -+#define V2VDEV_LOG "V2V-dev" ++#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) + +struct v2vdev_context +{ + int connected; ++ + void *buff; ++ char *data_ptr; + size_t buff_size; ++ size_t data_len; ++ ++ + int last_err; + int listenner; -+ int type; + struct v2v_channel *channel; +}; + ++#if 0 ++#define DUMP_CTX(a) dump_ctx(__func__, __LINE__, a) ++static void dump_ctx(const char *func, int line, struct v2vdev_context *ctx) ++{ ++ 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) ++ + +static void +hexdump (char *prefix, void *_d, int len) +{ + uint8_t *d = (uint8_t *) _d; + int i, j, k; -+ int s, e; ++ int e; + -+ printk (KERN_ERR "%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; @@ -120,19 +141,18 @@ index 0000000..c7afdf3 + + for (i = 0; i < e; i += 16) + { -+ printk (KERN_ERR "%s %05x:", prefix, i); ++ printk ("%s %05x:", prefix, i); + for (j = 0; j < 16; ++j) + { + k = i + j; + + if (k < len) -+ printk (" %02x", d[k]); ++ printk ("%02x", d[k]); + else -+ printk (" "); -+ if (j == 7) -+ printk (" "); ++ printk (" "); + } + ++ printk(" "); + for (j = 0; j < 16; ++j) + { + k = i + j; @@ -145,15 +165,64 @@ index 0000000..c7afdf3 + c = '.'; + printk ("%c", c); + } -+ else -+ printk (" "); -+ if (j == 7) -+ printk (" "); + } + printk ("\n"); + } +} + ++static int v2v_receive_in_queue(struct v2vdev_context *ctx) ++{ ++ return v2v_get_wake_reason(ctx->channel, V2V_WAKE_REASON_ANY) == V2V_WAKE_REASON_RECEIVE; ++} ++ ++static int v2vdev_message_get(struct v2vdev_context *ctx) ++{ ++ volatile void *buff; ++ ssize_t size = 0; ++ unsigned vtype, vflags; ++ ++ ++ if (!ctx->connected) { ++ ctx->last_err=-ENOTCONN; ++ return ctx->last_err; ++ } ++ ++ if (ctx->data_len) { ++ DPRINTK(KERN_ERR "****** data_len not zero in v2vdev_message_get\n"); ++ return 0; ++ } ++ ++ ++ vtype = vflags = 0; ++ ctx->last_err = v2v_nc2_get_message(ctx->channel, ++ (const volatile void **)&buff, &size, ++ &vtype, &vflags); ++ ++ if (ctx->last_err) { ++ if (ctx->last_err==-ENODATA) ++ ctx->last_err=0; ++ return ctx->last_err; ++ } ++ ++ hexdump("<", (void *) buff, size); ++ ++ if (size>ctx->buff_size) { ++ ctx->buff_size=size; ++ ctx->buff = krealloc(ctx->buff, ctx->buff_size, GFP_KERNEL); ++ } ++ ++ memcpy(ctx->buff, (void *)buff, size); ++ ctx->data_len=size; ++ ctx->data_ptr=ctx->buff; ++ //if (ctx->data_len > 2) ctx->data_len -=2; ++ ++ ++ v2v_nc2_finish_message(ctx->channel); ++ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_RECEIVE); ++ ++ return ctx->last_err; ++} ++ +static int v2vdev_wait_connected(struct v2vdev_context *ctx) +{ + struct v2v_wait *wait_state; @@ -164,7 +233,7 @@ index 0000000..c7afdf3 + while (!ctx->connected) + { + wait_state = v2v_get_wait_state(ctx->channel); -+ printk(V2VDEV_LOG" wait event ....\n"); ++ 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); @@ -172,11 +241,12 @@ index 0000000..c7afdf3 + err = v2v_get_remote_state(ctx->channel, &state); + if (err) + { -+ printk(V2VDEV_LOG" failure in v2v_get_remote_state() - err: %d\n", err); ++ DPRINTK("failure in v2v_get_remote_state() - err: %d\n", err); ++ ctx->connected = 0;; + v2v_disconnect(ctx->channel); + return err; + } -+ printk(V2VDEV_LOG" endpoint state: %s\n", v2v_endpoint_state_name(state)); ++ DPRINTK("endpoint state: %s\n", v2v_endpoint_state_name(state)); + ctx->connected = state == v2v_state_connected; + } + return 0; @@ -195,7 +265,7 @@ index 0000000..c7afdf3 + err = v2v_listen(path, &ctx->channel, 0, 0, 0); + if (err) + { -+ printk(V2VDEV_LOG" failure in v2v_listen() - error: %d\n", err); ++ DPRINTK("failure in v2v_listen() - error: %d\n", err); + return err; + } + BUG_ON(ctx->channel == NULL); @@ -215,19 +285,19 @@ index 0000000..c7afdf3 + return -EINVAL; + path[size] = 0; + -+ printk(V2VDEV_LOG" connect on %s\n", path); ++ DPRINTK("connect on %s\n", path); + + err = v2v_connect(path, &ctx->channel, 0); + if (err) + { -+ printk(V2VDEV_LOG" failure in connect() - err: %d\n", err); ++ DPRINTK("failure in connect() - err: %d\n", err); + return err; + } + + err = v2vdev_wait_connected(ctx); + if (err) + { -+ printk(V2VDEV_LOG" failure in wait_connected() - error: %d\n", err); ++ DPRINTK("failure in wait_connected() - error: %d\n", err); + return err; + } + return 0; @@ -237,26 +307,66 @@ index 0000000..c7afdf3 + size_t count, loff_t *ppos) +{ + struct v2vdev_context *ctx = filp->private_data; -+ ssize_t n, size; -+ uint16_t tag; -+ -+ if (ctx->last_err) -+ return -ctx->last_err; -+ -+ size = MIN(count, ctx->buff_size); -+ n = copy_to_user(buf, ctx->buff, size); -+ ctx->buff_size -= size; -+ if (ctx->buff_size == 0) -+ { -+ kfree(ctx->buff); -+ ctx->buff = NULL; -+ } -+ else -+ ctx->buff += size; -+ -+ v2v_nc2_finish_message(ctx->channel); -+ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_RECEIVE); -+ return size - n; ++ 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); ++ } ++ } ++ ++ DPRINTK("v2vdev_read needed got %d/%d\n",red,red); ++ ++ return red; +} + +static ssize_t v2vdev_write(struct file *filp, const char __user *buf, @@ -265,21 +375,22 @@ index 0000000..c7afdf3 + struct v2vdev_context *ctx = filp->private_data; + volatile void *msg; + int err; -+ -+ err = v2v_nc2_prep_message(ctx->channel, count, ctx->type, 0, &msg); ++ ++ DUMP_CTX(ctx); ++ if (!ctx->connected) ++ return -ENOTCONN; ++ ++ err = v2v_nc2_prep_message(ctx->channel, count, 1, 0, &msg); + if (err) + { -+ printk(V2VDEV_LOG" failure in v2v_nc2_prep_message() - error: %d\n", err); -+ return -EAGAIN; ++ DPRINTK("failure in v2v_nc2_prep_message() - error: %d\n", err); ++ return -EIO; + } + -+ if (copy_from_user((void *)msg, buf, count) != 0) -+ { -+ printk(V2VDEV_LOG" failure in copy_from_user()\n"); -+ return 0; -+ } ++ if (copy_from_user((void *)msg, buf, count)) ++ return -EFAULT; + -+ hexdump(">", msg, count); ++ hexdump(">", (void *) msg, count); + v2v_nc2_send_messages(ctx->channel); + v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_SEND); + return count; @@ -287,24 +398,23 @@ index 0000000..c7afdf3 + +static long v2vdev_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) -+{ -+ int rc; -+ struct v2vdev_context *ctx = filp->private_data; -+ ++{ ++ 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 -EINVAL; ++ return -ENOTTY; + + if (_IOC_DIR(cmd) == _IOC_WRITE) + { + if ((_IOC_NR(cmd) == _IOC_NR(V2VLISTEN(0)))) -+ rc = v2vdev_listen(ctx, (void __user *)arg, _IOC_SIZE(cmd)); ++ rc = v2vdev_listen(ctx, p, _IOC_SIZE(cmd)); + if ((_IOC_NR(cmd) == _IOC_NR(V2VCONNECT(0)))) -+ rc = v2vdev_connect(ctx, (void __user *)arg, _IOC_SIZE(cmd)); -+ if ((_IOC_NR(cmd) == _IOC_NR(V2VTYPE))) -+ ctx->type = arg; ++ rc = v2vdev_connect(ctx, p, _IOC_SIZE(cmd)); + } + break; + } @@ -317,8 +427,6 @@ index 0000000..c7afdf3 + + ctx = kmalloc(sizeof (struct v2vdev_context), GFP_KERNEL); + memset(ctx, 0, sizeof (struct v2vdev_context)); -+ /* Set the default type to DATA_STREAM */ -+ ctx->type = 1; + filp->private_data = ctx; + return 0; +} @@ -327,6 +435,7 @@ index 0000000..c7afdf3 +{ + struct v2vdev_context *ctx = filp->private_data; + ++ DPRINTK("Release device\n"); + if (ctx->connected) + v2v_disconnect(ctx->channel); + if (ctx->buff) @@ -335,27 +444,6 @@ index 0000000..c7afdf3 + return 0; +} + -+static int v2vdev_message_get(struct v2vdev_context *ctx) -+{ -+ volatile void *buff; -+ ssize_t size = 0; -+ unsigned vtype, vflags; -+ uint16_t tag; -+ -+ vtype = vflags = 0; -+ ctx->last_err = v2v_nc2_get_message(ctx->channel, -+ (const volatile void **)&buff, &size, -+ &vtype, &vflags); -+ if (ctx->last_err == 0) -+ { -+ hexdump("<", buff, size); -+ ctx->buff = krealloc(ctx->buff, ctx->buff_size + size, GFP_KERNEL); -+ memcpy(ctx->buff + ctx->buff_size, (void *)buff, size); -+ ctx->buff_size += size; -+ } -+ return ctx->last_err; -+} -+ +static unsigned int v2vdev_poll(struct file *filp, poll_table *wait) +{ + unsigned int mask = 0; @@ -363,27 +451,51 @@ index 0000000..c7afdf3 + struct v2v_wait *wait_state; + u8 reasons_mask = V2V_WAKE_REASON_CONTROL; + u8 reason; -+ -+ if (!ctx->connected) -+ reasons_mask |= V2V_WAKE_REASON_ANY; -+ else -+ reasons_mask |= V2V_WAKE_REASON_RECEIVE; ++ 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 && ctx->listenner) -+ if (v2v_accept(ctx->channel, 1) != EAGAIN) ++ if (ctx->connected) ++ reasons_mask |= V2V_WAKE_REASON_RECEIVE; ++ ++ reason = v2v_get_wake_reason(ctx->channel, reasons_mask); ++ if (reason & V2V_WAKE_REASON_CONTROL) ++ { ++ 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 + { -+ v2vdev_wait_connected(ctx); -+ printk(V2VDEV_LOG" connected !\n"); -+ return 0; ++ 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; ++ } + } ++ } ++ else if (reason & V2V_WAKE_REASON_RECEIVE) ++ { ++ DUMP_CTX(ctx); ++ v2vdev_message_get(ctx); ++ } ++ ++ if (ctx->data_len) ++ mask = POLLIN | POLLRDNORM; ++ + -+ reason = v2v_get_wake_reason(ctx->channel, reasons_mask); -+ if (reason & V2V_WAKE_REASON_RECEIVE) -+ if (v2vdev_message_get(ctx) == 0) -+ mask = POLLIN | POLLRDNORM; + return mask; +} + @@ -412,11 +524,11 @@ index 0000000..c7afdf3 + + err = misc_register(&v2vdev_miscdev); + if (err != 0) { -+ printk(KERN_ALERT "Could not register /dev/v2v\n"); ++ DPRINTK(KERN_ALERT "Could not register /dev/v2v\n"); + return err; + } -+ -+ printk("Xen V2V device installed.\n"); ++ ++ DPRINTK("Xen V2V device installed.\n"); + + return 0; +}