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