]> xenbits.xen.org Git - xenclient/linux-2.6.27-pq.git/commitdiff
Create a char device to handler v2v connection in userland.
authorJean Guyader <jean.guyader@eu.citrix.com>
Wed, 4 Nov 2009 05:27:08 +0000 (05:27 +0000)
committerJean Guyader <jean.guyader@eu.citrix.com>
Wed, 4 Nov 2009 05:28:51 +0000 (05:28 +0000)
master/series
master/v2v-dev [new file with mode: 0644]

index 33a4d809a9bd176750196d7a9776dcb0e30aede8..fe0cb9d32432a43c4e240ba257e8aec807d62ac7 100644 (file)
@@ -356,3 +356,4 @@ itpm
 v2v-core
 v2v-async
 v2v-accept-nonblock
+v2v-dev
diff --git a/master/v2v-dev b/master/v2v-dev
new file mode 100644 (file)
index 0000000..5b4a425
--- /dev/null
@@ -0,0 +1,432 @@
+diff --git a/drivers/xen/v2v/Kconfig b/drivers/xen/v2v/Kconfig
+index 5966234..b3b6ef4 100644
+--- a/drivers/xen/v2v/Kconfig
++++ b/drivers/xen/v2v/Kconfig
+@@ -22,3 +22,10 @@ config XEN_V2V_DRV
+       default n
+         help
+           Sample for Xen V2V interdomain communication services.
++
++config XEN_V2V_DEV
++        tristate "Xen V2V device"
++        depends on XEN_V2V
++      default m
++        help
++          Xen V2V char device for userland v2v.
+diff --git a/drivers/xen/v2v/Makefile b/drivers/xen/v2v/Makefile
+index f3442d9..5230cd6 100644
+--- a/drivers/xen/v2v/Makefile
++++ b/drivers/xen/v2v/Makefile
+@@ -1,5 +1,6 @@
+ 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
+--- /dev/null
++++ b/drivers/xen/v2v/v2vdev.c
+@@ -0,0 +1,400 @@
++/******************************************************************************
++ * drivers/xen/v2v/v2vdev.c
++ *
++ * V2V broker.
++ * 
++ * Copyright (c) 2009 Jean Guyader
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * 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
++ * 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
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/random.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/major.h>
++#include <linux/proc_fs.h>
++#include <linux/poll.h>
++#include <linux/jiffies.h>
++#include <xen/xenbus.h>
++#include <xen/v2v.h>
++#include <xen/interface/io/vring.h>
++
++#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 V2VDEV_LOG              "V2V-dev"
++
++struct v2vdev_context
++{
++    int                 connected;
++    void                *buff;
++    size_t              buff_size;
++    int                 last_err;
++    int                 listenner;
++    int                 type;
++    struct v2v_channel  *channel;
++};
++
++
++static void
++hexdump (char *prefix, void *_d, int len)
++{
++    uint8_t *d = (uint8_t *) _d;
++    int i, j, k;
++    int s, e;
++
++    printk (KERN_ERR "%s %d bytes from %p\n", prefix, len, d);
++
++    if (!d || len<0)
++        return;
++
++    e = len + 15;
++    e &= ~15;
++
++    for (i = 0; i < e; i += 16)
++    {
++        printk (KERN_ERR "%s %05x:", prefix, i);
++        for (j = 0; j < 16; ++j)
++        {
++            k = i + j;
++
++            if (k < len)
++                printk (" %02x", d[k]);
++            else
++                printk ("   ");
++            if (j == 7)
++                printk (" ");
++        }
++
++        for (j = 0; j < 16; ++j)
++        {
++            k = i + j;
++            if (k < len)
++            {
++                uint8_t c = d[k];
++                if (c < 33)
++                    c = '.';
++                if (c > 126)
++                    c = '.';
++                printk ("%c", c);
++            }
++            else
++                printk (" ");
++            if (j == 7)
++                printk (" ");
++        }
++        printk ("\n");
++    }
++}
++
++static int v2vdev_wait_connected(struct v2vdev_context *ctx)
++{
++    struct v2v_wait             *wait_state;
++    u8                          reasons_mask = V2V_WAKE_REASON_CONTROL;
++    int                         err;
++    enum v2v_endpoint_state     state;
++
++    while (!ctx->connected)
++    {
++        wait_state = v2v_get_wait_state(ctx->channel);
++        printk(V2VDEV_LOG" 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)
++        {
++            printk(V2VDEV_LOG" failure in v2v_get_remote_state() - err: %d\n", err);
++            v2v_disconnect(ctx->channel);
++            return err;
++        }
++        printk(V2VDEV_LOG" 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)
++{
++    int         err;
++    char        path[1024];
++
++    if (copy_from_user(path, user_path, size) != 0)
++        return -EINVAL;
++    path[size] = 0;
++
++    err = v2v_listen(path, &ctx->channel, 0, 0, 0);
++    if (err)
++    {
++        printk(V2VDEV_LOG" failure in v2v_listen() - error: %d\n", err);
++        return err;
++    }
++    BUG_ON(ctx->channel == NULL);
++
++    ctx->listenner = 1;
++
++    return 0;
++}
++
++static int v2vdev_connect(struct v2vdev_context *ctx,
++                          const char __user *user_path, size_t size)
++{
++    char                path[1024];
++    int                 err;
++
++    if (copy_from_user(path, user_path, size) != 0)
++        return -EINVAL;
++    path[size] = 0;
++
++    printk(V2VDEV_LOG" connect on %s\n", path);
++
++    err = v2v_connect(path, &ctx->channel, 0);
++    if (err)
++    {
++        printk(V2VDEV_LOG" 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);
++        return err;
++    }
++    return 0;
++}
++
++static ssize_t v2vdev_read(struct file *filp, char __user *buf,
++                           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;
++}
++
++static ssize_t v2vdev_write(struct file *filp, const char __user *buf,
++                               size_t count, loff_t *ppos)
++{
++    struct v2vdev_context       *ctx = filp->private_data;
++    volatile void               *msg;
++    int                         err;
++    
++    err = v2v_nc2_prep_message(ctx->channel, count, ctx->type, 0, &msg);
++    if (err)
++    {
++        printk(V2VDEV_LOG" failure in v2v_nc2_prep_message() - error: %d\n", err);
++        return -EAGAIN;
++    }
++
++    if (copy_from_user((void *)msg, buf, count) != 0)
++    {
++        printk(V2VDEV_LOG" failure in copy_from_user()\n");
++        return 0;
++    }
++
++    hexdump(">", msg, count);
++    v2v_nc2_send_messages(ctx->channel);
++    v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_SEND);
++    return count;
++}
++
++static long v2vdev_ioctl(struct file *filp,
++                          unsigned int cmd, unsigned long arg)
++{   
++    int                         rc;
++    struct v2vdev_context       *ctx = filp->private_data;
++    
++    rc = -ENOSYS;
++    switch (cmd) {
++        default:
++            if (_IOC_TYPE(cmd) != 'V')
++                return -EINVAL;
++
++            if (_IOC_DIR(cmd) == _IOC_WRITE)
++            {
++                if ((_IOC_NR(cmd) == _IOC_NR(V2VLISTEN(0))))
++                    rc = v2vdev_listen(ctx, (void __user *)arg, _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;
++            }
++            break;
++    }
++    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));
++    /* Set the default type to DATA_STREAM */
++    ctx->type = 1;
++    filp->private_data = ctx;
++    return 0;
++}
++
++static int v2vdev_release(struct inode *inode, struct file *filp)
++{
++    struct v2vdev_context       *ctx = filp->private_data;
++
++    if (ctx->connected)
++        v2v_disconnect(ctx->channel);
++    if (ctx->buff)
++        kfree(ctx->buff);
++    kfree(filp->private_data);
++    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;
++    struct v2vdev_context       *ctx = filp->private_data;
++    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;
++
++    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)
++        {
++            v2vdev_wait_connected(ctx);
++            printk(V2VDEV_LOG" connected !\n");
++            return 0;
++        }
++
++    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;
++}
++
++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 struct miscdevice v2vdev_miscdev = {
++    .minor        = MISC_DYNAMIC_MINOR,
++    .name         = "v2v",
++    .fops         = &v2vdev_fops,
++};
++
++static int __init v2vdev_init(void)
++{
++    int err = 0;
++
++    if (!is_running_on_xen())
++        return -ENODEV;
++
++    err = misc_register(&v2vdev_miscdev);
++    if (err != 0) {
++        printk(KERN_ALERT "Could not register /dev/v2v\n");
++        return err;
++    }
++    
++    printk("Xen V2V device installed.\n");
++
++    return 0;
++}
++
++static void __exit v2vdev_cleanup(void)
++{
++    misc_deregister(&v2vdev_miscdev);
++}
++
++module_init(v2vdev_init);
++module_exit(v2vdev_cleanup);
++
++MODULE_LICENSE("Dual BSD/GPL");