xenstore_dev.c revision 279562
1/* 2 * xenstore_dev.c 3 * 4 * Driver giving user-space access to the kernel's connection to the 5 * XenStore service. 6 * 7 * Copyright (c) 2005, Christian Limpach 8 * Copyright (c) 2005, Rusty Russell, IBM Corporation 9 * 10 * This file may be distributed separately from the Linux kernel, or 11 * incorporated into other software packages, subject to the following license: 12 * 13 * Permission is hereby granted, free of charge, to any person obtaining a copy 14 * of this source file (the "Software"), to deal in the Software without 15 * restriction, including without limitation the rights to use, copy, modify, 16 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 17 * and to permit persons to whom the Software is furnished to do so, subject to 18 * the following conditions: 19 * 20 * The above copyright notice and this permission notice shall be included in 21 * all copies or substantial portions of the Software. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29 * IN THE SOFTWARE. 30 */ 31 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: stable/10/sys/xen/xenstore/xenstore_dev.c 279562 2015-03-03 10:11:58Z royger $"); 35 36#include <sys/types.h> 37#include <sys/cdefs.h> 38#include <sys/errno.h> 39#include <sys/uio.h> 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/proc.h> 43#include <sys/kernel.h> 44#include <sys/malloc.h> 45#include <sys/conf.h> 46 47#include <xen/xen-os.h> 48 49#include <xen/hypervisor.h> 50#include <xen/xenstore/xenstorevar.h> 51#include <xen/xenstore/xenstore_internal.h> 52 53struct xs_dev_transaction { 54 LIST_ENTRY(xs_dev_transaction) list; 55 struct xs_transaction handle; 56}; 57 58struct xs_dev_data { 59 /* In-progress transaction. */ 60 LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions; 61 62 /* Partial request. */ 63 unsigned int len; 64 union { 65 struct xsd_sockmsg msg; 66 char buffer[PAGE_SIZE]; 67 } u; 68 69 /* Response queue. */ 70#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) 71 char read_buffer[PAGE_SIZE]; 72 unsigned int read_cons, read_prod; 73}; 74 75static int 76xs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) 77{ 78 int error; 79 struct xs_dev_data *u; 80 81 error = devfs_get_cdevpriv((void **)&u); 82 if (error != 0) 83 return (error); 84 85 while (u->read_prod == u->read_cons) { 86 error = tsleep(u, PCATCH, "xsdread", hz/10); 87 if (error && error != EWOULDBLOCK) 88 return (error); 89 } 90 91 while (uio->uio_resid > 0) { 92 if (u->read_cons == u->read_prod) 93 break; 94 error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 95 1, uio); 96 if (error) 97 return (error); 98 u->read_cons++; 99 } 100 return (0); 101} 102 103static void 104xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len) 105{ 106 int i; 107 108 for (i = 0; i < len; i++, u->read_prod++) 109 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 110 111 KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), 112 ("xenstore reply too big")); 113 114 wakeup(u); 115} 116 117static int 118xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) 119{ 120 int error; 121 struct xs_dev_data *u; 122 struct xs_dev_transaction *trans; 123 void *reply; 124 int len = uio->uio_resid; 125 126 error = devfs_get_cdevpriv((void **)&u); 127 if (error != 0) 128 return (error); 129 130 if ((len + u->len) > sizeof(u->u.buffer)) 131 return (EINVAL); 132 133 error = uiomove(u->u.buffer + u->len, len, uio); 134 if (error) 135 return (error); 136 137 u->len += len; 138 if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 139 return (0); 140 141 switch (u->u.msg.type) { 142 case XS_TRANSACTION_START: 143 case XS_TRANSACTION_END: 144 case XS_DIRECTORY: 145 case XS_READ: 146 case XS_GET_PERMS: 147 case XS_RELEASE: 148 case XS_GET_DOMAIN_PATH: 149 case XS_WRITE: 150 case XS_MKDIR: 151 case XS_RM: 152 case XS_SET_PERMS: 153 error = xs_dev_request_and_reply(&u->u.msg, &reply); 154 if (!error) { 155 if (u->u.msg.type == XS_TRANSACTION_START) { 156 trans = malloc(sizeof(*trans), M_XENSTORE, 157 M_WAITOK); 158 trans->handle.id = strtoul(reply, NULL, 0); 159 LIST_INSERT_HEAD(&u->transactions, trans, list); 160 } else if (u->u.msg.type == XS_TRANSACTION_END) { 161 LIST_FOREACH(trans, &u->transactions, list) 162 if (trans->handle.id == u->u.msg.tx_id) 163 break; 164#if 0 /* XXX does this mean the list is empty? */ 165 BUG_ON(&trans->list == &u->transactions); 166#endif 167 LIST_REMOVE(trans, list); 168 free(trans, M_XENSTORE); 169 } 170 xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 171 xs_queue_reply(u, (char *)reply, u->u.msg.len); 172 free(reply, M_XENSTORE); 173 } 174 break; 175 176 default: 177 error = EINVAL; 178 break; 179 } 180 181 if (error == 0) 182 u->len = 0; 183 184 return (error); 185} 186 187static void 188xs_dev_dtor(void *arg) 189{ 190 struct xs_dev_data *u = arg; 191 struct xs_dev_transaction *trans, *tmp; 192 193 LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { 194 xs_transaction_end(trans->handle, 1); 195 LIST_REMOVE(trans, list); 196 free(trans, M_XENSTORE); 197 } 198 199 free(u, M_XENSTORE); 200} 201 202static int 203xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 204{ 205 struct xs_dev_data *u; 206 int error; 207 208 u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); 209 LIST_INIT(&u->transactions); 210 error = devfs_set_cdevpriv(u, xs_dev_dtor); 211 if (error != 0) 212 free(u, M_XENSTORE); 213 214 return (error); 215} 216 217static struct cdevsw xs_dev_cdevsw = { 218 .d_version = D_VERSION, 219 .d_read = xs_dev_read, 220 .d_write = xs_dev_write, 221 .d_open = xs_dev_open, 222 .d_name = "xs_dev", 223}; 224 225void 226xs_dev_init() 227{ 228 229 make_dev_credf(MAKEDEV_ETERNAL, &xs_dev_cdevsw, 0, NULL, 230 UID_ROOT, GID_WHEEL, 0400, "xen/xenstore"); 231} 232