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 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 53 struct xs_dev_transaction { 54 LIST_ENTRY(xs_dev_transaction) list; 55 struct xs_transaction handle; 56 }; 57 58 struct 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 75 static int 76 xs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) 77 { 78 int error; 79 struct xs_dev_data *u = dev->si_drv1; 80 81 while (u->read_prod == u->read_cons) { 82 error = tsleep(u, PCATCH, "xsdread", hz/10); 83 if (error && error != EWOULDBLOCK) 84 return (error); 85 } 86 87 while (uio->uio_resid > 0) { 88 if (u->read_cons == u->read_prod) 89 break; 90 error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 91 1, uio); 92 if (error) 93 return (error); 94 u->read_cons++; 95 } 96 return (0); 97 } 98 99 static void 100 xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len) 101 { 102 int i; 103 104 for (i = 0; i < len; i++, u->read_prod++) 105 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 106 107 KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), 108 ("xenstore reply too big")); 109 110 wakeup(u); 111 } 112 113 static int 114 xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) 115 { 116 int error; 117 struct xs_dev_data *u = dev->si_drv1; 118 struct xs_dev_transaction *trans; 119 void *reply; 120 int len = uio->uio_resid; 121 122 if ((len + u->len) > sizeof(u->u.buffer)) 123 return (EINVAL); 124 125 error = uiomove(u->u.buffer + u->len, len, uio); 126 if (error) 127 return (error); 128 129 u->len += len; 130 if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 131 return (0); 132 133 switch (u->u.msg.type) { 134 case XS_TRANSACTION_START: 135 case XS_TRANSACTION_END: 136 case XS_DIRECTORY: 137 case XS_READ: 138 case XS_GET_PERMS: 139 case XS_RELEASE: 140 case XS_GET_DOMAIN_PATH: 141 case XS_WRITE: 142 case XS_MKDIR: 143 case XS_RM: 144 case XS_SET_PERMS: 145 error = xs_dev_request_and_reply(&u->u.msg, &reply); 146 if (!error) { 147 if (u->u.msg.type == XS_TRANSACTION_START) { 148 trans = malloc(sizeof(*trans), M_XENSTORE, 149 M_WAITOK); 150 trans->handle.id = strtoul(reply, NULL, 0); 151 LIST_INSERT_HEAD(&u->transactions, trans, list); 152 } else if (u->u.msg.type == XS_TRANSACTION_END) { 153 LIST_FOREACH(trans, &u->transactions, list) 154 if (trans->handle.id == u->u.msg.tx_id) 155 break; 156 #if 0 /* XXX does this mean the list is empty? */ 157 BUG_ON(&trans->list == &u->transactions); 158 #endif 159 LIST_REMOVE(trans, list); 160 free(trans, M_XENSTORE); 161 } 162 xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 163 xs_queue_reply(u, (char *)reply, u->u.msg.len); 164 free(reply, M_XENSTORE); 165 } 166 break; 167 168 default: 169 error = EINVAL; 170 break; 171 } 172 173 if (error == 0) 174 u->len = 0; 175 176 return (error); 177 } 178 179 static int 180 xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 181 { 182 struct xs_dev_data *u; 183 184 #if 0 /* XXX figure out if equiv needed */ 185 nonseekable_open(inode, filp); 186 #endif 187 u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); 188 LIST_INIT(&u->transactions); 189 dev->si_drv1 = u; 190 191 return (0); 192 } 193 194 static int 195 xs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 196 { 197 struct xs_dev_data *u = dev->si_drv1; 198 struct xs_dev_transaction *trans, *tmp; 199 200 LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { 201 xs_transaction_end(trans->handle, 1); 202 LIST_REMOVE(trans, list); 203 free(trans, M_XENSTORE); 204 } 205 206 free(u, M_XENSTORE); 207 return (0); 208 } 209 210 static struct cdevsw xs_dev_cdevsw = { 211 .d_version = D_VERSION, 212 .d_read = xs_dev_read, 213 .d_write = xs_dev_write, 214 .d_open = xs_dev_open, 215 .d_close = xs_dev_close, 216 .d_name = "xs_dev", 217 }; 218 219 void 220 xs_dev_init() 221 { 222 make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, 223 "xen/xenstore"); 224 } 225