485 lines · c
1/******************************************************************************2 * xenbus_comms.c3 *4 * Low level code to talks to Xen Store: ringbuffer and event channel.5 *6 * Copyright (C) 2005 Rusty Russell, IBM Corporation7 *8 * This program is free software; you can redistribute it and/or9 * modify it under the terms of the GNU General Public License version 210 * as published by the Free Software Foundation; or, when distributed11 * separately from the Linux kernel or incorporated into other12 * software packages, subject to the following license:13 *14 * Permission is hereby granted, free of charge, to any person obtaining a copy15 * of this source file (the "Software"), to deal in the Software without16 * restriction, including without limitation the rights to use, copy, modify,17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,18 * and to permit persons to whom the Software is furnished to do so, subject to19 * the following conditions:20 *21 * The above copyright notice and this permission notice shall be included in22 * all copies or substantial portions of the Software.23 *24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS30 * IN THE SOFTWARE.31 */32 33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt34 35#include <linux/wait.h>36#include <linux/interrupt.h>37#include <linux/kthread.h>38#include <linux/sched.h>39#include <linux/err.h>40#include <xen/xenbus.h>41#include <asm/xen/hypervisor.h>42#include <xen/events.h>43#include <xen/page.h>44#include "xenbus.h"45 46/* A list of replies. Currently only one will ever be outstanding. */47LIST_HEAD(xs_reply_list);48 49/* A list of write requests. */50LIST_HEAD(xb_write_list);51DECLARE_WAIT_QUEUE_HEAD(xb_waitq);52DEFINE_MUTEX(xb_write_mutex);53 54/* Protect xenbus reader thread against save/restore. */55DEFINE_MUTEX(xs_response_mutex);56 57static int xenbus_irq;58static struct task_struct *xenbus_task;59 60static irqreturn_t wake_waiting(int irq, void *unused)61{62 wake_up(&xb_waitq);63 return IRQ_HANDLED;64}65 66static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)67{68 return ((prod - cons) <= XENSTORE_RING_SIZE);69}70 71static void *get_output_chunk(XENSTORE_RING_IDX cons,72 XENSTORE_RING_IDX prod,73 char *buf, uint32_t *len)74{75 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);76 if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)77 *len = XENSTORE_RING_SIZE - (prod - cons);78 return buf + MASK_XENSTORE_IDX(prod);79}80 81static const void *get_input_chunk(XENSTORE_RING_IDX cons,82 XENSTORE_RING_IDX prod,83 const char *buf, uint32_t *len)84{85 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);86 if ((prod - cons) < *len)87 *len = prod - cons;88 return buf + MASK_XENSTORE_IDX(cons);89}90 91static int xb_data_to_write(void)92{93 struct xenstore_domain_interface *intf = xen_store_interface;94 95 return (intf->req_prod - intf->req_cons) != XENSTORE_RING_SIZE &&96 !list_empty(&xb_write_list);97}98 99/**100 * xb_write - low level write101 * @data: buffer to send102 * @len: length of buffer103 *104 * Returns number of bytes written or -err.105 */106static int xb_write(const void *data, unsigned int len)107{108 struct xenstore_domain_interface *intf = xen_store_interface;109 XENSTORE_RING_IDX cons, prod;110 unsigned int bytes = 0;111 112 while (len != 0) {113 void *dst;114 unsigned int avail;115 116 /* Read indexes, then verify. */117 cons = intf->req_cons;118 prod = intf->req_prod;119 if (!check_indexes(cons, prod)) {120 intf->req_cons = intf->req_prod = 0;121 return -EIO;122 }123 if (!xb_data_to_write())124 return bytes;125 126 /* Must write data /after/ reading the consumer index. */127 virt_mb();128 129 dst = get_output_chunk(cons, prod, intf->req, &avail);130 if (avail == 0)131 continue;132 if (avail > len)133 avail = len;134 135 memcpy(dst, data, avail);136 data += avail;137 len -= avail;138 bytes += avail;139 140 /* Other side must not see new producer until data is there. */141 virt_wmb();142 intf->req_prod += avail;143 144 /* Implies mb(): other side will see the updated producer. */145 if (prod <= intf->req_cons)146 notify_remote_via_evtchn(xen_store_evtchn);147 }148 149 return bytes;150}151 152static int xb_data_to_read(void)153{154 struct xenstore_domain_interface *intf = xen_store_interface;155 return (intf->rsp_cons != intf->rsp_prod);156}157 158static int xb_read(void *data, unsigned int len)159{160 struct xenstore_domain_interface *intf = xen_store_interface;161 XENSTORE_RING_IDX cons, prod;162 unsigned int bytes = 0;163 164 while (len != 0) {165 unsigned int avail;166 const char *src;167 168 /* Read indexes, then verify. */169 cons = intf->rsp_cons;170 prod = intf->rsp_prod;171 if (cons == prod)172 return bytes;173 174 if (!check_indexes(cons, prod)) {175 intf->rsp_cons = intf->rsp_prod = 0;176 return -EIO;177 }178 179 src = get_input_chunk(cons, prod, intf->rsp, &avail);180 if (avail == 0)181 continue;182 if (avail > len)183 avail = len;184 185 /* Must read data /after/ reading the producer index. */186 virt_rmb();187 188 memcpy(data, src, avail);189 data += avail;190 len -= avail;191 bytes += avail;192 193 /* Other side must not see free space until we've copied out */194 virt_mb();195 intf->rsp_cons += avail;196 197 /* Implies mb(): other side will see the updated consumer. */198 if (intf->rsp_prod - cons >= XENSTORE_RING_SIZE)199 notify_remote_via_evtchn(xen_store_evtchn);200 }201 202 return bytes;203}204 205static int process_msg(void)206{207 static struct {208 struct xsd_sockmsg msg;209 char *body;210 union {211 void *alloc;212 struct xs_watch_event *watch;213 };214 bool in_msg;215 bool in_hdr;216 unsigned int read;217 } state;218 struct xb_req_data *req;219 int err;220 unsigned int len;221 222 if (!state.in_msg) {223 state.in_msg = true;224 state.in_hdr = true;225 state.read = 0;226 227 /*228 * We must disallow save/restore while reading a message.229 * A partial read across s/r leaves us out of sync with230 * xenstored.231 * xs_response_mutex is locked as long as we are processing one232 * message. state.in_msg will be true as long as we are holding233 * the lock here.234 */235 mutex_lock(&xs_response_mutex);236 237 if (!xb_data_to_read()) {238 /* We raced with save/restore: pending data 'gone'. */239 mutex_unlock(&xs_response_mutex);240 state.in_msg = false;241 return 0;242 }243 }244 245 if (state.in_hdr) {246 if (state.read != sizeof(state.msg)) {247 err = xb_read((void *)&state.msg + state.read,248 sizeof(state.msg) - state.read);249 if (err < 0)250 goto out;251 state.read += err;252 if (state.read != sizeof(state.msg))253 return 0;254 if (state.msg.len > XENSTORE_PAYLOAD_MAX) {255 err = -EINVAL;256 goto out;257 }258 }259 260 len = state.msg.len + 1;261 if (state.msg.type == XS_WATCH_EVENT)262 len += sizeof(*state.watch);263 264 state.alloc = kmalloc(len, GFP_NOIO | __GFP_HIGH);265 if (!state.alloc)266 return -ENOMEM;267 268 if (state.msg.type == XS_WATCH_EVENT)269 state.body = state.watch->body;270 else271 state.body = state.alloc;272 state.in_hdr = false;273 state.read = 0;274 }275 276 err = xb_read(state.body + state.read, state.msg.len - state.read);277 if (err < 0)278 goto out;279 280 state.read += err;281 if (state.read != state.msg.len)282 return 0;283 284 state.body[state.msg.len] = '\0';285 286 if (state.msg.type == XS_WATCH_EVENT) {287 state.watch->len = state.msg.len;288 err = xs_watch_msg(state.watch);289 } else {290 err = -ENOENT;291 mutex_lock(&xb_write_mutex);292 list_for_each_entry(req, &xs_reply_list, list) {293 if (req->msg.req_id == state.msg.req_id) {294 list_del(&req->list);295 err = 0;296 break;297 }298 }299 mutex_unlock(&xb_write_mutex);300 if (err)301 goto out;302 303 if (req->state == xb_req_state_wait_reply) {304 req->msg.req_id = req->caller_req_id;305 req->msg.type = state.msg.type;306 req->msg.len = state.msg.len;307 req->body = state.body;308 /* write body, then update state */309 virt_wmb();310 req->state = xb_req_state_got_reply;311 req->cb(req);312 } else313 kfree(req);314 }315 316 mutex_unlock(&xs_response_mutex);317 318 state.in_msg = false;319 state.alloc = NULL;320 return err;321 322 out:323 mutex_unlock(&xs_response_mutex);324 state.in_msg = false;325 kfree(state.alloc);326 state.alloc = NULL;327 return err;328}329 330static int process_writes(void)331{332 static struct {333 struct xb_req_data *req;334 int idx;335 unsigned int written;336 } state;337 void *base;338 unsigned int len;339 int err = 0;340 341 if (!xb_data_to_write())342 return 0;343 344 mutex_lock(&xb_write_mutex);345 346 if (!state.req) {347 state.req = list_first_entry(&xb_write_list,348 struct xb_req_data, list);349 state.idx = -1;350 state.written = 0;351 }352 353 if (state.req->state == xb_req_state_aborted)354 goto out_err;355 356 while (state.idx < state.req->num_vecs) {357 if (state.idx < 0) {358 base = &state.req->msg;359 len = sizeof(state.req->msg);360 } else {361 base = state.req->vec[state.idx].iov_base;362 len = state.req->vec[state.idx].iov_len;363 }364 err = xb_write(base + state.written, len - state.written);365 if (err < 0)366 goto out_err;367 state.written += err;368 if (state.written != len)369 goto out;370 371 state.idx++;372 state.written = 0;373 }374 375 list_del(&state.req->list);376 state.req->state = xb_req_state_wait_reply;377 list_add_tail(&state.req->list, &xs_reply_list);378 state.req = NULL;379 380 out:381 mutex_unlock(&xb_write_mutex);382 383 return 0;384 385 out_err:386 state.req->msg.type = XS_ERROR;387 state.req->err = err;388 list_del(&state.req->list);389 if (state.req->state == xb_req_state_aborted)390 kfree(state.req);391 else {392 /* write err, then update state */393 virt_wmb();394 state.req->state = xb_req_state_got_reply;395 wake_up(&state.req->wq);396 }397 398 mutex_unlock(&xb_write_mutex);399 400 state.req = NULL;401 402 return err;403}404 405static int xb_thread_work(void)406{407 return xb_data_to_read() || xb_data_to_write();408}409 410static int xenbus_thread(void *unused)411{412 int err;413 414 while (!kthread_should_stop()) {415 if (wait_event_interruptible(xb_waitq, xb_thread_work()))416 continue;417 418 err = process_msg();419 if (err == -ENOMEM)420 schedule();421 else if (err)422 pr_warn_ratelimited("error %d while reading message\n",423 err);424 425 err = process_writes();426 if (err)427 pr_warn_ratelimited("error %d while writing message\n",428 err);429 }430 431 xenbus_task = NULL;432 return 0;433}434 435/**436 * xb_init_comms - Set up interrupt handler off store event channel.437 */438int xb_init_comms(void)439{440 struct xenstore_domain_interface *intf = xen_store_interface;441 442 if (intf->req_prod != intf->req_cons)443 pr_err("request ring is not quiescent (%08x:%08x)!\n",444 intf->req_cons, intf->req_prod);445 446 if (intf->rsp_prod != intf->rsp_cons) {447 pr_warn("response ring is not quiescent (%08x:%08x): fixing up\n",448 intf->rsp_cons, intf->rsp_prod);449 /* breaks kdump */450 if (!reset_devices)451 intf->rsp_cons = intf->rsp_prod;452 }453 454 if (xenbus_irq) {455 /* Already have an irq; assume we're resuming */456 rebind_evtchn_irq(xen_store_evtchn, xenbus_irq);457 } else {458 int err;459 460 err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting,461 0, "xenbus", &xb_waitq);462 if (err < 0) {463 pr_err("request irq failed %i\n", err);464 return err;465 }466 467 xenbus_irq = err;468 469 if (!xenbus_task) {470 xenbus_task = kthread_run(xenbus_thread, NULL,471 "xenbus");472 if (IS_ERR(xenbus_task))473 return PTR_ERR(xenbus_task);474 }475 }476 477 return 0;478}479 480void xb_deinit_comms(void)481{482 unbind_from_irqhandler(xenbus_irq, &xb_waitq);483 xenbus_irq = 0;484}485