xenstore_dev.c revision 214077
1181624Skmacy/* 2214077Sgibbs * xenstore_dev.c 3181624Skmacy * 4214077Sgibbs * Driver giving user-space access to the kernel's connection to the 5214077Sgibbs * XenStore service. 6181624Skmacy * 7181624Skmacy * Copyright (c) 2005, Christian Limpach 8181624Skmacy * Copyright (c) 2005, Rusty Russell, IBM Corporation 9181624Skmacy * 10181624Skmacy * This file may be distributed separately from the Linux kernel, or 11181624Skmacy * incorporated into other software packages, subject to the following license: 12181624Skmacy * 13181624Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy 14181624Skmacy * of this source file (the "Software"), to deal in the Software without 15181624Skmacy * restriction, including without limitation the rights to use, copy, modify, 16181624Skmacy * merge, publish, distribute, sublicense, and/or sell copies of the Software, 17181624Skmacy * and to permit persons to whom the Software is furnished to do so, subject to 18181624Skmacy * the following conditions: 19181624Skmacy * 20181624Skmacy * The above copyright notice and this permission notice shall be included in 21181624Skmacy * all copies or substantial portions of the Software. 22181624Skmacy * 23181624Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24181624Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25181624Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26181624Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27181624Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28181624Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29181624Skmacy * IN THE SOFTWARE. 30181624Skmacy */ 31181624Skmacy 32181624Skmacy 33181624Skmacy#include <sys/cdefs.h> 34181624Skmacy__FBSDID("$FreeBSD: head/sys/xen/xenstore/xenstore_dev.c 214077 2010-10-19 20:53:30Z gibbs $"); 35181624Skmacy 36181624Skmacy#include <sys/types.h> 37181624Skmacy#include <sys/cdefs.h> 38181624Skmacy#include <sys/errno.h> 39181624Skmacy#include <sys/uio.h> 40181624Skmacy#include <sys/param.h> 41181624Skmacy#include <sys/systm.h> 42181624Skmacy#include <sys/proc.h> 43181624Skmacy#include <sys/kernel.h> 44181624Skmacy#include <sys/malloc.h> 45181624Skmacy#include <sys/conf.h> 46181624Skmacy 47181747Skmacy#include <machine/xen/xen-os.h> 48214077Sgibbs 49186557Skmacy#include <xen/hypervisor.h> 50214077Sgibbs#include <xen/xenstore/xenstorevar.h> 51214077Sgibbs#include <xen/xenstore/xenstore_internal.h> 52181624Skmacy 53214077Sgibbsstruct xs_dev_transaction { 54214077Sgibbs LIST_ENTRY(xs_dev_transaction) list; 55214077Sgibbs struct xs_transaction handle; 56181624Skmacy}; 57181624Skmacy 58214077Sgibbsstruct xs_dev_data { 59181624Skmacy /* In-progress transaction. */ 60214077Sgibbs LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions; 61181624Skmacy 62181624Skmacy /* Partial request. */ 63181624Skmacy unsigned int len; 64181624Skmacy union { 65181624Skmacy struct xsd_sockmsg msg; 66181624Skmacy char buffer[PAGE_SIZE]; 67181624Skmacy } u; 68181624Skmacy 69181624Skmacy /* Response queue. */ 70181624Skmacy#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) 71181624Skmacy char read_buffer[PAGE_SIZE]; 72181624Skmacy unsigned int read_cons, read_prod; 73181624Skmacy}; 74186557Skmacy 75181624Skmacystatic int 76214077Sgibbsxs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) 77181624Skmacy{ 78186557Skmacy int error; 79214077Sgibbs struct xs_dev_data *u = dev->si_drv1; 80181624Skmacy 81186557Skmacy while (u->read_prod == u->read_cons) { 82214077Sgibbs error = tsleep(u, PCATCH, "xsdread", hz/10); 83186557Skmacy if (error && error != EWOULDBLOCK) 84186557Skmacy return (error); 85186557Skmacy } 86181624Skmacy 87186557Skmacy while (uio->uio_resid > 0) { 88181624Skmacy if (u->read_cons == u->read_prod) 89181624Skmacy break; 90186557Skmacy error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 91186557Skmacy 1, uio); 92186557Skmacy if (error) 93186557Skmacy return (error); 94181624Skmacy u->read_cons++; 95181624Skmacy } 96186557Skmacy return (0); 97181624Skmacy} 98181624Skmacy 99186557Skmacystatic void 100214077Sgibbsxs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len) 101181624Skmacy{ 102181624Skmacy int i; 103181624Skmacy 104181624Skmacy for (i = 0; i < len; i++, u->read_prod++) 105181624Skmacy u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 106181624Skmacy 107186557Skmacy KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), 108186557Skmacy ("xenstore reply too big")); 109181624Skmacy 110186557Skmacy wakeup(u); 111181624Skmacy} 112181624Skmacy 113181624Skmacystatic int 114214077Sgibbsxs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) 115181624Skmacy{ 116186557Skmacy int error; 117214077Sgibbs struct xs_dev_data *u = dev->si_drv1; 118214077Sgibbs struct xs_dev_transaction *trans; 119181624Skmacy void *reply; 120186557Skmacy int len = uio->uio_resid; 121181624Skmacy 122181624Skmacy if ((len + u->len) > sizeof(u->u.buffer)) 123186557Skmacy return (EINVAL); 124181624Skmacy 125186557Skmacy error = uiomove(u->u.buffer + u->len, len, uio); 126186557Skmacy if (error) 127186557Skmacy return (error); 128181624Skmacy 129181624Skmacy u->len += len; 130181624Skmacy if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 131186557Skmacy return (0); 132181624Skmacy 133181624Skmacy switch (u->u.msg.type) { 134181624Skmacy case XS_TRANSACTION_START: 135181624Skmacy case XS_TRANSACTION_END: 136181624Skmacy case XS_DIRECTORY: 137181624Skmacy case XS_READ: 138181624Skmacy case XS_GET_PERMS: 139181624Skmacy case XS_RELEASE: 140181624Skmacy case XS_GET_DOMAIN_PATH: 141181624Skmacy case XS_WRITE: 142181624Skmacy case XS_MKDIR: 143181624Skmacy case XS_RM: 144181624Skmacy case XS_SET_PERMS: 145214077Sgibbs error = xs_dev_request_and_reply(&u->u.msg, &reply); 146186557Skmacy if (!error) { 147181624Skmacy if (u->u.msg.type == XS_TRANSACTION_START) { 148214077Sgibbs trans = malloc(sizeof(*trans), M_XENSTORE, 149186557Skmacy M_WAITOK); 150186557Skmacy trans->handle.id = strtoul(reply, NULL, 0); 151181624Skmacy LIST_INSERT_HEAD(&u->transactions, trans, list); 152181624Skmacy } else if (u->u.msg.type == XS_TRANSACTION_END) { 153186557Skmacy LIST_FOREACH(trans, &u->transactions, list) 154186557Skmacy if (trans->handle.id == u->u.msg.tx_id) 155181624Skmacy break; 156181624Skmacy#if 0 /* XXX does this mean the list is empty? */ 157181624Skmacy BUG_ON(&trans->list == &u->transactions); 158181624Skmacy#endif 159181624Skmacy LIST_REMOVE(trans, list); 160214077Sgibbs free(trans, M_XENSTORE); 161181624Skmacy } 162214077Sgibbs xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 163214077Sgibbs xs_queue_reply(u, (char *)reply, u->u.msg.len); 164214077Sgibbs free(reply, M_XENSTORE); 165181624Skmacy } 166181624Skmacy break; 167181624Skmacy 168181624Skmacy default: 169186557Skmacy error = EINVAL; 170181624Skmacy break; 171181624Skmacy } 172181624Skmacy 173186557Skmacy if (error == 0) 174181624Skmacy u->len = 0; 175181624Skmacy 176186557Skmacy return (error); 177181624Skmacy} 178181624Skmacy 179186557Skmacystatic int 180214077Sgibbsxs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 181181624Skmacy{ 182214077Sgibbs struct xs_dev_data *u; 183181624Skmacy 184181624Skmacy#if 0 /* XXX figure out if equiv needed */ 185181624Skmacy nonseekable_open(inode, filp); 186181624Skmacy#endif 187214077Sgibbs u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); 188181624Skmacy LIST_INIT(&u->transactions); 189181624Skmacy dev->si_drv1 = u; 190181624Skmacy 191186557Skmacy return (0); 192181624Skmacy} 193181624Skmacy 194186557Skmacystatic int 195214077Sgibbsxs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 196181624Skmacy{ 197214077Sgibbs struct xs_dev_data *u = dev->si_drv1; 198214077Sgibbs struct xs_dev_transaction *trans, *tmp; 199181624Skmacy 200181624Skmacy LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { 201214077Sgibbs xs_transaction_end(trans->handle, 1); 202181624Skmacy LIST_REMOVE(trans, list); 203214077Sgibbs free(trans, M_XENSTORE); 204181624Skmacy } 205181624Skmacy 206214077Sgibbs free(u, M_XENSTORE); 207186557Skmacy return (0); 208181624Skmacy} 209181624Skmacy 210214077Sgibbsstatic struct cdevsw xs_dev_cdevsw = { 211181624Skmacy .d_version = D_VERSION, 212214077Sgibbs .d_read = xs_dev_read, 213214077Sgibbs .d_write = xs_dev_write, 214214077Sgibbs .d_open = xs_dev_open, 215214077Sgibbs .d_close = xs_dev_close, 216214077Sgibbs .d_name = "xs_dev", 217181624Skmacy}; 218181624Skmacy 219214077Sgibbsvoid 220214077Sgibbsxs_dev_init() 221181624Skmacy{ 222214077Sgibbs make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, 223214077Sgibbs "xen/xenstore"); 224181624Skmacy} 225