cregit-Linux how code gets into the kernel

Release 4.11 drivers/xen/xenbus/xenbus_comms.c

/******************************************************************************
 * xenbus_comms.c
 *
 * Low level code to talks to Xen Store: ringbuffer and event channel.
 *
 * Copyright (C) 2005 Rusty Russell, IBM Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation; or, when distributed
 * separately from the Linux kernel or incorporated into other
 * software packages, subject to the following license:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this source file (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/err.h>
#include <xen/xenbus.h>
#include <asm/xen/hypervisor.h>
#include <xen/events.h>
#include <xen/page.h>
#include "xenbus.h"

/* A list of replies. Currently only one will ever be outstanding. */

LIST_HEAD(xs_reply_list);

/* A list of write requests. */

LIST_HEAD(xb_write_list);

DECLARE_WAIT_QUEUE_HEAD(xb_waitq);

DEFINE_MUTEX(xb_write_mutex);

/* Protect xenbus reader thread against save/restore. */

DEFINE_MUTEX(xs_response_mutex);


static int xenbus_irq;

static struct task_struct *xenbus_task;

static DECLARE_WORK(probe_work, xenbus_probe);



static irqreturn_t wake_waiting(int irq, void *unused) { if (unlikely(xenstored_ready == 0)) { xenstored_ready = 1; schedule_work(&probe_work); } wake_up(&xb_waitq); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge43100.00%1100.00%
Total43100.00%1100.00%


static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) { return ((prod - cons) <= XENSTORE_RING_SIZE); }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge23100.00%1100.00%
Total23100.00%1100.00%


static void *get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, char *buf, uint32_t *len) { *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) *len = XENSTORE_RING_SIZE - (prod - cons); return buf + MASK_XENSTORE_IDX(prod); }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge65100.00%1100.00%
Total65100.00%1100.00%


static const void *get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, const char *buf, uint32_t *len) { *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); if ((prod - cons) < *len) *len = prod - cons; return buf + MASK_XENSTORE_IDX(cons); }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge59100.00%1100.00%
Total59100.00%1100.00%


static int xb_data_to_write(void) { struct xenstore_domain_interface *intf = xen_store_interface; return (intf->req_prod - intf->req_cons) != XENSTORE_RING_SIZE && !list_empty(&xb_write_list); }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross35100.00%1100.00%
Total35100.00%1100.00%

/** * xb_write - low level write * @data: buffer to send * @len: length of buffer * * Returns number of bytes written or -err. */
static int xb_write(const void *data, unsigned int len) { struct xenstore_domain_interface *intf = xen_store_interface; XENSTORE_RING_IDX cons, prod; unsigned int bytes = 0; while (len != 0) { void *dst; unsigned int avail; /* Read indexes, then verify. */ cons = intf->req_cons; prod = intf->req_prod; if (!check_indexes(cons, prod)) { intf->req_cons = intf->req_prod = 0; return -EIO; } if (!xb_data_to_write()) return bytes; /* Must write data /after/ reading the consumer index. */ virt_mb(); dst = get_output_chunk(cons, prod, intf->req, &avail); if (avail == 0) continue; if (avail > len) avail = len; memcpy(dst, data, avail); data += avail; len -= avail; bytes += avail; /* Other side must not see new producer until data is there. */ virt_wmb(); intf->req_prod += avail; /* Implies mb(): other side will see the updated producer. */ if (prod <= intf->req_cons) notify_remote_via_evtchn(xen_store_evtchn); } return bytes; }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge14981.87%133.33%
Juergen Gross3217.58%133.33%
Michael S. Tsirkin10.55%133.33%
Total182100.00%3100.00%


static int xb_data_to_read(void) { struct xenstore_domain_interface *intf = xen_store_interface; return (intf->rsp_cons != intf->rsp_prod); }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge2596.15%150.00%
Juergen Gross13.85%150.00%
Total26100.00%2100.00%


