162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Driver giving user-space access to the kernel's xenbus connection
362306a36Sopenharmony_ci * to xenstore.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2005, Christian Limpach
662306a36Sopenharmony_ci * Copyright (c) 2005, Rusty Russell, IBM Corporation
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or
962306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2
1062306a36Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed
1162306a36Sopenharmony_ci * separately from the Linux kernel or incorporated into other
1262306a36Sopenharmony_ci * software packages, subject to the following license:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
1562306a36Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without
1662306a36Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify,
1762306a36Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software,
1862306a36Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to
1962306a36Sopenharmony_ci * the following conditions:
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
2262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2762306a36Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2862306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2962306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
3062306a36Sopenharmony_ci * IN THE SOFTWARE.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * Changes:
3362306a36Sopenharmony_ci * 2008-10-07  Alex Zeffertt    Replaced /proc/xen/xenbus with xenfs filesystem
3462306a36Sopenharmony_ci *                              and /proc/xen compatibility mount point.
3562306a36Sopenharmony_ci *                              Turned xenfs into a loadable module.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <linux/kernel.h>
4162306a36Sopenharmony_ci#include <linux/errno.h>
4262306a36Sopenharmony_ci#include <linux/uio.h>
4362306a36Sopenharmony_ci#include <linux/notifier.h>
4462306a36Sopenharmony_ci#include <linux/wait.h>
4562306a36Sopenharmony_ci#include <linux/fs.h>
4662306a36Sopenharmony_ci#include <linux/poll.h>
4762306a36Sopenharmony_ci#include <linux/mutex.h>
4862306a36Sopenharmony_ci#include <linux/sched.h>
4962306a36Sopenharmony_ci#include <linux/spinlock.h>
5062306a36Sopenharmony_ci#include <linux/mount.h>
5162306a36Sopenharmony_ci#include <linux/pagemap.h>
5262306a36Sopenharmony_ci#include <linux/uaccess.h>
5362306a36Sopenharmony_ci#include <linux/init.h>
5462306a36Sopenharmony_ci#include <linux/namei.h>
5562306a36Sopenharmony_ci#include <linux/string.h>
5662306a36Sopenharmony_ci#include <linux/slab.h>
5762306a36Sopenharmony_ci#include <linux/miscdevice.h>
5862306a36Sopenharmony_ci#include <linux/workqueue.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include <xen/xenbus.h>
6162306a36Sopenharmony_ci#include <xen/xen.h>
6262306a36Sopenharmony_ci#include <asm/xen/hypervisor.h>
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#include "xenbus.h"
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciunsigned int xb_dev_generation_id;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * An element of a list of outstanding transactions, for which we're
7062306a36Sopenharmony_ci * still waiting a reply.
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_cistruct xenbus_transaction_holder {
7362306a36Sopenharmony_ci	struct list_head list;
7462306a36Sopenharmony_ci	struct xenbus_transaction handle;
7562306a36Sopenharmony_ci	unsigned int generation_id;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/*
7962306a36Sopenharmony_ci * A buffer of data on the queue.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistruct read_buffer {
8262306a36Sopenharmony_ci	struct list_head list;
8362306a36Sopenharmony_ci	unsigned int cons;
8462306a36Sopenharmony_ci	unsigned int len;
8562306a36Sopenharmony_ci	char msg[];
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistruct xenbus_file_priv {
8962306a36Sopenharmony_ci	/*
9062306a36Sopenharmony_ci	 * msgbuffer_mutex is held while partial requests are built up
9162306a36Sopenharmony_ci	 * and complete requests are acted on.  It therefore protects
9262306a36Sopenharmony_ci	 * the "transactions" and "watches" lists, and the partial
9362306a36Sopenharmony_ci	 * request length and buffer.
9462306a36Sopenharmony_ci	 *
9562306a36Sopenharmony_ci	 * reply_mutex protects the reply being built up to return to
9662306a36Sopenharmony_ci	 * usermode.  It nests inside msgbuffer_mutex but may be held
9762306a36Sopenharmony_ci	 * alone during a watch callback.
9862306a36Sopenharmony_ci	 */
9962306a36Sopenharmony_ci	struct mutex msgbuffer_mutex;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* In-progress transactions */
10262306a36Sopenharmony_ci	struct list_head transactions;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Active watches. */
10562306a36Sopenharmony_ci	struct list_head watches;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Partial request. */
10862306a36Sopenharmony_ci	unsigned int len;
10962306a36Sopenharmony_ci	union {
11062306a36Sopenharmony_ci		struct xsd_sockmsg msg;
11162306a36Sopenharmony_ci		char buffer[XENSTORE_PAYLOAD_MAX];
11262306a36Sopenharmony_ci	} u;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Response queue. */
11562306a36Sopenharmony_ci	struct mutex reply_mutex;
11662306a36Sopenharmony_ci	struct list_head read_buffers;
11762306a36Sopenharmony_ci	wait_queue_head_t read_waitq;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	struct kref kref;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	struct work_struct wq;
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* Read out any raw xenbus messages queued up. */
12562306a36Sopenharmony_cistatic ssize_t xenbus_file_read(struct file *filp,
12662306a36Sopenharmony_ci			       char __user *ubuf,
12762306a36Sopenharmony_ci			       size_t len, loff_t *ppos)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct xenbus_file_priv *u = filp->private_data;
13062306a36Sopenharmony_ci	struct read_buffer *rb;
13162306a36Sopenharmony_ci	ssize_t i;
13262306a36Sopenharmony_ci	int ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mutex_lock(&u->reply_mutex);
13562306a36Sopenharmony_ciagain:
13662306a36Sopenharmony_ci	while (list_empty(&u->read_buffers)) {
13762306a36Sopenharmony_ci		mutex_unlock(&u->reply_mutex);
13862306a36Sopenharmony_ci		if (filp->f_flags & O_NONBLOCK)
13962306a36Sopenharmony_ci			return -EAGAIN;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		ret = wait_event_interruptible(u->read_waitq,
14262306a36Sopenharmony_ci					       !list_empty(&u->read_buffers));
14362306a36Sopenharmony_ci		if (ret)
14462306a36Sopenharmony_ci			return ret;
14562306a36Sopenharmony_ci		mutex_lock(&u->reply_mutex);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	rb = list_entry(u->read_buffers.next, struct read_buffer, list);
14962306a36Sopenharmony_ci	i = 0;
15062306a36Sopenharmony_ci	while (i < len) {
15162306a36Sopenharmony_ci		size_t sz = min_t(size_t, len - i, rb->len - rb->cons);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		i += sz - ret;
15662306a36Sopenharmony_ci		rb->cons += sz - ret;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		if (ret != 0) {
15962306a36Sopenharmony_ci			if (i == 0)
16062306a36Sopenharmony_ci				i = -EFAULT;
16162306a36Sopenharmony_ci			goto out;
16262306a36Sopenharmony_ci		}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		/* Clear out buffer if it has been consumed */
16562306a36Sopenharmony_ci		if (rb->cons == rb->len) {
16662306a36Sopenharmony_ci			list_del(&rb->list);
16762306a36Sopenharmony_ci			kfree(rb);
16862306a36Sopenharmony_ci			if (list_empty(&u->read_buffers))
16962306a36Sopenharmony_ci				break;
17062306a36Sopenharmony_ci			rb = list_entry(u->read_buffers.next,
17162306a36Sopenharmony_ci					struct read_buffer, list);
17262306a36Sopenharmony_ci		}
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	if (i == 0)
17562306a36Sopenharmony_ci		goto again;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciout:
17862306a36Sopenharmony_ci	mutex_unlock(&u->reply_mutex);
17962306a36Sopenharmony_ci	return i;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/*
18362306a36Sopenharmony_ci * Add a buffer to the queue.  Caller must hold the appropriate lock
18462306a36Sopenharmony_ci * if the queue is not local.  (Commonly the caller will build up
18562306a36Sopenharmony_ci * multiple queued buffers on a temporary local list, and then add it
18662306a36Sopenharmony_ci * to the appropriate list under lock once all the buffers have een
18762306a36Sopenharmony_ci * successfully allocated.)
18862306a36Sopenharmony_ci */
18962306a36Sopenharmony_cistatic int queue_reply(struct list_head *queue, const void *data, size_t len)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct read_buffer *rb;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (len == 0)
19462306a36Sopenharmony_ci		return 0;
19562306a36Sopenharmony_ci	if (len > XENSTORE_PAYLOAD_MAX)
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
19962306a36Sopenharmony_ci	if (rb == NULL)
20062306a36Sopenharmony_ci		return -ENOMEM;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	rb->cons = 0;
20362306a36Sopenharmony_ci	rb->len = len;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	memcpy(rb->msg, data, len);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	list_add_tail(&rb->list, queue);
20862306a36Sopenharmony_ci	return 0;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/*
21262306a36Sopenharmony_ci * Free all the read_buffer s on a list.
21362306a36Sopenharmony_ci * Caller must have sole reference to list.
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_cistatic void queue_cleanup(struct list_head *list)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct read_buffer *rb;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	while (!list_empty(list)) {
22062306a36Sopenharmony_ci		rb = list_entry(list->next, struct read_buffer, list);
22162306a36Sopenharmony_ci		list_del(list->next);
22262306a36Sopenharmony_ci		kfree(rb);
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistruct watch_adapter {
22762306a36Sopenharmony_ci	struct list_head list;
22862306a36Sopenharmony_ci	struct xenbus_watch watch;
22962306a36Sopenharmony_ci	struct xenbus_file_priv *dev_data;
23062306a36Sopenharmony_ci	char *token;
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic void free_watch_adapter(struct watch_adapter *watch)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	kfree(watch->watch.node);
23662306a36Sopenharmony_ci	kfree(watch->token);
23762306a36Sopenharmony_ci	kfree(watch);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic struct watch_adapter *alloc_watch_adapter(const char *path,
24162306a36Sopenharmony_ci						 const char *token)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct watch_adapter *watch;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	watch = kzalloc(sizeof(*watch), GFP_KERNEL);
24662306a36Sopenharmony_ci	if (watch == NULL)
24762306a36Sopenharmony_ci		goto out_fail;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	watch->watch.node = kstrdup(path, GFP_KERNEL);
25062306a36Sopenharmony_ci	if (watch->watch.node == NULL)
25162306a36Sopenharmony_ci		goto out_free;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	watch->token = kstrdup(token, GFP_KERNEL);
25462306a36Sopenharmony_ci	if (watch->token == NULL)
25562306a36Sopenharmony_ci		goto out_free;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return watch;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ciout_free:
26062306a36Sopenharmony_ci	free_watch_adapter(watch);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciout_fail:
26362306a36Sopenharmony_ci	return NULL;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic void watch_fired(struct xenbus_watch *watch,
26762306a36Sopenharmony_ci			const char *path,
26862306a36Sopenharmony_ci			const char *token)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct watch_adapter *adap;
27162306a36Sopenharmony_ci	struct xsd_sockmsg hdr;
27262306a36Sopenharmony_ci	const char *token_caller;
27362306a36Sopenharmony_ci	int path_len, tok_len, body_len;
27462306a36Sopenharmony_ci	int ret;
27562306a36Sopenharmony_ci	LIST_HEAD(staging_q);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	adap = container_of(watch, struct watch_adapter, watch);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	token_caller = adap->token;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	path_len = strlen(path) + 1;
28262306a36Sopenharmony_ci	tok_len = strlen(token_caller) + 1;
28362306a36Sopenharmony_ci	body_len = path_len + tok_len;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	hdr.type = XS_WATCH_EVENT;
28662306a36Sopenharmony_ci	hdr.len = body_len;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	mutex_lock(&adap->dev_data->reply_mutex);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	ret = queue_reply(&staging_q, &hdr, sizeof(hdr));
29162306a36Sopenharmony_ci	if (!ret)
29262306a36Sopenharmony_ci		ret = queue_reply(&staging_q, path, path_len);
29362306a36Sopenharmony_ci	if (!ret)
29462306a36Sopenharmony_ci		ret = queue_reply(&staging_q, token_caller, tok_len);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (!ret) {
29762306a36Sopenharmony_ci		/* success: pass reply list onto watcher */
29862306a36Sopenharmony_ci		list_splice_tail(&staging_q, &adap->dev_data->read_buffers);
29962306a36Sopenharmony_ci		wake_up(&adap->dev_data->read_waitq);
30062306a36Sopenharmony_ci	} else
30162306a36Sopenharmony_ci		queue_cleanup(&staging_q);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	mutex_unlock(&adap->dev_data->reply_mutex);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void xenbus_worker(struct work_struct *wq)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct xenbus_file_priv *u;
30962306a36Sopenharmony_ci	struct xenbus_transaction_holder *trans, *tmp;
31062306a36Sopenharmony_ci	struct watch_adapter *watch, *tmp_watch;
31162306a36Sopenharmony_ci	struct read_buffer *rb, *tmp_rb;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	u = container_of(wq, struct xenbus_file_priv, wq);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/*
31662306a36Sopenharmony_ci	 * No need for locking here because there are no other users,
31762306a36Sopenharmony_ci	 * by definition.
31862306a36Sopenharmony_ci	 */
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
32162306a36Sopenharmony_ci		xenbus_transaction_end(trans->handle, 1);
32262306a36Sopenharmony_ci		list_del(&trans->list);
32362306a36Sopenharmony_ci		kfree(trans);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
32762306a36Sopenharmony_ci		unregister_xenbus_watch(&watch->watch);
32862306a36Sopenharmony_ci		list_del(&watch->list);
32962306a36Sopenharmony_ci		free_watch_adapter(watch);
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
33362306a36Sopenharmony_ci		list_del(&rb->list);
33462306a36Sopenharmony_ci		kfree(rb);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci	kfree(u);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void xenbus_file_free(struct kref *kref)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct xenbus_file_priv *u;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/*
34462306a36Sopenharmony_ci	 * We might be called in xenbus_thread().
34562306a36Sopenharmony_ci	 * Use workqueue to avoid deadlock.
34662306a36Sopenharmony_ci	 */
34762306a36Sopenharmony_ci	u = container_of(kref, struct xenbus_file_priv, kref);
34862306a36Sopenharmony_ci	schedule_work(&u->wq);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic struct xenbus_transaction_holder *xenbus_get_transaction(
35262306a36Sopenharmony_ci	struct xenbus_file_priv *u, uint32_t tx_id)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct xenbus_transaction_holder *trans;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	list_for_each_entry(trans, &u->transactions, list)
35762306a36Sopenharmony_ci		if (trans->handle.id == tx_id)
35862306a36Sopenharmony_ci			return trans;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return NULL;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_civoid xenbus_dev_queue_reply(struct xb_req_data *req)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct xenbus_file_priv *u = req->par;
36662306a36Sopenharmony_ci	struct xenbus_transaction_holder *trans = NULL;
36762306a36Sopenharmony_ci	int rc;
36862306a36Sopenharmony_ci	LIST_HEAD(staging_q);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	xs_request_exit(req);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	mutex_lock(&u->msgbuffer_mutex);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (req->type == XS_TRANSACTION_START) {
37562306a36Sopenharmony_ci		trans = xenbus_get_transaction(u, 0);
37662306a36Sopenharmony_ci		if (WARN_ON(!trans))
37762306a36Sopenharmony_ci			goto out;
37862306a36Sopenharmony_ci		if (req->msg.type == XS_ERROR) {
37962306a36Sopenharmony_ci			list_del(&trans->list);
38062306a36Sopenharmony_ci			kfree(trans);
38162306a36Sopenharmony_ci		} else {
38262306a36Sopenharmony_ci			rc = kstrtou32(req->body, 10, &trans->handle.id);
38362306a36Sopenharmony_ci			if (WARN_ON(rc))
38462306a36Sopenharmony_ci				goto out;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	} else if (req->type == XS_TRANSACTION_END) {
38762306a36Sopenharmony_ci		trans = xenbus_get_transaction(u, req->msg.tx_id);
38862306a36Sopenharmony_ci		if (WARN_ON(!trans))
38962306a36Sopenharmony_ci			goto out;
39062306a36Sopenharmony_ci		list_del(&trans->list);
39162306a36Sopenharmony_ci		kfree(trans);
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	mutex_unlock(&u->msgbuffer_mutex);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	mutex_lock(&u->reply_mutex);
39762306a36Sopenharmony_ci	rc = queue_reply(&staging_q, &req->msg, sizeof(req->msg));
39862306a36Sopenharmony_ci	if (!rc)
39962306a36Sopenharmony_ci		rc = queue_reply(&staging_q, req->body, req->msg.len);
40062306a36Sopenharmony_ci	if (!rc) {
40162306a36Sopenharmony_ci		list_splice_tail(&staging_q, &u->read_buffers);
40262306a36Sopenharmony_ci		wake_up(&u->read_waitq);
40362306a36Sopenharmony_ci	} else {
40462306a36Sopenharmony_ci		queue_cleanup(&staging_q);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	mutex_unlock(&u->reply_mutex);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	kfree(req->body);
40962306a36Sopenharmony_ci	kfree(req);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	kref_put(&u->kref, xenbus_file_free);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci out:
41662306a36Sopenharmony_ci	mutex_unlock(&u->msgbuffer_mutex);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic int xenbus_command_reply(struct xenbus_file_priv *u,
42062306a36Sopenharmony_ci				unsigned int msg_type, const char *reply)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct {
42362306a36Sopenharmony_ci		struct xsd_sockmsg hdr;
42462306a36Sopenharmony_ci		char body[16];
42562306a36Sopenharmony_ci	} msg;
42662306a36Sopenharmony_ci	int rc;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	msg.hdr = u->u.msg;
42962306a36Sopenharmony_ci	msg.hdr.type = msg_type;
43062306a36Sopenharmony_ci	msg.hdr.len = strlen(reply) + 1;
43162306a36Sopenharmony_ci	if (msg.hdr.len > sizeof(msg.body))
43262306a36Sopenharmony_ci		return -E2BIG;
43362306a36Sopenharmony_ci	memcpy(&msg.body, reply, msg.hdr.len);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	mutex_lock(&u->reply_mutex);
43662306a36Sopenharmony_ci	rc = queue_reply(&u->read_buffers, &msg, sizeof(msg.hdr) + msg.hdr.len);
43762306a36Sopenharmony_ci	wake_up(&u->read_waitq);
43862306a36Sopenharmony_ci	mutex_unlock(&u->reply_mutex);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (!rc)
44162306a36Sopenharmony_ci		kref_put(&u->kref, xenbus_file_free);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return rc;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic int xenbus_write_transaction(unsigned msg_type,
44762306a36Sopenharmony_ci				    struct xenbus_file_priv *u)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	int rc;
45062306a36Sopenharmony_ci	struct xenbus_transaction_holder *trans = NULL;
45162306a36Sopenharmony_ci	struct {
45262306a36Sopenharmony_ci		struct xsd_sockmsg hdr;
45362306a36Sopenharmony_ci		char body[];
45462306a36Sopenharmony_ci	} *msg = (void *)u->u.buffer;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (msg_type == XS_TRANSACTION_START) {
45762306a36Sopenharmony_ci		trans = kzalloc(sizeof(*trans), GFP_KERNEL);
45862306a36Sopenharmony_ci		if (!trans) {
45962306a36Sopenharmony_ci			rc = -ENOMEM;
46062306a36Sopenharmony_ci			goto out;
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci		trans->generation_id = xb_dev_generation_id;
46362306a36Sopenharmony_ci		list_add(&trans->list, &u->transactions);
46462306a36Sopenharmony_ci	} else if (msg->hdr.tx_id != 0 &&
46562306a36Sopenharmony_ci		   !xenbus_get_transaction(u, msg->hdr.tx_id))
46662306a36Sopenharmony_ci		return xenbus_command_reply(u, XS_ERROR, "ENOENT");
46762306a36Sopenharmony_ci	else if (msg_type == XS_TRANSACTION_END &&
46862306a36Sopenharmony_ci		 !(msg->hdr.len == 2 &&
46962306a36Sopenharmony_ci		   (!strcmp(msg->body, "T") || !strcmp(msg->body, "F"))))
47062306a36Sopenharmony_ci		return xenbus_command_reply(u, XS_ERROR, "EINVAL");
47162306a36Sopenharmony_ci	else if (msg_type == XS_TRANSACTION_END) {
47262306a36Sopenharmony_ci		trans = xenbus_get_transaction(u, msg->hdr.tx_id);
47362306a36Sopenharmony_ci		if (trans && trans->generation_id != xb_dev_generation_id) {
47462306a36Sopenharmony_ci			list_del(&trans->list);
47562306a36Sopenharmony_ci			kfree(trans);
47662306a36Sopenharmony_ci			if (!strcmp(msg->body, "T"))
47762306a36Sopenharmony_ci				return xenbus_command_reply(u, XS_ERROR,
47862306a36Sopenharmony_ci							    "EAGAIN");
47962306a36Sopenharmony_ci			else
48062306a36Sopenharmony_ci				return xenbus_command_reply(u,
48162306a36Sopenharmony_ci							    XS_TRANSACTION_END,
48262306a36Sopenharmony_ci							    "OK");
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	rc = xenbus_dev_request_and_reply(&msg->hdr, u);
48762306a36Sopenharmony_ci	if (rc && trans) {
48862306a36Sopenharmony_ci		list_del(&trans->list);
48962306a36Sopenharmony_ci		kfree(trans);
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ciout:
49362306a36Sopenharmony_ci	return rc;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct watch_adapter *watch;
49962306a36Sopenharmony_ci	char *path, *token;
50062306a36Sopenharmony_ci	int err, rc;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	path = u->u.buffer + sizeof(u->u.msg);
50362306a36Sopenharmony_ci	token = memchr(path, 0, u->u.msg.len);
50462306a36Sopenharmony_ci	if (token == NULL) {
50562306a36Sopenharmony_ci		rc = xenbus_command_reply(u, XS_ERROR, "EINVAL");
50662306a36Sopenharmony_ci		goto out;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci	token++;
50962306a36Sopenharmony_ci	if (memchr(token, 0, u->u.msg.len - (token - path)) == NULL) {
51062306a36Sopenharmony_ci		rc = xenbus_command_reply(u, XS_ERROR, "EINVAL");
51162306a36Sopenharmony_ci		goto out;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (msg_type == XS_WATCH) {
51562306a36Sopenharmony_ci		watch = alloc_watch_adapter(path, token);
51662306a36Sopenharmony_ci		if (watch == NULL) {
51762306a36Sopenharmony_ci			rc = -ENOMEM;
51862306a36Sopenharmony_ci			goto out;
51962306a36Sopenharmony_ci		}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		watch->watch.callback = watch_fired;
52262306a36Sopenharmony_ci		watch->dev_data = u;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		err = register_xenbus_watch(&watch->watch);
52562306a36Sopenharmony_ci		if (err) {
52662306a36Sopenharmony_ci			free_watch_adapter(watch);
52762306a36Sopenharmony_ci			rc = err;
52862306a36Sopenharmony_ci			goto out;
52962306a36Sopenharmony_ci		}
53062306a36Sopenharmony_ci		list_add(&watch->list, &u->watches);
53162306a36Sopenharmony_ci	} else {
53262306a36Sopenharmony_ci		list_for_each_entry(watch, &u->watches, list) {
53362306a36Sopenharmony_ci			if (!strcmp(watch->token, token) &&
53462306a36Sopenharmony_ci			    !strcmp(watch->watch.node, path)) {
53562306a36Sopenharmony_ci				unregister_xenbus_watch(&watch->watch);
53662306a36Sopenharmony_ci				list_del(&watch->list);
53762306a36Sopenharmony_ci				free_watch_adapter(watch);
53862306a36Sopenharmony_ci				break;
53962306a36Sopenharmony_ci			}
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* Success.  Synthesize a reply to say all is OK. */
54462306a36Sopenharmony_ci	rc = xenbus_command_reply(u, msg_type, "OK");
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ciout:
54762306a36Sopenharmony_ci	return rc;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic ssize_t xenbus_file_write(struct file *filp,
55162306a36Sopenharmony_ci				const char __user *ubuf,
55262306a36Sopenharmony_ci				size_t len, loff_t *ppos)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	struct xenbus_file_priv *u = filp->private_data;
55562306a36Sopenharmony_ci	uint32_t msg_type;
55662306a36Sopenharmony_ci	int rc = len;
55762306a36Sopenharmony_ci	int ret;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/*
56062306a36Sopenharmony_ci	 * We're expecting usermode to be writing properly formed
56162306a36Sopenharmony_ci	 * xenbus messages.  If they write an incomplete message we
56262306a36Sopenharmony_ci	 * buffer it up.  Once it is complete, we act on it.
56362306a36Sopenharmony_ci	 */
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/*
56662306a36Sopenharmony_ci	 * Make sure concurrent writers can't stomp all over each
56762306a36Sopenharmony_ci	 * other's messages and make a mess of our partial message
56862306a36Sopenharmony_ci	 * buffer.  We don't make any attemppt to stop multiple
56962306a36Sopenharmony_ci	 * writers from making a mess of each other's incomplete
57062306a36Sopenharmony_ci	 * messages; we're just trying to guarantee our own internal
57162306a36Sopenharmony_ci	 * consistency and make sure that single writes are handled
57262306a36Sopenharmony_ci	 * atomically.
57362306a36Sopenharmony_ci	 */
57462306a36Sopenharmony_ci	mutex_lock(&u->msgbuffer_mutex);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* Get this out of the way early to avoid confusion */
57762306a36Sopenharmony_ci	if (len == 0)
57862306a36Sopenharmony_ci		goto out;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* Can't write a xenbus message larger we can buffer */
58162306a36Sopenharmony_ci	if (len > sizeof(u->u.buffer) - u->len) {
58262306a36Sopenharmony_ci		/* On error, dump existing buffer */
58362306a36Sopenharmony_ci		u->len = 0;
58462306a36Sopenharmony_ci		rc = -EINVAL;
58562306a36Sopenharmony_ci		goto out;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (ret != 0) {
59162306a36Sopenharmony_ci		rc = -EFAULT;
59262306a36Sopenharmony_ci		goto out;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* Deal with a partial copy. */
59662306a36Sopenharmony_ci	len -= ret;
59762306a36Sopenharmony_ci	rc = len;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	u->len += len;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Return if we haven't got a full message yet */
60262306a36Sopenharmony_ci	if (u->len < sizeof(u->u.msg))
60362306a36Sopenharmony_ci		goto out;	/* not even the header yet */
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* If we're expecting a message that's larger than we can
60662306a36Sopenharmony_ci	   possibly send, dump what we have and return an error. */
60762306a36Sopenharmony_ci	if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) {
60862306a36Sopenharmony_ci		rc = -E2BIG;
60962306a36Sopenharmony_ci		u->len = 0;
61062306a36Sopenharmony_ci		goto out;
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
61462306a36Sopenharmony_ci		goto out;	/* incomplete data portion */
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/*
61762306a36Sopenharmony_ci	 * OK, now we have a complete message.  Do something with it.
61862306a36Sopenharmony_ci	 */
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	kref_get(&u->kref);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	msg_type = u->u.msg.type;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	switch (msg_type) {
62562306a36Sopenharmony_ci	case XS_WATCH:
62662306a36Sopenharmony_ci	case XS_UNWATCH:
62762306a36Sopenharmony_ci		/* (Un)Ask for some path to be watched for changes */
62862306a36Sopenharmony_ci		ret = xenbus_write_watch(msg_type, u);
62962306a36Sopenharmony_ci		break;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	default:
63262306a36Sopenharmony_ci		/* Send out a transaction */
63362306a36Sopenharmony_ci		ret = xenbus_write_transaction(msg_type, u);
63462306a36Sopenharmony_ci		break;
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci	if (ret != 0) {
63762306a36Sopenharmony_ci		rc = ret;
63862306a36Sopenharmony_ci		kref_put(&u->kref, xenbus_file_free);
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/* Buffered message consumed */
64262306a36Sopenharmony_ci	u->len = 0;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci out:
64562306a36Sopenharmony_ci	mutex_unlock(&u->msgbuffer_mutex);
64662306a36Sopenharmony_ci	return rc;
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic int xenbus_file_open(struct inode *inode, struct file *filp)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct xenbus_file_priv *u;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (xen_store_evtchn == 0)
65462306a36Sopenharmony_ci		return -ENOENT;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	stream_open(inode, filp);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	u = kzalloc(sizeof(*u), GFP_KERNEL);
65962306a36Sopenharmony_ci	if (u == NULL)
66062306a36Sopenharmony_ci		return -ENOMEM;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	kref_init(&u->kref);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	INIT_LIST_HEAD(&u->transactions);
66562306a36Sopenharmony_ci	INIT_LIST_HEAD(&u->watches);
66662306a36Sopenharmony_ci	INIT_LIST_HEAD(&u->read_buffers);
66762306a36Sopenharmony_ci	init_waitqueue_head(&u->read_waitq);
66862306a36Sopenharmony_ci	INIT_WORK(&u->wq, xenbus_worker);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	mutex_init(&u->reply_mutex);
67162306a36Sopenharmony_ci	mutex_init(&u->msgbuffer_mutex);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	filp->private_data = u;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return 0;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int xenbus_file_release(struct inode *inode, struct file *filp)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct xenbus_file_priv *u = filp->private_data;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	kref_put(&u->kref, xenbus_file_free);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic __poll_t xenbus_file_poll(struct file *file, poll_table *wait)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct xenbus_file_priv *u = file->private_data;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	poll_wait(file, &u->read_waitq, wait);
69262306a36Sopenharmony_ci	if (!list_empty(&u->read_buffers))
69362306a36Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
69462306a36Sopenharmony_ci	return 0;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ciconst struct file_operations xen_xenbus_fops = {
69862306a36Sopenharmony_ci	.read = xenbus_file_read,
69962306a36Sopenharmony_ci	.write = xenbus_file_write,
70062306a36Sopenharmony_ci	.open = xenbus_file_open,
70162306a36Sopenharmony_ci	.release = xenbus_file_release,
70262306a36Sopenharmony_ci	.poll = xenbus_file_poll,
70362306a36Sopenharmony_ci	.llseek = no_llseek,
70462306a36Sopenharmony_ci};
70562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xen_xenbus_fops);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic struct miscdevice xenbus_dev = {
70862306a36Sopenharmony_ci	.minor = MISC_DYNAMIC_MINOR,
70962306a36Sopenharmony_ci	.name = "xen/xenbus",
71062306a36Sopenharmony_ci	.fops = &xen_xenbus_fops,
71162306a36Sopenharmony_ci};
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic int __init xenbus_init(void)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	int err;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	if (!xen_domain())
71862306a36Sopenharmony_ci		return -ENODEV;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	err = misc_register(&xenbus_dev);
72162306a36Sopenharmony_ci	if (err)
72262306a36Sopenharmony_ci		pr_err("Could not register xenbus frontend device\n");
72362306a36Sopenharmony_ci	return err;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_cidevice_initcall(xenbus_init);
726