]> xenbits.xen.org Git - xenclient/linux-2.6.27-pq.git/commitdiff
Update v2vdev.
authorJean Guyader <jean.guyader@eu.citrix.com>
Fri, 6 Nov 2009 14:03:40 +0000 (14:03 +0000)
committerJean Guyader <jean.guyader@eu.citrix.com>
Fri, 6 Nov 2009 14:03:40 +0000 (14:03 +0000)
        - Handle connect/disconnect.
        - do the v2v_accept inside _poll
        - modify _read to have a more posix sementic.

master/v2v-dev

index 5b4a425b82cc0283cf2246ba7f0af1393499433f..866d633900068296eb32f48724c9429a5e931cd0 100644 (file)
@@ -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;
 +}