static int xb_read(void *data, unsigned int len) { struct xenstore_domain_interface *intf = xen_store_interface; XENSTORE_RING_IDX cons, prod; unsigned int bytes = 0; while (len != 0) { unsigned int avail; const char *src; /* Read indexes, then verify. */ cons = intf->rsp_cons; prod = intf->rsp_prod; if (cons == prod) return bytes; if (!check_indexes(cons, prod)) { intf->rsp_cons = intf->rsp_prod = 0; return -EIO; } src = get_input_chunk(cons, prod, intf->rsp, &avail); if (avail == 0) continue; if (avail > len) avail = len; /* Must read data /after/ reading the producer index. */ virt_rmb(); memcpy(data, src, avail); data += avail; len -= avail; bytes += avail; /* Other side must not see free space until we've copied out */ virt_mb(); intf->rsp_cons += avail; /* Implies mb(): other side will see the updated consumer. */ if (intf->rsp_prod - cons >= XENSTORE_RING_SIZE) notify_remote_via_evtchn(xen_store_evtchn); } return bytes; }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge15282.61%133.33%
Juergen Gross3016.30%133.33%
Michael S. Tsirkin21.09%133.33%
Total184100.00%3100.00%


static int process_msg(void) { static struct { struct xsd_sockmsg msg; char *body; union { void *alloc; struct xs_watch_event *watch; }; bool in_msg; bool in_hdr; unsigned int read; } state; struct xb_req_data *req; int err; unsigned int len; if (!state.in_msg) { state.in_msg = true; state.in_hdr = true; state.read = 0; /* * We must disallow save/restore while reading a message. * A partial read across s/r leaves us out of sync with * xenstored. * xs_response_mutex is locked as long as we are processing one * message. state.in_msg will be true as long as we are holding * the lock here. */ mutex_lock(&xs_response_mutex); if (!xb_data_to_read()) { /* We raced with save/restore: pending data 'gone'. */ mutex_unlock(&xs_response_mutex); state.in_msg = false; return 0; } } if (state.in_hdr) { if (state.read != sizeof(state.msg)) { err = xb_read((void *)&state.msg + state.read, sizeof(state.msg) - state.read); if (err < 0) goto out; state.read += err; if (state.read != sizeof(state.msg)) return 0; if (state.msg.len > XENSTORE_PAYLOAD_MAX) { err = -EINVAL; goto out; } } len = state.msg.len + 1; if (state.msg.type == XS_WATCH_EVENT) len += sizeof(*state.watch); state.alloc = kmalloc(len, GFP_NOIO | __GFP_HIGH); if (!state.alloc) return -ENOMEM; if (state.msg.type == XS_WATCH_EVENT) state.body = state.watch->body; else state.body = state.alloc; state.in_hdr = false; state.read = 0; } err = xb_read(state.body + state.read, state.msg.len - state.read); if (err < 0) goto out; state.read += err; if (state.read != state.msg.len) return 0; state.body[state.msg.len] = '\0'; if (state.msg.type == XS_WATCH_EVENT) { state.watch->len = state.msg.len; err = xs_watch_msg(state.watch); } else { err = -ENOENT; mutex_lock(&xb_write_mutex); list_for_each_entry(req, &xs_reply_list, list) { if (req->msg.req_id == state.msg.req_id) { if (req->state == xb_req_state_wait_reply) { req->msg.type = state.msg.type; req->msg.len = state.msg.len; req->body = state.body; req->state = xb_req_state_got_reply; list_del(&req->list); req->cb(req); } else { list_del(&req->list); kfree(req); } err = 0; break; } } mutex_unlock(&xb_write_mutex); if (err) goto out; } mutex_unlock(&xs_response_mutex); state.in_msg = false; state.alloc = NULL; return err; out: mutex_unlock(&xs_response_mutex); state.in_msg = false; kfree(state.alloc); state.alloc = NULL; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross58998.17%150.00%
Jeremy Fitzhardinge111.83%150.00%
Total600100.00%2100.00%


static int process_writes(void) { static struct { struct xb_req_data *req; int idx; unsigned int written; } state; void *base; unsigned int len; int err = 0; if (!xb_data_to_write()) return 0; mutex_lock(&xb_write_mutex); if (!state.req) { state.req = list_first_entry(&xb_write_list, struct xb_req_data, list); state.idx = -1; state.written = 0; } if (state.req->state == xb_req_state_aborted) goto out_err; while (state.idx < state.req->num_vecs) { if (state.idx < 0) { base = &state.req->msg; len = sizeof(state.req->msg); } else { base = state.req->vec[state.idx].iov_base; len = state.req->vec[state.idx].iov_len; } err = xb_write(base + state.written, len - state.written); if (err < 0) goto out_err; state.written += err; if (state.written != len) goto out; state.idx++; state.written = 0; } list_del(&state.req->list); state.req->state = xb_req_state_wait_reply; list_add_tail(&state.req->list, &xs_reply_list); state.req = NULL; out: mutex_unlock(&xb_write_mutex); return 0; out_err: state.req->msg.type = XS_ERROR; state.req->err = err; list_del(&state.req->list); if (state.req->state == xb_req_state_aborted) kfree(state.req); else { state.req->state = xb_req_state_got_reply; wake_up(&state.req->wq); } mutex_unlock(&xb_write_mutex); state.req = NULL; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross366100.00%1100.00%
Total366100.00%1100.00%


static int xb_thread_work(void) { return xb_data_to_read() || xb_data_to_write(); }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross15100.00%1100.00%
Total15100.00%1100.00%


static int xenbus_thread(void *unused) { int err; while (!kthread_should_stop()) { if (wait_event_interruptible(xb_waitq, xb_thread_work())) continue; err = process_msg(); if (err == -ENOMEM) schedule(); else if (err) pr_warn_ratelimited("error %d while reading message\n", err); err = process_writes(); if (err) pr_warn_ratelimited("error %d while writing message\n", err); } xenbus_task = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross82100.00%1100.00%
Total82100.00%1100.00%

/** * xb_init_comms - Set up interrupt handler off store event channel. */
int xb_init_comms(void) { struct xenstore_domain_interface *intf = xen_store_interface; if (intf->req_prod != intf->req_cons) pr_err("request ring is not quiescent (%08x:%08x)!\n", intf->req_cons, intf->req_prod); if (intf->rsp_prod != intf->rsp_cons) { pr_warn("response ring is not quiescent (%08x:%08x): fixing up\n", intf->rsp_cons, intf->rsp_prod); /* breaks kdump */ if (!reset_devices) intf->rsp_cons = intf->rsp_prod; } if (xenbus_irq) { /* Already have an irq; assume we're resuming */ rebind_evtchn_irq(xen_store_evtchn, xenbus_irq); } else { int err; err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting, 0, "xenbus", &xb_waitq); if (err < 0) { pr_err("request irq failed %i\n", err); return err; } xenbus_irq = err; if (!xenbus_task) { xenbus_task = kthread_run(xenbus_thread, NULL, "xenbus"); if (IS_ERR(xenbus_task)) return PTR_ERR(xenbus_task); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jeremy Fitzhardinge9657.14%233.33%
Juergen Gross6136.31%116.67%
Olaf Hering63.57%116.67%
Joe Perches42.38%116.67%
Stefano Stabellini10.60%116.67%
Total168100.00%6100.00%


void xb_deinit_comms(void) { unbind_from_irqhandler(xenbus_irq, &xb_waitq); xenbus_irq = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel De Graaf19100.00%1100.00%
Total19100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Juergen Gross125164.06%222.22%
Jeremy Fitzhardinge66233.90%222.22%
Daniel De Graaf190.97%111.11%
Joe Perches110.56%111.11%
Olaf Hering60.31%111.11%
Michael S. Tsirkin30.15%111.11%
Stefano Stabellini10.05%111.11%
Total1953100.00%9100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.