[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 4/5] xen: Add xenbus device driver



On Sun, Nov 27, 2011 at 11:07:07PM +0100, Bastian Blank wrote:
> Access to xenbus is currently handled via xenfs. This adds a device
> driver for xenbus and makes xenfs use this code.
> 
> Signed-off-by: Bastian Blank <waldi@xxxxxxxxxx>
> ---
>  drivers/xen/xenbus/Makefile              |    1 +
>  drivers/xen/xenbus/xenbus_comms.h        |    4 +
>  drivers/xen/xenbus/xenbus_dev_frontend.c |  624 
> ++++++++++++++++++++++++++++++
>  drivers/xen/xenfs/Makefile               |    2 +-
>  drivers/xen/xenfs/super.c                |    3 +-
>  drivers/xen/xenfs/xenbus.c               |  593 ----------------------------
>  drivers/xen/xenfs/xenfs.h                |    1 -

Can you use 'git mv' please?

This looks  ike you are just moving the file around.

>  7 files changed, 632 insertions(+), 596 deletions(-)
>  create mode 100644 drivers/xen/xenbus/xenbus_dev_frontend.c
>  delete mode 100644 drivers/xen/xenfs/xenbus.c
> 
> diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
> index 8dca685..a2ea363 100644
> --- a/drivers/xen/xenbus/Makefile
> +++ b/drivers/xen/xenbus/Makefile
> @@ -1,4 +1,5 @@
>  obj-y        += xenbus.o
> +obj-y        += xenbus_dev_frontend.o
>  
>  xenbus-objs =
>  xenbus-objs += xenbus_client.o
> diff --git a/drivers/xen/xenbus/xenbus_comms.h 
> b/drivers/xen/xenbus/xenbus_comms.h
> index c21db75..6e42800 100644
> --- a/drivers/xen/xenbus/xenbus_comms.h
> +++ b/drivers/xen/xenbus/xenbus_comms.h
> @@ -31,6 +31,8 @@
>  #ifndef _XENBUS_COMMS_H
>  #define _XENBUS_COMMS_H
>  
> +#include <linux/fs.h>
> +
>  int xs_init(void);
>  int xb_init_comms(void);
>  
> @@ -43,4 +45,6 @@ int xs_input_avail(void);
>  extern struct xenstore_domain_interface *xen_store_interface;
>  extern int xen_store_evtchn;
>  
> +extern const struct file_operations xen_xenbus_fops;
> +
>  #endif /* _XENBUS_COMMS_H */
> diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c 
> b/drivers/xen/xenbus/xenbus_dev_frontend.c
> new file mode 100644
> index 0000000..fb30cff
> --- /dev/null
> +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c
> @@ -0,0 +1,624 @@
> +/*
> + * Driver giving user-space access to the kernel's xenbus connection
> + * to xenstore.
> + *
> + * Copyright (c) 2005, Christian Limpach
> + * Copyright (c) 2005, Rusty Russell, IBM Corporation
> + *
> + * 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 file (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.
> + *
> + * Changes:
> + * 2008-10-07  Alex Zeffertt    Replaced /proc/xen/xenbus with xenfs 
> filesystem
> + *                              and /proc/xen compatibility mount point.
> + *                              Turned xenfs into a loadable module.
> + */
> +
> +#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 <linux/poll.h>
> +#include <linux/mutex.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +#include <linux/mount.h>
> +#include <linux/pagemap.h>
> +#include <linux/uaccess.h>
> +#include <linux/init.h>
> +#include <linux/namei.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +
> +#include "xenbus_comms.h"
> +
> +#include <xen/xenbus.h>
> +#include <asm/xen/hypervisor.h>
> +
> +MODULE_LICENSE("GPL");
> +
> +/*
> + * An element of a list of outstanding transactions, for which we're
> + * still waiting a reply.
> + */
> +struct xenbus_transaction_holder {
> +     struct list_head list;
> +     struct xenbus_transaction handle;
> +};
> +
> +/*
> + * A buffer of data on the queue.
> + */
> +struct read_buffer {
> +     struct list_head list;
> +     unsigned int cons;
> +     unsigned int len;
> +     char msg[];
> +};
> +
> +struct xenbus_file_priv {
> +     /*
> +      * msgbuffer_mutex is held while partial requests are built up
> +      * and complete requests are acted on.  It therefore protects
> +      * the "transactions" and "watches" lists, and the partial
> +      * request length and buffer.
> +      *
> +      * reply_mutex protects the reply being built up to return to
> +      * usermode.  It nests inside msgbuffer_mutex but may be held
> +      * alone during a watch callback.
> +      */
> +     struct mutex msgbuffer_mutex;
> +
> +     /* In-progress transactions */
> +     struct list_head transactions;
> +
> +     /* Active watches. */
> +     struct list_head watches;
> +
> +     /* Partial request. */
> +     unsigned int len;
> +     union {
> +             struct xsd_sockmsg msg;
> +             char buffer[PAGE_SIZE];
> +     } u;
> +
> +     /* Response queue. */
> +     struct mutex reply_mutex;
> +     struct list_head read_buffers;
> +     wait_queue_head_t read_waitq;
> +
> +};
> +
> +/* Read out any raw xenbus messages queued up. */
> +static ssize_t xenbus_file_read(struct file *filp,
> +                            char __user *ubuf,
> +                            size_t len, loff_t *ppos)
> +{
> +     struct xenbus_file_priv *u = filp->private_data;
> +     struct read_buffer *rb;
> +     unsigned i;
> +     int ret;
> +
> +     mutex_lock(&u->reply_mutex);
> +again:
> +     while (list_empty(&u->read_buffers)) {
> +             mutex_unlock(&u->reply_mutex);
> +             if (filp->f_flags & O_NONBLOCK)
> +                     return -EAGAIN;
> +
> +             ret = wait_event_interruptible(u->read_waitq,
> +                                            !list_empty(&u->read_buffers));
> +             if (ret)
> +                     return ret;
> +             mutex_lock(&u->reply_mutex);
> +     }
> +
> +     rb = list_entry(u->read_buffers.next, struct read_buffer, list);
> +     i = 0;
> +     while (i < len) {
> +             unsigned sz = min((unsigned)len - i, rb->len - rb->cons);
> +
> +             ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz);
> +
> +             i += sz - ret;
> +             rb->cons += sz - ret;
> +
> +             if (ret != 0) {
> +                     if (i == 0)
> +                             i = -EFAULT;
> +                     goto out;
> +             }
> +
> +             /* Clear out buffer if it has been consumed */
> +             if (rb->cons == rb->len) {
> +                     list_del(&rb->list);
> +                     kfree(rb);
> +                     if (list_empty(&u->read_buffers))
> +                             break;
> +                     rb = list_entry(u->read_buffers.next,
> +                                     struct read_buffer, list);
> +             }
> +     }
> +     if (i == 0)
> +             goto again;
> +
> +out:
> +     mutex_unlock(&u->reply_mutex);
> +     return i;
> +}
> +
> +/*
> + * Add a buffer to the queue.  Caller must hold the appropriate lock
> + * if the queue is not local.  (Commonly the caller will build up
> + * multiple queued buffers on a temporary local list, and then add it
> + * to the appropriate list under lock once all the buffers have een
> + * successfully allocated.)
> + */
> +static int queue_reply(struct list_head *queue, const void *data, size_t len)
> +{
> +     struct read_buffer *rb;
> +
> +     if (len == 0)
> +             return 0;
> +
> +     rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
> +     if (rb == NULL)
> +             return -ENOMEM;
> +
> +     rb->cons = 0;
> +     rb->len = len;
> +
> +     memcpy(rb->msg, data, len);
> +
> +     list_add_tail(&rb->list, queue);
> +     return 0;
> +}
> +
> +/*
> + * Free all the read_buffer s on a list.
> + * Caller must have sole reference to list.
> + */
> +static void queue_cleanup(struct list_head *list)
> +{
> +     struct read_buffer *rb;
> +
> +     while (!list_empty(list)) {
> +             rb = list_entry(list->next, struct read_buffer, list);
> +             list_del(list->next);
> +             kfree(rb);
> +     }
> +}
> +
> +struct watch_adapter {
> +     struct list_head list;
> +     struct xenbus_watch watch;
> +     struct xenbus_file_priv *dev_data;
> +     char *token;
> +};
> +
> +static void free_watch_adapter(struct watch_adapter *watch)
> +{
> +     kfree(watch->watch.node);
> +     kfree(watch->token);
> +     kfree(watch);
> +}
> +
> +static struct watch_adapter *alloc_watch_adapter(const char *path,
> +                                              const char *token)
> +{
> +     struct watch_adapter *watch;
> +
> +     watch = kzalloc(sizeof(*watch), GFP_KERNEL);
> +     if (watch == NULL)
> +             goto out_fail;
> +
> +     watch->watch.node = kstrdup(path, GFP_KERNEL);
> +     if (watch->watch.node == NULL)
> +             goto out_free;
> +
> +     watch->token = kstrdup(token, GFP_KERNEL);
> +     if (watch->token == NULL)
> +             goto out_free;
> +
> +     return watch;
> +
> +out_free:
> +     free_watch_adapter(watch);
> +
> +out_fail:
> +     return NULL;
> +}
> +
> +static void watch_fired(struct xenbus_watch *watch,
> +                     const char **vec,
> +                     unsigned int len)
> +{
> +     struct watch_adapter *adap;
> +     struct xsd_sockmsg hdr;
> +     const char *path, *token;
> +     int path_len, tok_len, body_len, data_len = 0;
> +     int ret;
> +     LIST_HEAD(staging_q);
> +
> +     adap = container_of(watch, struct watch_adapter, watch);
> +
> +     path = vec[XS_WATCH_PATH];
> +     token = adap->token;
> +
> +     path_len = strlen(path) + 1;
> +     tok_len = strlen(token) + 1;
> +     if (len > 2)
> +             data_len = vec[len] - vec[2] + 1;
> +     body_len = path_len + tok_len + data_len;
> +
> +     hdr.type = XS_WATCH_EVENT;
> +     hdr.len = body_len;
> +
> +     mutex_lock(&adap->dev_data->reply_mutex);
> +
> +     ret = queue_reply(&staging_q, &hdr, sizeof(hdr));
> +     if (!ret)
> +             ret = queue_reply(&staging_q, path, path_len);
> +     if (!ret)
> +             ret = queue_reply(&staging_q, token, tok_len);
> +     if (!ret && len > 2)
> +             ret = queue_reply(&staging_q, vec[2], data_len);
> +
> +     if (!ret) {
> +             /* success: pass reply list onto watcher */
> +             list_splice_tail(&staging_q, &adap->dev_data->read_buffers);
> +             wake_up(&adap->dev_data->read_waitq);
> +     } else
> +             queue_cleanup(&staging_q);
> +
> +     mutex_unlock(&adap->dev_data->reply_mutex);
> +}
> +
> +static int xenbus_write_transaction(unsigned msg_type,
> +                                 struct xenbus_file_priv *u)
> +{
> +     int rc;
> +     void *reply;
> +     struct xenbus_transaction_holder *trans = NULL;
> +     LIST_HEAD(staging_q);
> +
> +     if (msg_type == XS_TRANSACTION_START) {
> +             trans = kmalloc(sizeof(*trans), GFP_KERNEL);
> +             if (!trans) {
> +                     rc = -ENOMEM;
> +                     goto out;
> +             }
> +     }
> +
> +     reply = xenbus_dev_request_and_reply(&u->u.msg);
> +     if (IS_ERR(reply)) {
> +             kfree(trans);
> +             rc = PTR_ERR(reply);
> +             goto out;
> +     }
> +
> +     if (msg_type == XS_TRANSACTION_START) {
> +             trans->handle.id = simple_strtoul(reply, NULL, 0);
> +
> +             list_add(&trans->list, &u->transactions);
> +     } else if (msg_type == XS_TRANSACTION_END) {
> +             list_for_each_entry(trans, &u->transactions, list)
> +                     if (trans->handle.id == u->u.msg.tx_id)
> +                             break;
> +             BUG_ON(&trans->list == &u->transactions);
> +             list_del(&trans->list);
> +
> +             kfree(trans);
> +     }
> +
> +     mutex_lock(&u->reply_mutex);
> +     rc = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg));
> +     if (!rc)
> +             rc = queue_reply(&staging_q, reply, u->u.msg.len);
> +     if (!rc) {
> +             list_splice_tail(&staging_q, &u->read_buffers);
> +             wake_up(&u->read_waitq);
> +     } else {
> +             queue_cleanup(&staging_q);
> +     }
> +     mutex_unlock(&u->reply_mutex);
> +
> +     kfree(reply);
> +
> +out:
> +     return rc;
> +}
> +
> +static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
> +{
> +     struct watch_adapter *watch, *tmp_watch;
> +     char *path, *token;
> +     int err, rc;
> +     LIST_HEAD(staging_q);
> +
> +     path = u->u.buffer + sizeof(u->u.msg);
> +     token = memchr(path, 0, u->u.msg.len);
> +     if (token == NULL) {
> +             rc = -EILSEQ;
> +             goto out;
> +     }
> +     token++;
> +
> +     if (msg_type == XS_WATCH) {
> +             watch = alloc_watch_adapter(path, token);
> +             if (watch == NULL) {
> +                     rc = -ENOMEM;
> +                     goto out;
> +             }
> +
> +             watch->watch.callback = watch_fired;
> +             watch->dev_data = u;
> +
> +             err = register_xenbus_watch(&watch->watch);
> +             if (err) {
> +                     free_watch_adapter(watch);
> +                     rc = err;
> +                     goto out;
> +             }
> +             list_add(&watch->list, &u->watches);
> +     } else {
> +             list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
> +                     if (!strcmp(watch->token, token) &&
> +                         !strcmp(watch->watch.node, path)) {
> +                             unregister_xenbus_watch(&watch->watch);
> +                             list_del(&watch->list);
> +                             free_watch_adapter(watch);
> +                             break;
> +                     }
> +             }
> +     }
> +
> +     /* Success.  Synthesize a reply to say all is OK. */
> +     {
> +             struct {
> +                     struct xsd_sockmsg hdr;
> +                     char body[3];
> +             } __packed reply = {
> +                     {
> +                             .type = msg_type,
> +                             .len = sizeof(reply.body)
> +                     },
> +                     "OK"
> +             };
> +
> +             mutex_lock(&u->reply_mutex);
> +             rc = queue_reply(&u->read_buffers, &reply, sizeof(reply));
> +             wake_up(&u->read_waitq);
> +             mutex_unlock(&u->reply_mutex);
> +     }
> +
> +out:
> +     return rc;
> +}
> +
> +static ssize_t xenbus_file_write(struct file *filp,
> +                             const char __user *ubuf,
> +                             size_t len, loff_t *ppos)
> +{
> +     struct xenbus_file_priv *u = filp->private_data;
> +     uint32_t msg_type;
> +     int rc = len;
> +     int ret;
> +     LIST_HEAD(staging_q);
> +
> +     /*
> +      * We're expecting usermode to be writing properly formed
> +      * xenbus messages.  If they write an incomplete message we
> +      * buffer it up.  Once it is complete, we act on it.
> +      */
> +
> +     /*
> +      * Make sure concurrent writers can't stomp all over each
> +      * other's messages and make a mess of our partial message
> +      * buffer.  We don't make any attemppt to stop multiple
> +      * writers from making a mess of each other's incomplete
> +      * messages; we're just trying to guarantee our own internal
> +      * consistency and make sure that single writes are handled
> +      * atomically.
> +      */
> +     mutex_lock(&u->msgbuffer_mutex);
> +
> +     /* Get this out of the way early to avoid confusion */
> +     if (len == 0)
> +             goto out;
> +
> +     /* Can't write a xenbus message larger we can buffer */
> +     if ((len + u->len) > sizeof(u->u.buffer)) {
> +             /* On error, dump existing buffer */
> +             u->len = 0;
> +             rc = -EINVAL;
> +             goto out;
> +     }
> +
> +     ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
> +
> +     if (ret != 0) {
> +             rc = -EFAULT;
> +             goto out;
> +     }
> +
> +     /* Deal with a partial copy. */
> +     len -= ret;
> +     rc = len;
> +
> +     u->len += len;
> +
> +     /* Return if we haven't got a full message yet */
> +     if (u->len < sizeof(u->u.msg))
> +             goto out;       /* not even the header yet */
> +
> +     /* If we're expecting a message that's larger than we can
> +        possibly send, dump what we have and return an error. */
> +     if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) {
> +             rc = -E2BIG;
> +             u->len = 0;
> +             goto out;
> +     }
> +
> +     if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
> +             goto out;       /* incomplete data portion */
> +
> +     /*
> +      * OK, now we have a complete message.  Do something with it.
> +      */
> +
> +     msg_type = u->u.msg.type;
> +
> +     switch (msg_type) {
> +     case XS_WATCH:
> +     case XS_UNWATCH:
> +             /* (Un)Ask for some path to be watched for changes */
> +             ret = xenbus_write_watch(msg_type, u);
> +             break;
> +
> +     default:
> +             /* Send out a transaction */
> +             ret = xenbus_write_transaction(msg_type, u);
> +             break;
> +     }
> +     if (ret != 0)
> +             rc = ret;
> +
> +     /* Buffered message consumed */
> +     u->len = 0;
> +
> + out:
> +     mutex_unlock(&u->msgbuffer_mutex);
> +     return rc;
> +}
> +
> +static int xenbus_file_open(struct inode *inode, struct file *filp)
> +{
> +     struct xenbus_file_priv *u;
> +
> +     if (xen_store_evtchn == 0)
> +             return -ENOENT;
> +
> +     nonseekable_open(inode, filp);
> +
> +     u = kzalloc(sizeof(*u), GFP_KERNEL);
> +     if (u == NULL)
> +             return -ENOMEM;
> +
> +     INIT_LIST_HEAD(&u->transactions);
> +     INIT_LIST_HEAD(&u->watches);
> +     INIT_LIST_HEAD(&u->read_buffers);
> +     init_waitqueue_head(&u->read_waitq);
> +
> +     mutex_init(&u->reply_mutex);
> +     mutex_init(&u->msgbuffer_mutex);
> +
> +     filp->private_data = u;
> +
> +     return 0;
> +}
> +
> +static int xenbus_file_release(struct inode *inode, struct file *filp)
> +{
> +     struct xenbus_file_priv *u = filp->private_data;
> +     struct xenbus_transaction_holder *trans, *tmp;
> +     struct watch_adapter *watch, *tmp_watch;
> +     struct read_buffer *rb, *tmp_rb;
> +
> +     /*
> +      * No need for locking here because there are no other users,
> +      * by definition.
> +      */
> +
> +     list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
> +             xenbus_transaction_end(trans->handle, 1);
> +             list_del(&trans->list);
> +             kfree(trans);
> +     }
> +
> +     list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
> +             unregister_xenbus_watch(&watch->watch);
> +             list_del(&watch->list);
> +             free_watch_adapter(watch);
> +     }
> +
> +     list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
> +             list_del(&rb->list);
> +             kfree(rb);
> +     }
> +     kfree(u);
> +
> +     return 0;
> +}
> +
> +static unsigned int xenbus_file_poll(struct file *file, poll_table *wait)
> +{
> +     struct xenbus_file_priv *u = file->private_data;
> +
> +     poll_wait(file, &u->read_waitq, wait);
> +     if (!list_empty(&u->read_buffers))
> +             return POLLIN | POLLRDNORM;
> +     return 0;
> +}
> +
> +const struct file_operations xen_xenbus_fops = {
> +     .read = xenbus_file_read,
> +     .write = xenbus_file_write,
> +     .open = xenbus_file_open,
> +     .release = xenbus_file_release,
> +     .poll = xenbus_file_poll,
> +     .llseek = no_llseek,
> +};
> +EXPORT_SYMBOL_GPL(xen_xenbus_fops);
> +
> +static struct miscdevice xenbus_dev = {
> +     .minor = MISC_DYNAMIC_MINOR,
> +     .name = "xen/xenbus",
> +     .fops = &xen_xenbus_fops,
> +};
> +
> +static int __init xenbus_init(void)
> +{
> +     int err;
> +
> +     if (!xen_domain())
> +             return -ENODEV;
> +
> +     err = misc_register(&xenbus_dev);
> +     if (err)
> +             printk(KERN_ERR "Could not register xenbus device\n");
> +     return err;
> +}
> +
> +static void __exit xenbus_exit(void)
> +{
> +     misc_deregister(&xenbus_dev);
> +}
> +
> +module_init(xenbus_init);
> +module_exit(xenbus_exit);
> diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile
> index 5d45ff1..b019865 100644
> --- a/drivers/xen/xenfs/Makefile
> +++ b/drivers/xen/xenfs/Makefile
> @@ -1,4 +1,4 @@
>  obj-$(CONFIG_XENFS) += xenfs.o
>  
> -xenfs-y                        = super.o xenbus.o
> +xenfs-y                        = super.o
>  xenfs-$(CONFIG_XEN_DOM0) += xenstored.o
> diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
> index a55fbf9..a84b53c 100644
> --- a/drivers/xen/xenfs/super.c
> +++ b/drivers/xen/xenfs/super.c
> @@ -17,6 +17,7 @@
>  
>  #include "xenfs.h"
>  #include "../privcmd.h"
> +#include "../xenbus/xenbus_comms.h"
>  
>  #include <asm/xen/hypervisor.h>
>  
> @@ -83,7 +84,7 @@ static int xenfs_fill_super(struct super_block *sb, void 
> *data, int silent)
>  {
>       static struct tree_descr xenfs_files[] = {
>               [1] = {},
> -             { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR },
> +             { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR },
>               { "capabilities", &capabilities_file_ops, S_IRUGO },
>               { "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR },
>               {""},
> diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c
> deleted file mode 100644
> index bbd000f..0000000
> --- a/drivers/xen/xenfs/xenbus.c
> +++ /dev/null
> @@ -1,593 +0,0 @@
> -/*
> - * Driver giving user-space access to the kernel's xenbus connection
> - * to xenstore.
> - *
> - * Copyright (c) 2005, Christian Limpach
> - * Copyright (c) 2005, Rusty Russell, IBM Corporation
> - *
> - * 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 file (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.
> - *
> - * Changes:
> - * 2008-10-07  Alex Zeffertt    Replaced /proc/xen/xenbus with xenfs 
> filesystem
> - *                              and /proc/xen compatibility mount point.
> - *                              Turned xenfs into a loadable module.
> - */
> -
> -#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 <linux/poll.h>
> -#include <linux/mutex.h>
> -#include <linux/sched.h>
> -#include <linux/spinlock.h>
> -#include <linux/mount.h>
> -#include <linux/pagemap.h>
> -#include <linux/uaccess.h>
> -#include <linux/init.h>
> -#include <linux/namei.h>
> -#include <linux/string.h>
> -#include <linux/slab.h>
> -
> -#include "xenfs.h"
> -#include "../xenbus/xenbus_comms.h"
> -
> -#include <xen/xenbus.h>
> -#include <asm/xen/hypervisor.h>
> -
> -/*
> - * An element of a list of outstanding transactions, for which we're
> - * still waiting a reply.
> - */
> -struct xenbus_transaction_holder {
> -     struct list_head list;
> -     struct xenbus_transaction handle;
> -};
> -
> -/*
> - * A buffer of data on the queue.
> - */
> -struct read_buffer {
> -     struct list_head list;
> -     unsigned int cons;
> -     unsigned int len;
> -     char msg[];
> -};
> -
> -struct xenbus_file_priv {
> -     /*
> -      * msgbuffer_mutex is held while partial requests are built up
> -      * and complete requests are acted on.  It therefore protects
> -      * the "transactions" and "watches" lists, and the partial
> -      * request length and buffer.
> -      *
> -      * reply_mutex protects the reply being built up to return to
> -      * usermode.  It nests inside msgbuffer_mutex but may be held
> -      * alone during a watch callback.
> -      */
> -     struct mutex msgbuffer_mutex;
> -
> -     /* In-progress transactions */
> -     struct list_head transactions;
> -
> -     /* Active watches. */
> -     struct list_head watches;
> -
> -     /* Partial request. */
> -     unsigned int len;
> -     union {
> -             struct xsd_sockmsg msg;
> -             char buffer[PAGE_SIZE];
> -     } u;
> -
> -     /* Response queue. */
> -     struct mutex reply_mutex;
> -     struct list_head read_buffers;
> -     wait_queue_head_t read_waitq;
> -
> -};
> -
> -/* Read out any raw xenbus messages queued up. */
> -static ssize_t xenbus_file_read(struct file *filp,
> -                            char __user *ubuf,
> -                            size_t len, loff_t *ppos)
> -{
> -     struct xenbus_file_priv *u = filp->private_data;
> -     struct read_buffer *rb;
> -     unsigned i;
> -     int ret;
> -
> -     mutex_lock(&u->reply_mutex);
> -again:
> -     while (list_empty(&u->read_buffers)) {
> -             mutex_unlock(&u->reply_mutex);
> -             if (filp->f_flags & O_NONBLOCK)
> -                     return -EAGAIN;
> -
> -             ret = wait_event_interruptible(u->read_waitq,
> -                                            !list_empty(&u->read_buffers));
> -             if (ret)
> -                     return ret;
> -             mutex_lock(&u->reply_mutex);
> -     }
> -
> -     rb = list_entry(u->read_buffers.next, struct read_buffer, list);
> -     i = 0;
> -     while (i < len) {
> -             unsigned sz = min((unsigned)len - i, rb->len - rb->cons);
> -
> -             ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz);
> -
> -             i += sz - ret;
> -             rb->cons += sz - ret;
> -
> -             if (ret != 0) {
> -                     if (i == 0)
> -                             i = -EFAULT;
> -                     goto out;
> -             }
> -
> -             /* Clear out buffer if it has been consumed */
> -             if (rb->cons == rb->len) {
> -                     list_del(&rb->list);
> -                     kfree(rb);
> -                     if (list_empty(&u->read_buffers))
> -                             break;
> -                     rb = list_entry(u->read_buffers.next,
> -                                     struct read_buffer, list);
> -             }
> -     }
> -     if (i == 0)
> -             goto again;
> -
> -out:
> -     mutex_unlock(&u->reply_mutex);
> -     return i;
> -}
> -
> -/*
> - * Add a buffer to the queue.  Caller must hold the appropriate lock
> - * if the queue is not local.  (Commonly the caller will build up
> - * multiple queued buffers on a temporary local list, and then add it
> - * to the appropriate list under lock once all the buffers have een
> - * successfully allocated.)
> - */
> -static int queue_reply(struct list_head *queue, const void *data, size_t len)
> -{
> -     struct read_buffer *rb;
> -
> -     if (len == 0)
> -             return 0;
> -
> -     rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
> -     if (rb == NULL)
> -             return -ENOMEM;
> -
> -     rb->cons = 0;
> -     rb->len = len;
> -
> -     memcpy(rb->msg, data, len);
> -
> -     list_add_tail(&rb->list, queue);
> -     return 0;
> -}
> -
> -/*
> - * Free all the read_buffer s on a list.
> - * Caller must have sole reference to list.
> - */
> -static void queue_cleanup(struct list_head *list)
> -{
> -     struct read_buffer *rb;
> -
> -     while (!list_empty(list)) {
> -             rb = list_entry(list->next, struct read_buffer, list);
> -             list_del(list->next);
> -             kfree(rb);
> -     }
> -}
> -
> -struct watch_adapter {
> -     struct list_head list;
> -     struct xenbus_watch watch;
> -     struct xenbus_file_priv *dev_data;
> -     char *token;
> -};
> -
> -static void free_watch_adapter(struct watch_adapter *watch)
> -{
> -     kfree(watch->watch.node);
> -     kfree(watch->token);
> -     kfree(watch);
> -}
> -
> -static struct watch_adapter *alloc_watch_adapter(const char *path,
> -                                              const char *token)
> -{
> -     struct watch_adapter *watch;
> -
> -     watch = kzalloc(sizeof(*watch), GFP_KERNEL);
> -     if (watch == NULL)
> -             goto out_fail;
> -
> -     watch->watch.node = kstrdup(path, GFP_KERNEL);
> -     if (watch->watch.node == NULL)
> -             goto out_free;
> -
> -     watch->token = kstrdup(token, GFP_KERNEL);
> -     if (watch->token == NULL)
> -             goto out_free;
> -
> -     return watch;
> -
> -out_free:
> -     free_watch_adapter(watch);
> -
> -out_fail:
> -     return NULL;
> -}
> -
> -static void watch_fired(struct xenbus_watch *watch,
> -                     const char **vec,
> -                     unsigned int len)
> -{
> -     struct watch_adapter *adap;
> -     struct xsd_sockmsg hdr;
> -     const char *path, *token;
> -     int path_len, tok_len, body_len, data_len = 0;
> -     int ret;
> -     LIST_HEAD(staging_q);
> -
> -     adap = container_of(watch, struct watch_adapter, watch);
> -
> -     path = vec[XS_WATCH_PATH];
> -     token = adap->token;
> -
> -     path_len = strlen(path) + 1;
> -     tok_len = strlen(token) + 1;
> -     if (len > 2)
> -             data_len = vec[len] - vec[2] + 1;
> -     body_len = path_len + tok_len + data_len;
> -
> -     hdr.type = XS_WATCH_EVENT;
> -     hdr.len = body_len;
> -
> -     mutex_lock(&adap->dev_data->reply_mutex);
> -
> -     ret = queue_reply(&staging_q, &hdr, sizeof(hdr));
> -     if (!ret)
> -             ret = queue_reply(&staging_q, path, path_len);
> -     if (!ret)
> -             ret = queue_reply(&staging_q, token, tok_len);
> -     if (!ret && len > 2)
> -             ret = queue_reply(&staging_q, vec[2], data_len);
> -
> -     if (!ret) {
> -             /* success: pass reply list onto watcher */
> -             list_splice_tail(&staging_q, &adap->dev_data->read_buffers);
> -             wake_up(&adap->dev_data->read_waitq);
> -     } else
> -             queue_cleanup(&staging_q);
> -
> -     mutex_unlock(&adap->dev_data->reply_mutex);
> -}
> -
> -static int xenbus_write_transaction(unsigned msg_type,
> -                                 struct xenbus_file_priv *u)
> -{
> -     int rc;
> -     void *reply;
> -     struct xenbus_transaction_holder *trans = NULL;
> -     LIST_HEAD(staging_q);
> -
> -     if (msg_type == XS_TRANSACTION_START) {
> -             trans = kmalloc(sizeof(*trans), GFP_KERNEL);
> -             if (!trans) {
> -                     rc = -ENOMEM;
> -                     goto out;
> -             }
> -     }
> -
> -     reply = xenbus_dev_request_and_reply(&u->u.msg);
> -     if (IS_ERR(reply)) {
> -             kfree(trans);
> -             rc = PTR_ERR(reply);
> -             goto out;
> -     }
> -
> -     if (msg_type == XS_TRANSACTION_START) {
> -             trans->handle.id = simple_strtoul(reply, NULL, 0);
> -
> -             list_add(&trans->list, &u->transactions);
> -     } else if (msg_type == XS_TRANSACTION_END) {
> -             list_for_each_entry(trans, &u->transactions, list)
> -                     if (trans->handle.id == u->u.msg.tx_id)
> -                             break;
> -             BUG_ON(&trans->list == &u->transactions);
> -             list_del(&trans->list);
> -
> -             kfree(trans);
> -     }
> -
> -     mutex_lock(&u->reply_mutex);
> -     rc = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg));
> -     if (!rc)
> -             rc = queue_reply(&staging_q, reply, u->u.msg.len);
> -     if (!rc) {
> -             list_splice_tail(&staging_q, &u->read_buffers);
> -             wake_up(&u->read_waitq);
> -     } else {
> -             queue_cleanup(&staging_q);
> -     }
> -     mutex_unlock(&u->reply_mutex);
> -
> -     kfree(reply);
> -
> -out:
> -     return rc;
> -}
> -
> -static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
> -{
> -     struct watch_adapter *watch, *tmp_watch;
> -     char *path, *token;
> -     int err, rc;
> -     LIST_HEAD(staging_q);
> -
> -     path = u->u.buffer + sizeof(u->u.msg);
> -     token = memchr(path, 0, u->u.msg.len);
> -     if (token == NULL) {
> -             rc = -EILSEQ;
> -             goto out;
> -     }
> -     token++;
> -
> -     if (msg_type == XS_WATCH) {
> -             watch = alloc_watch_adapter(path, token);
> -             if (watch == NULL) {
> -                     rc = -ENOMEM;
> -                     goto out;
> -             }
> -
> -             watch->watch.callback = watch_fired;
> -             watch->dev_data = u;
> -
> -             err = register_xenbus_watch(&watch->watch);
> -             if (err) {
> -                     free_watch_adapter(watch);
> -                     rc = err;
> -                     goto out;
> -             }
> -             list_add(&watch->list, &u->watches);
> -     } else {
> -             list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
> -                     if (!strcmp(watch->token, token) &&
> -                         !strcmp(watch->watch.node, path)) {
> -                             unregister_xenbus_watch(&watch->watch);
> -                             list_del(&watch->list);
> -                             free_watch_adapter(watch);
> -                             break;
> -                     }
> -             }
> -     }
> -
> -     /* Success.  Synthesize a reply to say all is OK. */
> -     {
> -             struct {
> -                     struct xsd_sockmsg hdr;
> -                     char body[3];
> -             } __packed reply = {
> -                     {
> -                             .type = msg_type,
> -                             .len = sizeof(reply.body)
> -                     },
> -                     "OK"
> -             };
> -
> -             mutex_lock(&u->reply_mutex);
> -             rc = queue_reply(&u->read_buffers, &reply, sizeof(reply));
> -             wake_up(&u->read_waitq);
> -             mutex_unlock(&u->reply_mutex);
> -     }
> -
> -out:
> -     return rc;
> -}
> -
> -static ssize_t xenbus_file_write(struct file *filp,
> -                             const char __user *ubuf,
> -                             size_t len, loff_t *ppos)
> -{
> -     struct xenbus_file_priv *u = filp->private_data;
> -     uint32_t msg_type;
> -     int rc = len;
> -     int ret;
> -     LIST_HEAD(staging_q);
> -
> -     /*
> -      * We're expecting usermode to be writing properly formed
> -      * xenbus messages.  If they write an incomplete message we
> -      * buffer it up.  Once it is complete, we act on it.
> -      */
> -
> -     /*
> -      * Make sure concurrent writers can't stomp all over each
> -      * other's messages and make a mess of our partial message
> -      * buffer.  We don't make any attemppt to stop multiple
> -      * writers from making a mess of each other's incomplete
> -      * messages; we're just trying to guarantee our own internal
> -      * consistency and make sure that single writes are handled
> -      * atomically.
> -      */
> -     mutex_lock(&u->msgbuffer_mutex);
> -
> -     /* Get this out of the way early to avoid confusion */
> -     if (len == 0)
> -             goto out;
> -
> -     /* Can't write a xenbus message larger we can buffer */
> -     if ((len + u->len) > sizeof(u->u.buffer)) {
> -             /* On error, dump existing buffer */
> -             u->len = 0;
> -             rc = -EINVAL;
> -             goto out;
> -     }
> -
> -     ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
> -
> -     if (ret != 0) {
> -             rc = -EFAULT;
> -             goto out;
> -     }
> -
> -     /* Deal with a partial copy. */
> -     len -= ret;
> -     rc = len;
> -
> -     u->len += len;
> -
> -     /* Return if we haven't got a full message yet */
> -     if (u->len < sizeof(u->u.msg))
> -             goto out;       /* not even the header yet */
> -
> -     /* If we're expecting a message that's larger than we can
> -        possibly send, dump what we have and return an error. */
> -     if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) {
> -             rc = -E2BIG;
> -             u->len = 0;
> -             goto out;
> -     }
> -
> -     if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
> -             goto out;       /* incomplete data portion */
> -
> -     /*
> -      * OK, now we have a complete message.  Do something with it.
> -      */
> -
> -     msg_type = u->u.msg.type;
> -
> -     switch (msg_type) {
> -     case XS_WATCH:
> -     case XS_UNWATCH:
> -             /* (Un)Ask for some path to be watched for changes */
> -             ret = xenbus_write_watch(msg_type, u);
> -             break;
> -
> -     default:
> -             /* Send out a transaction */
> -             ret = xenbus_write_transaction(msg_type, u);
> -             break;
> -     }
> -     if (ret != 0)
> -             rc = ret;
> -
> -     /* Buffered message consumed */
> -     u->len = 0;
> -
> - out:
> -     mutex_unlock(&u->msgbuffer_mutex);
> -     return rc;
> -}
> -
> -static int xenbus_file_open(struct inode *inode, struct file *filp)
> -{
> -     struct xenbus_file_priv *u;
> -
> -     if (xen_store_evtchn == 0)
> -             return -ENOENT;
> -
> -     nonseekable_open(inode, filp);
> -
> -     u = kzalloc(sizeof(*u), GFP_KERNEL);
> -     if (u == NULL)
> -             return -ENOMEM;
> -
> -     INIT_LIST_HEAD(&u->transactions);
> -     INIT_LIST_HEAD(&u->watches);
> -     INIT_LIST_HEAD(&u->read_buffers);
> -     init_waitqueue_head(&u->read_waitq);
> -
> -     mutex_init(&u->reply_mutex);
> -     mutex_init(&u->msgbuffer_mutex);
> -
> -     filp->private_data = u;
> -
> -     return 0;
> -}
> -
> -static int xenbus_file_release(struct inode *inode, struct file *filp)
> -{
> -     struct xenbus_file_priv *u = filp->private_data;
> -     struct xenbus_transaction_holder *trans, *tmp;
> -     struct watch_adapter *watch, *tmp_watch;
> -     struct read_buffer *rb, *tmp_rb;
> -
> -     /*
> -      * No need for locking here because there are no other users,
> -      * by definition.
> -      */
> -
> -     list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
> -             xenbus_transaction_end(trans->handle, 1);
> -             list_del(&trans->list);
> -             kfree(trans);
> -     }
> -
> -     list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
> -             unregister_xenbus_watch(&watch->watch);
> -             list_del(&watch->list);
> -             free_watch_adapter(watch);
> -     }
> -
> -     list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
> -             list_del(&rb->list);
> -             kfree(rb);
> -     }
> -     kfree(u);
> -
> -     return 0;
> -}
> -
> -static unsigned int xenbus_file_poll(struct file *file, poll_table *wait)
> -{
> -     struct xenbus_file_priv *u = file->private_data;
> -
> -     poll_wait(file, &u->read_waitq, wait);
> -     if (!list_empty(&u->read_buffers))
> -             return POLLIN | POLLRDNORM;
> -     return 0;
> -}
> -
> -const struct file_operations xenbus_file_ops = {
> -     .read = xenbus_file_read,
> -     .write = xenbus_file_write,
> -     .open = xenbus_file_open,
> -     .release = xenbus_file_release,
> -     .poll = xenbus_file_poll,
> -     .llseek = no_llseek,
> -};
> diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h
> index 5056306..6b80c77 100644
> --- a/drivers/xen/xenfs/xenfs.h
> +++ b/drivers/xen/xenfs/xenfs.h
> @@ -1,7 +1,6 @@
>  #ifndef _XENFS_XENBUS_H
>  #define _XENFS_XENBUS_H
>  
> -extern const struct file_operations xenbus_file_ops;
>  extern const struct file_operations xsd_kva_file_ops;
>  extern const struct file_operations xsd_port_file_ops;
>  
> -- 
> 1.7.7.3
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.