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