diff options
Diffstat (limited to 'drivers/xen/xenfs/xenbus.c')
| -rw-r--r-- | drivers/xen/xenfs/xenbus.c | 598 | 
1 files changed, 0 insertions, 598 deletions
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c deleted file mode 100644 index 1c1236087f7..00000000000 --- a/drivers/xen/xenfs/xenbus.c +++ /dev/null @@ -1,598 +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); -	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 != sz) { -			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); -		} -	} - -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)); -		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 == len) { -		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_TRANSACTION_START: -	case XS_TRANSACTION_END: -	case XS_DIRECTORY: -	case XS_READ: -	case XS_GET_PERMS: -	case XS_RELEASE: -	case XS_GET_DOMAIN_PATH: -	case XS_WRITE: -	case XS_MKDIR: -	case XS_RM: -	case XS_SET_PERMS: -		/* Send out a transaction */ -		ret = xenbus_write_transaction(msg_type, u); -		break; - -	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: -		ret = -EINVAL; -		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; - -	/* -	 * 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); -	} - -	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, -};  | 
