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$"); 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 #include <sys/module.h> 47 48 #include <xen/xen-os.h> 49 50 #include <xen/hypervisor.h> 51 #include <xen/xenstore/xenstorevar.h> 52 #include <xen/xenstore/xenstore_internal.h> 53 54 struct xs_dev_transaction { 55 LIST_ENTRY(xs_dev_transaction) list; 56 struct xs_transaction handle; 57 }; 58 59 struct xs_dev_data { 60 /* In-progress transaction. */ 61 LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions; 62 63 /* Partial request. */ 64 unsigned int len; 65 union { 66 struct xsd_sockmsg msg; 67 char buffer[PAGE_SIZE]; 68 } u; 69 70 /* Response queue. */ 71 #define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) 72 char read_buffer[PAGE_SIZE]; 73 unsigned int read_cons, read_prod; 74 }; 75 76 static int 77 xs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) 78 { 79 int error; 80 struct xs_dev_data *u = dev->si_drv1; 81 82 while (u->read_prod == u->read_cons) { 83 error = tsleep(u, PCATCH, "xsdread", hz/10); 84 if (error && error != EWOULDBLOCK) 85 return (error); 86 } 87 88 while (uio->uio_resid > 0) { 89 if (u->read_cons == u->read_prod) 90 break; 91 error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 92 1, uio); 93 if (error) 94 return (error); 95 u->read_cons++; 96 } 97 return (0); 98 } 99 100 static void 101 xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len) 102 { 103 int i; 104 105 for (i = 0; i < len; i++, u->read_prod++) 106 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 107 108 KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), 109 ("xenstore reply too big")); 110 111 wakeup(u); 112 } 113 114 static int 115 xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) 116 { 117 int error; 118 struct xs_dev_data *u = dev->si_drv1; 119 struct xs_dev_transaction *trans; 120 void *reply; 121 int len = uio->uio_resid; 122 123 if ((len + u->len) > sizeof(u->u.buffer)) 124 return (EINVAL); 125 126 error = uiomove(u->u.buffer + u->len, len, uio); 127 if (error) 128 return (error); 129 130 u->len += len; 131 if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 132 return (0); 133 134 switch (u->u.msg.type) { 135 case XS_TRANSACTION_START: 136 case XS_TRANSACTION_END: 137 case XS_DIRECTORY: 138 case XS_READ: 139 case XS_GET_PERMS: 140 case XS_RELEASE: 141 case XS_GET_DOMAIN_PATH: 142 case XS_WRITE: 143 case XS_MKDIR: 144 case XS_RM: 145 case XS_SET_PERMS: 146 error = xs_dev_request_and_reply(&u->u.msg, &reply); 147 if (!error) { 148 if (u->u.msg.type == XS_TRANSACTION_START) { 149 trans = malloc(sizeof(*trans), M_XENSTORE, 150 M_WAITOK); 151 trans->handle.id = strtoul(reply, NULL, 0); 152 LIST_INSERT_HEAD(&u->transactions, trans, list); 153 } else if (u->u.msg.type == XS_TRANSACTION_END) { 154 LIST_FOREACH(trans, &u->transactions, list) 155 if (trans->handle.id == u->u.msg.tx_id) 156 break; 157 #if 0 /* XXX does this mean the list is empty? */ 158 BUG_ON(&trans->list == &u->transactions); 159 #endif 160 LIST_REMOVE(trans, list); 161 free(trans, M_XENSTORE); 162 } 163 xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 164 xs_queue_reply(u, (char *)reply, u->u.msg.len); 165 free(reply, M_XENSTORE); 166 } 167 break; 168 169 default: 170 error = EINVAL; 171 break; 172 } 173 174 if (error == 0) 175 u->len = 0; 176 177 return (error); 178 } 179 180 static int 181 xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 182 { 183 struct xs_dev_data *u; 184 185 #if 0 /* XXX figure out if equiv needed */ 186 nonseekable_open(inode, filp); 187 #endif 188 u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); 189 LIST_INIT(&u->transactions); 190 dev->si_drv1 = u; 191 192 return (0); 193 } 194 195 static int 196 xs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 197 { 198 struct xs_dev_data *u = dev->si_drv1; 199 struct xs_dev_transaction *trans, *tmp; 200 201 LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { 202 xs_transaction_end(trans->handle, 1); 203 LIST_REMOVE(trans, list); 204 free(trans, M_XENSTORE); 205 } 206 207 free(u, M_XENSTORE); 208 return (0); 209 } 210 211 static struct cdevsw xs_dev_cdevsw = { 212 .d_version = D_VERSION, 213 .d_read = xs_dev_read, 214 .d_write = xs_dev_write, 215 .d_open = xs_dev_open, 216 .d_close = xs_dev_close, 217 .d_name = "xs_dev", 218 }; 219 220 /*------------------ Private Device Attachment Functions --------------------*/ 221 /** 222 * \brief Identify instances of this device type in the system. 223 * 224 * \param driver The driver performing this identify action. 225 * \param parent The NewBus parent device for any devices this method adds. 226 */ 227 static void 228 xs_dev_identify(driver_t *driver __unused, device_t parent) 229 { 230 /* 231 * A single device instance for our driver is always present 232 * in a system operating under Xen. 233 */ 234 BUS_ADD_CHILD(parent, 0, driver->name, 0); 235 } 236 237 /** 238 * \brief Probe for the existance of the Xenstore device 239 * 240 * \param dev NewBus device_t for this instance. 241 * 242 * \return Always returns 0 indicating success. 243 */ 244 static int 245 xs_dev_probe(device_t dev) 246 { 247 248 device_set_desc(dev, "Xenstore user-space device"); 249 return (0); 250 } 251 252 /** 253 * \brief Attach the Xenstore device. 254 * 255 * \param dev NewBus device_t for this instance. 256 * 257 * \return On success, 0. Otherwise an errno value indicating the 258 * type of failure. 259 */ 260 static int 261 xs_dev_attach(device_t dev) 262 { 263 struct cdev *xs_cdev; 264 265 xs_cdev = make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, 266 "xen/xenstore"); 267 if (xs_cdev == NULL) 268 return (EINVAL); 269 270 return (0); 271 } 272 273 /*-------------------- Private Device Attachment Data -----------------------*/ 274 static device_method_t xs_dev_methods[] = { 275 /* Device interface */ 276 DEVMETHOD(device_identify, xs_dev_identify), 277 DEVMETHOD(device_probe, xs_dev_probe), 278 DEVMETHOD(device_attach, xs_dev_attach), 279 280 DEVMETHOD_END 281 }; 282 283 DEFINE_CLASS_0(xs_dev, xs_dev_driver, xs_dev_methods, 0); 284 devclass_t xs_dev_devclass; 285 286 DRIVER_MODULE(xs_dev, xenstore, xs_dev_driver, xs_dev_devclass, 287 NULL, NULL); 288