162306a36Sopenharmony_ci/****************************************************************************** 262306a36Sopenharmony_ci * xenbus_comms.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Low level code to talks to Xen Store: ringbuffer and event channel. 562306a36Sopenharmony_ci * 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 3362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/wait.h> 3662306a36Sopenharmony_ci#include <linux/interrupt.h> 3762306a36Sopenharmony_ci#include <linux/kthread.h> 3862306a36Sopenharmony_ci#include <linux/sched.h> 3962306a36Sopenharmony_ci#include <linux/err.h> 4062306a36Sopenharmony_ci#include <xen/xenbus.h> 4162306a36Sopenharmony_ci#include <asm/xen/hypervisor.h> 4262306a36Sopenharmony_ci#include <xen/events.h> 4362306a36Sopenharmony_ci#include <xen/page.h> 4462306a36Sopenharmony_ci#include "xenbus.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* A list of replies. Currently only one will ever be outstanding. */ 4762306a36Sopenharmony_ciLIST_HEAD(xs_reply_list); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* A list of write requests. */ 5062306a36Sopenharmony_ciLIST_HEAD(xb_write_list); 5162306a36Sopenharmony_ciDECLARE_WAIT_QUEUE_HEAD(xb_waitq); 5262306a36Sopenharmony_ciDEFINE_MUTEX(xb_write_mutex); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* Protect xenbus reader thread against save/restore. */ 5562306a36Sopenharmony_ciDEFINE_MUTEX(xs_response_mutex); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int xenbus_irq; 5862306a36Sopenharmony_cistatic struct task_struct *xenbus_task; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic irqreturn_t wake_waiting(int irq, void *unused) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci wake_up(&xb_waitq); 6362306a36Sopenharmony_ci return IRQ_HANDLED; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return ((prod - cons) <= XENSTORE_RING_SIZE); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void *get_output_chunk(XENSTORE_RING_IDX cons, 7262306a36Sopenharmony_ci XENSTORE_RING_IDX prod, 7362306a36Sopenharmony_ci char *buf, uint32_t *len) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); 7662306a36Sopenharmony_ci if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) 7762306a36Sopenharmony_ci *len = XENSTORE_RING_SIZE - (prod - cons); 7862306a36Sopenharmony_ci return buf + MASK_XENSTORE_IDX(prod); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic const void *get_input_chunk(XENSTORE_RING_IDX cons, 8262306a36Sopenharmony_ci XENSTORE_RING_IDX prod, 8362306a36Sopenharmony_ci const char *buf, uint32_t *len) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); 8662306a36Sopenharmony_ci if ((prod - cons) < *len) 8762306a36Sopenharmony_ci *len = prod - cons; 8862306a36Sopenharmony_ci return buf + MASK_XENSTORE_IDX(cons); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int xb_data_to_write(void) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct xenstore_domain_interface *intf = xen_store_interface; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return (intf->req_prod - intf->req_cons) != XENSTORE_RING_SIZE && 9662306a36Sopenharmony_ci !list_empty(&xb_write_list); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * xb_write - low level write 10162306a36Sopenharmony_ci * @data: buffer to send 10262306a36Sopenharmony_ci * @len: length of buffer 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Returns number of bytes written or -err. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic int xb_write(const void *data, unsigned int len) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct xenstore_domain_interface *intf = xen_store_interface; 10962306a36Sopenharmony_ci XENSTORE_RING_IDX cons, prod; 11062306a36Sopenharmony_ci unsigned int bytes = 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci while (len != 0) { 11362306a36Sopenharmony_ci void *dst; 11462306a36Sopenharmony_ci unsigned int avail; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Read indexes, then verify. */ 11762306a36Sopenharmony_ci cons = intf->req_cons; 11862306a36Sopenharmony_ci prod = intf->req_prod; 11962306a36Sopenharmony_ci if (!check_indexes(cons, prod)) { 12062306a36Sopenharmony_ci intf->req_cons = intf->req_prod = 0; 12162306a36Sopenharmony_ci return -EIO; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci if (!xb_data_to_write()) 12462306a36Sopenharmony_ci return bytes; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Must write data /after/ reading the consumer index. */ 12762306a36Sopenharmony_ci virt_mb(); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci dst = get_output_chunk(cons, prod, intf->req, &avail); 13062306a36Sopenharmony_ci if (avail == 0) 13162306a36Sopenharmony_ci continue; 13262306a36Sopenharmony_ci if (avail > len) 13362306a36Sopenharmony_ci avail = len; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci memcpy(dst, data, avail); 13662306a36Sopenharmony_ci data += avail; 13762306a36Sopenharmony_ci len -= avail; 13862306a36Sopenharmony_ci bytes += avail; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Other side must not see new producer until data is there. */ 14162306a36Sopenharmony_ci virt_wmb(); 14262306a36Sopenharmony_ci intf->req_prod += avail; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Implies mb(): other side will see the updated producer. */ 14562306a36Sopenharmony_ci if (prod <= intf->req_cons) 14662306a36Sopenharmony_ci notify_remote_via_evtchn(xen_store_evtchn); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return bytes; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int xb_data_to_read(void) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct xenstore_domain_interface *intf = xen_store_interface; 15562306a36Sopenharmony_ci return (intf->rsp_cons != intf->rsp_prod); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int xb_read(void *data, unsigned int len) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct xenstore_domain_interface *intf = xen_store_interface; 16162306a36Sopenharmony_ci XENSTORE_RING_IDX cons, prod; 16262306a36Sopenharmony_ci unsigned int bytes = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci while (len != 0) { 16562306a36Sopenharmony_ci unsigned int avail; 16662306a36Sopenharmony_ci const char *src; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Read indexes, then verify. */ 16962306a36Sopenharmony_ci cons = intf->rsp_cons; 17062306a36Sopenharmony_ci prod = intf->rsp_prod; 17162306a36Sopenharmony_ci if (cons == prod) 17262306a36Sopenharmony_ci return bytes; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!check_indexes(cons, prod)) { 17562306a36Sopenharmony_ci intf->rsp_cons = intf->rsp_prod = 0; 17662306a36Sopenharmony_ci return -EIO; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci src = get_input_chunk(cons, prod, intf->rsp, &avail); 18062306a36Sopenharmony_ci if (avail == 0) 18162306a36Sopenharmony_ci continue; 18262306a36Sopenharmony_ci if (avail > len) 18362306a36Sopenharmony_ci avail = len; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Must read data /after/ reading the producer index. */ 18662306a36Sopenharmony_ci virt_rmb(); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci memcpy(data, src, avail); 18962306a36Sopenharmony_ci data += avail; 19062306a36Sopenharmony_ci len -= avail; 19162306a36Sopenharmony_ci bytes += avail; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Other side must not see free space until we've copied out */ 19462306a36Sopenharmony_ci virt_mb(); 19562306a36Sopenharmony_ci intf->rsp_cons += avail; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Implies mb(): other side will see the updated consumer. */ 19862306a36Sopenharmony_ci if (intf->rsp_prod - cons >= XENSTORE_RING_SIZE) 19962306a36Sopenharmony_ci notify_remote_via_evtchn(xen_store_evtchn); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return bytes; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int process_msg(void) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci static struct { 20862306a36Sopenharmony_ci struct xsd_sockmsg msg; 20962306a36Sopenharmony_ci char *body; 21062306a36Sopenharmony_ci union { 21162306a36Sopenharmony_ci void *alloc; 21262306a36Sopenharmony_ci struct xs_watch_event *watch; 21362306a36Sopenharmony_ci }; 21462306a36Sopenharmony_ci bool in_msg; 21562306a36Sopenharmony_ci bool in_hdr; 21662306a36Sopenharmony_ci unsigned int read; 21762306a36Sopenharmony_ci } state; 21862306a36Sopenharmony_ci struct xb_req_data *req; 21962306a36Sopenharmony_ci int err; 22062306a36Sopenharmony_ci unsigned int len; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!state.in_msg) { 22362306a36Sopenharmony_ci state.in_msg = true; 22462306a36Sopenharmony_ci state.in_hdr = true; 22562306a36Sopenharmony_ci state.read = 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* 22862306a36Sopenharmony_ci * We must disallow save/restore while reading a message. 22962306a36Sopenharmony_ci * A partial read across s/r leaves us out of sync with 23062306a36Sopenharmony_ci * xenstored. 23162306a36Sopenharmony_ci * xs_response_mutex is locked as long as we are processing one 23262306a36Sopenharmony_ci * message. state.in_msg will be true as long as we are holding 23362306a36Sopenharmony_ci * the lock here. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci mutex_lock(&xs_response_mutex); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (!xb_data_to_read()) { 23862306a36Sopenharmony_ci /* We raced with save/restore: pending data 'gone'. */ 23962306a36Sopenharmony_ci mutex_unlock(&xs_response_mutex); 24062306a36Sopenharmony_ci state.in_msg = false; 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (state.in_hdr) { 24662306a36Sopenharmony_ci if (state.read != sizeof(state.msg)) { 24762306a36Sopenharmony_ci err = xb_read((void *)&state.msg + state.read, 24862306a36Sopenharmony_ci sizeof(state.msg) - state.read); 24962306a36Sopenharmony_ci if (err < 0) 25062306a36Sopenharmony_ci goto out; 25162306a36Sopenharmony_ci state.read += err; 25262306a36Sopenharmony_ci if (state.read != sizeof(state.msg)) 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci if (state.msg.len > XENSTORE_PAYLOAD_MAX) { 25562306a36Sopenharmony_ci err = -EINVAL; 25662306a36Sopenharmony_ci goto out; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci len = state.msg.len + 1; 26162306a36Sopenharmony_ci if (state.msg.type == XS_WATCH_EVENT) 26262306a36Sopenharmony_ci len += sizeof(*state.watch); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci state.alloc = kmalloc(len, GFP_NOIO | __GFP_HIGH); 26562306a36Sopenharmony_ci if (!state.alloc) 26662306a36Sopenharmony_ci return -ENOMEM; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (state.msg.type == XS_WATCH_EVENT) 26962306a36Sopenharmony_ci state.body = state.watch->body; 27062306a36Sopenharmony_ci else 27162306a36Sopenharmony_ci state.body = state.alloc; 27262306a36Sopenharmony_ci state.in_hdr = false; 27362306a36Sopenharmony_ci state.read = 0; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci err = xb_read(state.body + state.read, state.msg.len - state.read); 27762306a36Sopenharmony_ci if (err < 0) 27862306a36Sopenharmony_ci goto out; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci state.read += err; 28162306a36Sopenharmony_ci if (state.read != state.msg.len) 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci state.body[state.msg.len] = '\0'; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (state.msg.type == XS_WATCH_EVENT) { 28762306a36Sopenharmony_ci state.watch->len = state.msg.len; 28862306a36Sopenharmony_ci err = xs_watch_msg(state.watch); 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci err = -ENOENT; 29162306a36Sopenharmony_ci mutex_lock(&xb_write_mutex); 29262306a36Sopenharmony_ci list_for_each_entry(req, &xs_reply_list, list) { 29362306a36Sopenharmony_ci if (req->msg.req_id == state.msg.req_id) { 29462306a36Sopenharmony_ci list_del(&req->list); 29562306a36Sopenharmony_ci err = 0; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci mutex_unlock(&xb_write_mutex); 30062306a36Sopenharmony_ci if (err) 30162306a36Sopenharmony_ci goto out; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (req->state == xb_req_state_wait_reply) { 30462306a36Sopenharmony_ci req->msg.req_id = req->caller_req_id; 30562306a36Sopenharmony_ci req->msg.type = state.msg.type; 30662306a36Sopenharmony_ci req->msg.len = state.msg.len; 30762306a36Sopenharmony_ci req->body = state.body; 30862306a36Sopenharmony_ci /* write body, then update state */ 30962306a36Sopenharmony_ci virt_wmb(); 31062306a36Sopenharmony_ci req->state = xb_req_state_got_reply; 31162306a36Sopenharmony_ci req->cb(req); 31262306a36Sopenharmony_ci } else 31362306a36Sopenharmony_ci kfree(req); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci mutex_unlock(&xs_response_mutex); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci state.in_msg = false; 31962306a36Sopenharmony_ci state.alloc = NULL; 32062306a36Sopenharmony_ci return err; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci out: 32362306a36Sopenharmony_ci mutex_unlock(&xs_response_mutex); 32462306a36Sopenharmony_ci state.in_msg = false; 32562306a36Sopenharmony_ci kfree(state.alloc); 32662306a36Sopenharmony_ci state.alloc = NULL; 32762306a36Sopenharmony_ci return err; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic int process_writes(void) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci static struct { 33362306a36Sopenharmony_ci struct xb_req_data *req; 33462306a36Sopenharmony_ci int idx; 33562306a36Sopenharmony_ci unsigned int written; 33662306a36Sopenharmony_ci } state; 33762306a36Sopenharmony_ci void *base; 33862306a36Sopenharmony_ci unsigned int len; 33962306a36Sopenharmony_ci int err = 0; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!xb_data_to_write()) 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci mutex_lock(&xb_write_mutex); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!state.req) { 34762306a36Sopenharmony_ci state.req = list_first_entry(&xb_write_list, 34862306a36Sopenharmony_ci struct xb_req_data, list); 34962306a36Sopenharmony_ci state.idx = -1; 35062306a36Sopenharmony_ci state.written = 0; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (state.req->state == xb_req_state_aborted) 35462306a36Sopenharmony_ci goto out_err; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci while (state.idx < state.req->num_vecs) { 35762306a36Sopenharmony_ci if (state.idx < 0) { 35862306a36Sopenharmony_ci base = &state.req->msg; 35962306a36Sopenharmony_ci len = sizeof(state.req->msg); 36062306a36Sopenharmony_ci } else { 36162306a36Sopenharmony_ci base = state.req->vec[state.idx].iov_base; 36262306a36Sopenharmony_ci len = state.req->vec[state.idx].iov_len; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci err = xb_write(base + state.written, len - state.written); 36562306a36Sopenharmony_ci if (err < 0) 36662306a36Sopenharmony_ci goto out_err; 36762306a36Sopenharmony_ci state.written += err; 36862306a36Sopenharmony_ci if (state.written != len) 36962306a36Sopenharmony_ci goto out; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci state.idx++; 37262306a36Sopenharmony_ci state.written = 0; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci list_del(&state.req->list); 37662306a36Sopenharmony_ci state.req->state = xb_req_state_wait_reply; 37762306a36Sopenharmony_ci list_add_tail(&state.req->list, &xs_reply_list); 37862306a36Sopenharmony_ci state.req = NULL; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci out: 38162306a36Sopenharmony_ci mutex_unlock(&xb_write_mutex); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci out_err: 38662306a36Sopenharmony_ci state.req->msg.type = XS_ERROR; 38762306a36Sopenharmony_ci state.req->err = err; 38862306a36Sopenharmony_ci list_del(&state.req->list); 38962306a36Sopenharmony_ci if (state.req->state == xb_req_state_aborted) 39062306a36Sopenharmony_ci kfree(state.req); 39162306a36Sopenharmony_ci else { 39262306a36Sopenharmony_ci /* write err, then update state */ 39362306a36Sopenharmony_ci virt_wmb(); 39462306a36Sopenharmony_ci state.req->state = xb_req_state_got_reply; 39562306a36Sopenharmony_ci wake_up(&state.req->wq); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci mutex_unlock(&xb_write_mutex); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci state.req = NULL; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return err; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int xb_thread_work(void) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci return xb_data_to_read() || xb_data_to_write(); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int xenbus_thread(void *unused) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci int err; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci while (!kthread_should_stop()) { 41562306a36Sopenharmony_ci if (wait_event_interruptible(xb_waitq, xb_thread_work())) 41662306a36Sopenharmony_ci continue; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci err = process_msg(); 41962306a36Sopenharmony_ci if (err == -ENOMEM) 42062306a36Sopenharmony_ci schedule(); 42162306a36Sopenharmony_ci else if (err) 42262306a36Sopenharmony_ci pr_warn_ratelimited("error %d while reading message\n", 42362306a36Sopenharmony_ci err); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci err = process_writes(); 42662306a36Sopenharmony_ci if (err) 42762306a36Sopenharmony_ci pr_warn_ratelimited("error %d while writing message\n", 42862306a36Sopenharmony_ci err); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci xenbus_task = NULL; 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/** 43662306a36Sopenharmony_ci * xb_init_comms - Set up interrupt handler off store event channel. 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_ciint xb_init_comms(void) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct xenstore_domain_interface *intf = xen_store_interface; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (intf->req_prod != intf->req_cons) 44362306a36Sopenharmony_ci pr_err("request ring is not quiescent (%08x:%08x)!\n", 44462306a36Sopenharmony_ci intf->req_cons, intf->req_prod); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (intf->rsp_prod != intf->rsp_cons) { 44762306a36Sopenharmony_ci pr_warn("response ring is not quiescent (%08x:%08x): fixing up\n", 44862306a36Sopenharmony_ci intf->rsp_cons, intf->rsp_prod); 44962306a36Sopenharmony_ci /* breaks kdump */ 45062306a36Sopenharmony_ci if (!reset_devices) 45162306a36Sopenharmony_ci intf->rsp_cons = intf->rsp_prod; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (xenbus_irq) { 45562306a36Sopenharmony_ci /* Already have an irq; assume we're resuming */ 45662306a36Sopenharmony_ci rebind_evtchn_irq(xen_store_evtchn, xenbus_irq); 45762306a36Sopenharmony_ci } else { 45862306a36Sopenharmony_ci int err; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting, 46162306a36Sopenharmony_ci 0, "xenbus", &xb_waitq); 46262306a36Sopenharmony_ci if (err < 0) { 46362306a36Sopenharmony_ci pr_err("request irq failed %i\n", err); 46462306a36Sopenharmony_ci return err; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci xenbus_irq = err; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!xenbus_task) { 47062306a36Sopenharmony_ci xenbus_task = kthread_run(xenbus_thread, NULL, 47162306a36Sopenharmony_ci "xenbus"); 47262306a36Sopenharmony_ci if (IS_ERR(xenbus_task)) 47362306a36Sopenharmony_ci return PTR_ERR(xenbus_task); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_civoid xb_deinit_comms(void) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci unbind_from_irqhandler(xenbus_irq, &xb_waitq); 48362306a36Sopenharmony_ci xenbus_irq = 0; 48462306a36Sopenharmony_ci} 485