1205869Sjfv/* 2205869Sjfv * xenstore_dev.c 3228387Sjfv * 4205869Sjfv * Driver giving user-space access to the kernel's connection to the 5205869Sjfv * XenStore service. 6205869Sjfv * 7205869Sjfv * Copyright (c) 2005, Christian Limpach 8205869Sjfv * Copyright (c) 2005, Rusty Russell, IBM Corporation 9205869Sjfv * 10205869Sjfv * This file may be distributed separately from the Linux kernel, or 11205869Sjfv * incorporated into other software packages, subject to the following license: 12205869Sjfv * 13205869Sjfv * Permission is hereby granted, free of charge, to any person obtaining a copy 14205869Sjfv * of this source file (the "Software"), to deal in the Software without 15205869Sjfv * restriction, including without limitation the rights to use, copy, modify, 16205869Sjfv * merge, publish, distribute, sublicense, and/or sell copies of the Software, 17205869Sjfv * and to permit persons to whom the Software is furnished to do so, subject to 18205869Sjfv * the following conditions: 19205869Sjfv * 20205869Sjfv * The above copyright notice and this permission notice shall be included in 21205869Sjfv * all copies or substantial portions of the Software. 22205869Sjfv * 23205869Sjfv * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24205869Sjfv * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25205869Sjfv * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26205869Sjfv * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27205869Sjfv * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28205869Sjfv * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29205869Sjfv * IN THE SOFTWARE. 30205869Sjfv */ 31205869Sjfv 32205869Sjfv#include <sys/types.h> 33205869Sjfv#include <sys/cdefs.h> 34205869Sjfv#include <sys/errno.h> 35205869Sjfv#include <sys/uio.h> 36205869Sjfv#include <sys/param.h> 37205869Sjfv#include <sys/systm.h> 38205869Sjfv#include <sys/proc.h> 39205869Sjfv#include <sys/kernel.h> 40205869Sjfv#include <sys/malloc.h> 41205869Sjfv#include <sys/conf.h> 42205869Sjfv#include <sys/module.h> 43205869Sjfv#include <sys/selinfo.h> 44205869Sjfv#include <sys/sysctl.h> 45205869Sjfv#include <sys/poll.h> 46205869Sjfv 47205869Sjfv#include <xen/xen-os.h> 48205869Sjfv 49205869Sjfv#include <xen/hypervisor.h> 50205869Sjfv#include <xen/xenstore/xenstorevar.h> 51205869Sjfv#include <xen/xenstore/xenstore_internal.h> 52205869Sjfv 53205869Sjfvstatic unsigned int max_pending_watches = 1000; 54205869Sjfv 55205869Sjfvstruct xs_dev_transaction { 56205869Sjfv LIST_ENTRY(xs_dev_transaction) list; 57205869Sjfv struct xs_transaction handle; 58205869Sjfv}; 59205869Sjfv 60205869Sjfvstruct xs_dev_watch { 61205869Sjfv LIST_ENTRY(xs_dev_watch) list; 62205869Sjfv struct xs_watch watch; 63205869Sjfv char *token; 64205869Sjfv struct xs_dev_data *user; 65205869Sjfv}; 66205869Sjfv 67205869Sjfvstruct xs_dev_data { 68205869Sjfv /* In-progress transaction. */ 69205869Sjfv LIST_HEAD(, xs_dev_transaction) transactions; 70205869Sjfv 71205869Sjfv /* Active watches. */ 72205869Sjfv LIST_HEAD(, xs_dev_watch) watches; 73205869Sjfv 74205869Sjfv /* Partial request. */ 75205869Sjfv unsigned int len; 76205869Sjfv union { 77205869Sjfv struct xsd_sockmsg msg; 78205869Sjfv char buffer[PAGE_SIZE]; 79205869Sjfv } u; 80205869Sjfv 81205869Sjfv /* Response queue. */ 82205869Sjfv#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) 83205869Sjfv char read_buffer[PAGE_SIZE]; 84205869Sjfv unsigned int read_cons, read_prod; 85205869Sjfv 86205869Sjfv /* Serializes writes to the read buffer. */ 87205869Sjfv struct mtx lock; 88205869Sjfv 89205869Sjfv /* Polling structure (for reads only ATM). */ 90205869Sjfv struct selinfo ev_rsel; 91205869Sjfv}; 92205869Sjfv 93205869Sjfvstatic void 94205869Sjfvxs_queue_reply(struct xs_dev_data *u, const char *data, unsigned int len) 95205869Sjfv{ 96205869Sjfv unsigned int i; 97205869Sjfv 98205869Sjfv for (i = 0; i < len; i++, u->read_prod++) 99205869Sjfv u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 100205869Sjfv 101205869Sjfv KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer), 102205869Sjfv ("xenstore reply too big")); 103205869Sjfv 104205869Sjfv wakeup(u); 105205869Sjfv selwakeup(&u->ev_rsel); 106205869Sjfv} 107205869Sjfv 108205869Sjfvstatic const char * 109205869Sjfvxs_dev_error_to_string(int error) 110205869Sjfv{ 111205869Sjfv unsigned int i; 112205869Sjfv 113205869Sjfv for (i = 0; i < nitems(xsd_errors); i++) 114205869Sjfv if (xsd_errors[i].errnum == error) 115205869Sjfv return (xsd_errors[i].errstring); 116205869Sjfv 117205869Sjfv return (NULL); 118205869Sjfv} 119205869Sjfv 120205869Sjfvstatic void 121205869Sjfvxs_dev_return_error(struct xs_dev_data *u, int error, int req_id, int tx_id) 122205869Sjfv{ 123205869Sjfv struct xsd_sockmsg msg; 124205869Sjfv const char *payload; 125205869Sjfv 126205869Sjfv msg.type = XS_ERROR; 127205869Sjfv msg.req_id = req_id; 128205869Sjfv msg.tx_id = tx_id; 129205869Sjfv payload = NULL; 130205869Sjfv 131205869Sjfv payload = xs_dev_error_to_string(error); 132205869Sjfv if (payload == NULL) 133205869Sjfv payload = xs_dev_error_to_string(EINVAL); 134205869Sjfv KASSERT(payload != NULL, ("Unable to find string for EINVAL errno")); 135205869Sjfv 136205869Sjfv msg.len = strlen(payload) + 1; 137205869Sjfv 138205869Sjfv mtx_lock(&u->lock); 139205869Sjfv xs_queue_reply(u, (char *)&msg, sizeof(msg)); 140205869Sjfv xs_queue_reply(u, payload, msg.len); 141205869Sjfv mtx_unlock(&u->lock); 142205869Sjfv} 143205869Sjfv 144205869Sjfvstatic int 145205869Sjfvxs_dev_watch_message_parse_string(const char **p, const char *end, 146205869Sjfv const char **string_r) 147205869Sjfv{ 148205869Sjfv const char *nul; 149205869Sjfv 150205869Sjfv nul = memchr(*p, 0, end - *p); 151205869Sjfv if (!nul) 152205869Sjfv return (EINVAL); 153205869Sjfv 154205869Sjfv *string_r = *p; 155205869Sjfv *p = nul+1; 156205869Sjfv 157205869Sjfv return (0); 158205869Sjfv} 159205869Sjfv 160205869Sjfvstatic int 161205869Sjfvxs_dev_watch_message_parse(const struct xsd_sockmsg *msg, const char **path_r, 162205869Sjfv const char **token_r) 163205869Sjfv{ 164205869Sjfv const char *p, *end; 165205869Sjfv int error; 166205869Sjfv 167205869Sjfv p = (const char *)msg + sizeof(*msg); 168205869Sjfv end = p + msg->len; 169205869Sjfv KASSERT(p <= end, ("payload overflow")); 170205869Sjfv 171205869Sjfv error = xs_dev_watch_message_parse_string(&p, end, path_r); 172205869Sjfv if (error) 173205869Sjfv return (error); 174205869Sjfv error = xs_dev_watch_message_parse_string(&p, end, token_r); 175205869Sjfv if (error) 176205869Sjfv return (error); 177205869Sjfv 178205869Sjfv return (0); 179205869Sjfv} 180205869Sjfv 181205869Sjfvstatic struct xs_dev_watch * 182205869Sjfvxs_dev_find_watch(struct xs_dev_data *u, const char *token) 183205869Sjfv{ 184205869Sjfv struct xs_dev_watch *watch; 185205869Sjfv 186205869Sjfv LIST_FOREACH(watch, &u->watches, list) 187205869Sjfv if (strcmp(watch->token, token) == 0) 188205869Sjfv return (watch); 189205869Sjfv 190205869Sjfv return (NULL); 191205869Sjfv} 192205869Sjfv 193205869Sjfvstatic void 194205869Sjfvxs_dev_watch_cb(struct xs_watch *watch, const char **vec, unsigned int len) 195205869Sjfv{ 196205869Sjfv struct xs_dev_watch *dwatch; 197205869Sjfv struct xsd_sockmsg msg; 198205869Sjfv char *payload; 199205869Sjfv 200205869Sjfv dwatch = (struct xs_dev_watch *)watch->callback_data; 201205869Sjfv msg.type = XS_WATCH_EVENT; 202205869Sjfv msg.req_id = msg.tx_id = 0; 203205869Sjfv msg.len = strlen(vec[XS_WATCH_PATH]) + strlen(dwatch->token) + 2; 204205869Sjfv 205205869Sjfv payload = malloc(msg.len, M_XENSTORE, M_WAITOK); 206205869Sjfv strcpy(payload, vec[XS_WATCH_PATH]); 207205869Sjfv strcpy(&payload[strlen(vec[XS_WATCH_PATH]) + 1], dwatch->token); 208205869Sjfv mtx_lock(&dwatch->user->lock); 209205869Sjfv xs_queue_reply(dwatch->user, (char *)&msg, sizeof(msg)); 210205869Sjfv xs_queue_reply(dwatch->user, payload, msg.len); 211205869Sjfv mtx_unlock(&dwatch->user->lock); 212205869Sjfv free(payload, M_XENSTORE); 213205869Sjfv} 214205869Sjfv 215205869Sjfvstatic struct xs_dev_transaction * 216205869Sjfvxs_dev_find_transaction(struct xs_dev_data *u, uint32_t tx_id) 217205869Sjfv{ 218205869Sjfv struct xs_dev_transaction *trans; 219205869Sjfv 220228387Sjfv LIST_FOREACH(trans, &u->transactions, list) 221219753Sjfv if (trans->handle.id == tx_id) 222219753Sjfv return (trans); 223219753Sjfv 224205869Sjfv return (NULL); 225205869Sjfv} 226205869Sjfv 227205869Sjfvstatic int 228205869Sjfvxs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) 229205869Sjfv{ 230205869Sjfv int error; 231205869Sjfv struct xs_dev_data *u; 232205869Sjfv 233205869Sjfv error = devfs_get_cdevpriv((void **)&u); 234205869Sjfv if (error != 0) 235205869Sjfv return (error); 236205869Sjfv 237205869Sjfv while (u->read_prod == u->read_cons) { 238205869Sjfv error = tsleep(u, PCATCH, "xsdread", hz/10); 239205869Sjfv if (error && error != EWOULDBLOCK) 240205869Sjfv return (error); 241205869Sjfv } 242205869Sjfv 243205869Sjfv while (uio->uio_resid > 0) { 244205869Sjfv if (u->read_cons == u->read_prod) 245205869Sjfv break; 246205869Sjfv error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 247205869Sjfv 1, uio); 248205869Sjfv if (error) 249205869Sjfv return (error); 250205869Sjfv u->read_cons++; 251205869Sjfv } 252205869Sjfv return (0); 253205869Sjfv} 254205869Sjfv 255205869Sjfvstatic int 256205869Sjfvxs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) 257205869Sjfv{ 258205869Sjfv int error; 259205869Sjfv const char *wpath, *wtoken; 260205869Sjfv struct xs_dev_data *u; 261205869Sjfv struct xs_dev_transaction *trans; 262205869Sjfv struct xs_dev_watch *watch; 263205869Sjfv void *reply; 264205869Sjfv static const char *ok = "OK"; 265205869Sjfv int len = uio->uio_resid; 266205869Sjfv 267205869Sjfv error = devfs_get_cdevpriv((void **)&u); 268205869Sjfv if (error != 0) 269205869Sjfv return (error); 270205869Sjfv 271205869Sjfv if ((len + u->len) > sizeof(u->u.buffer)) 272205869Sjfv return (EINVAL); 273205869Sjfv 274205869Sjfv error = uiomove(u->u.buffer + u->len, len, uio); 275205869Sjfv if (error) 276205869Sjfv return (error); 277205869Sjfv 278205869Sjfv u->len += len; 279205869Sjfv if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 280205869Sjfv return (0); 281205869Sjfv 282205869Sjfv switch (u->u.msg.type) { 283205869Sjfv case XS_TRANSACTION_START: 284205869Sjfv case XS_TRANSACTION_END: 285205869Sjfv case XS_DIRECTORY: 286205869Sjfv case XS_READ: 287205869Sjfv case XS_GET_PERMS: 288205869Sjfv case XS_RELEASE: 289205869Sjfv case XS_GET_DOMAIN_PATH: 290205869Sjfv case XS_WRITE: 291205869Sjfv case XS_MKDIR: 292205869Sjfv case XS_RM: 293205869Sjfv case XS_SET_PERMS: 294205869Sjfv /* Check that this transaction id is not hijacked. */ 295205869Sjfv if (u->u.msg.tx_id != 0 && 296205869Sjfv xs_dev_find_transaction(u, u->u.msg.tx_id) == NULL) { 297205869Sjfv error = EINVAL; 298205869Sjfv break; 299205869Sjfv } 300206001Smarius error = xs_dev_request_and_reply(&u->u.msg, &reply); 301205869Sjfv if (!error) { 302205869Sjfv if (u->u.msg.type == XS_TRANSACTION_START) { 303205869Sjfv trans = malloc(sizeof(*trans), M_XENSTORE, 304205869Sjfv M_WAITOK); 305205869Sjfv trans->handle.id = strtoul(reply, NULL, 0); 306205869Sjfv LIST_INSERT_HEAD(&u->transactions, trans, list); 307205869Sjfv } else if (u->u.msg.type == XS_TRANSACTION_END) { 308205869Sjfv trans = xs_dev_find_transaction(u, 309205869Sjfv u->u.msg.tx_id); 310205869Sjfv KASSERT(trans != NULL, 311205869Sjfv ("Unable to find transaction")); 312205869Sjfv LIST_REMOVE(trans, list); 313205869Sjfv free(trans, M_XENSTORE); 314205869Sjfv } 315205869Sjfv mtx_lock(&u->lock); 316205869Sjfv xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 317205869Sjfv xs_queue_reply(u, (char *)reply, u->u.msg.len); 318205869Sjfv mtx_unlock(&u->lock); 319205869Sjfv free(reply, M_XENSTORE); 320205869Sjfv } 321205869Sjfv break; 322205869Sjfv case XS_WATCH: 323205869Sjfv u->u.msg.tx_id = 0; 324205869Sjfv error = xs_dev_watch_message_parse(&u->u.msg, &wpath, &wtoken); 325205869Sjfv if (error) 326205869Sjfv break; 327205869Sjfv if (xs_dev_find_watch(u, wtoken) != NULL) { 328205869Sjfv error = EINVAL; 329205869Sjfv break; 330205869Sjfv } 331205869Sjfv 332205869Sjfv watch = malloc(sizeof(*watch), M_XENSTORE, M_WAITOK); 333205869Sjfv watch->watch.node = strdup(wpath, M_XENSTORE); 334205869Sjfv watch->watch.callback = xs_dev_watch_cb; 335205869Sjfv watch->watch.callback_data = (uintptr_t)watch; 336205869Sjfv watch->watch.max_pending = max_pending_watches; 337205869Sjfv watch->token = strdup(wtoken, M_XENSTORE); 338205869Sjfv watch->user = u; 339205869Sjfv 340205869Sjfv error = xs_register_watch(&watch->watch); 341205869Sjfv if (error != 0) { 342205869Sjfv free(watch->token, M_XENSTORE); 343205869Sjfv free(watch->watch.node, M_XENSTORE); 344211913Syongari free(watch, M_XENSTORE); 345211913Syongari break; 346214646Sjfv } 347214646Sjfv 348214646Sjfv LIST_INSERT_HEAD(&u->watches, watch, list); 349214646Sjfv u->u.msg.len = sizeof(ok); 350214646Sjfv mtx_lock(&u->lock); 351214646Sjfv xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 352214646Sjfv xs_queue_reply(u, ok, sizeof(ok)); 353214646Sjfv mtx_unlock(&u->lock); 354214646Sjfv break; 355214646Sjfv case XS_UNWATCH: 356205869Sjfv u->u.msg.tx_id = 0; 357205869Sjfv error = xs_dev_watch_message_parse(&u->u.msg, &wpath, &wtoken); 358205869Sjfv if (error) 359205869Sjfv break; 360214646Sjfv watch = xs_dev_find_watch(u, wtoken); 361214646Sjfv if (watch == NULL) { 362205869Sjfv error = EINVAL; 363205869Sjfv break; 364205869Sjfv } 365205869Sjfv 366250414Sluigi LIST_REMOVE(watch, list); 367205869Sjfv xs_unregister_watch(&watch->watch); 368205869Sjfv free(watch->watch.node, M_XENSTORE); 369205869Sjfv free(watch->token, M_XENSTORE); 370205869Sjfv free(watch, M_XENSTORE); 371205869Sjfv u->u.msg.len = sizeof(ok); 372205869Sjfv mtx_lock(&u->lock); 373205869Sjfv xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 374205869Sjfv xs_queue_reply(u, ok, sizeof(ok)); 375205869Sjfv mtx_unlock(&u->lock); 376205869Sjfv break; 377205869Sjfv default: 378205869Sjfv error = EINVAL; 379205869Sjfv break; 380205869Sjfv } 381205869Sjfv 382205869Sjfv if (error != 0) 383205869Sjfv xs_dev_return_error(u, error, u->u.msg.req_id, u->u.msg.tx_id); 384205869Sjfv 385205869Sjfv /* Reset the write buffer. */ 386205869Sjfv u->len = 0; 387205869Sjfv 388205869Sjfv return (0); 389205869Sjfv} 390205869Sjfv 391205869Sjfvstatic int 392205869Sjfvxs_dev_poll(struct cdev *dev, int events, struct thread *td) 393205869Sjfv{ 394205869Sjfv struct xs_dev_data *u; 395205869Sjfv int error, mask; 396205869Sjfv 397205869Sjfv error = devfs_get_cdevpriv((void **)&u); 398205869Sjfv if (error != 0) 399205869Sjfv return (POLLERR); 400205869Sjfv 401205869Sjfv /* we can always write */ 402205869Sjfv mask = events & (POLLOUT | POLLWRNORM); 403205869Sjfv 404205869Sjfv if (events & (POLLIN | POLLRDNORM)) { 405205869Sjfv if (u->read_cons != u->read_prod) { 406205869Sjfv mask |= events & (POLLIN | POLLRDNORM); 407205869Sjfv } else { 408205869Sjfv /* Record that someone is waiting */ 409205869Sjfv selrecord(td, &u->ev_rsel); 410205869Sjfv } 411205869Sjfv } 412205869Sjfv 413205869Sjfv return (mask); 414205869Sjfv} 415205869Sjfv 416205869Sjfvstatic void 417205869Sjfvxs_dev_dtor(void *arg) 418205869Sjfv{ 419205869Sjfv struct xs_dev_data *u = arg; 420205869Sjfv struct xs_dev_transaction *trans, *tmpt; 421205869Sjfv struct xs_dev_watch *watch, *tmpw; 422205869Sjfv 423205869Sjfv seldrain(&u->ev_rsel); 424214646Sjfv 425214646Sjfv LIST_FOREACH_SAFE(trans, &u->transactions, list, tmpt) { 426214646Sjfv xs_transaction_end(trans->handle, 1); 427205869Sjfv LIST_REMOVE(trans, list); 428205869Sjfv free(trans, M_XENSTORE); 429205869Sjfv } 430205869Sjfv 431205869Sjfv LIST_FOREACH_SAFE(watch, &u->watches, list, tmpw) { 432205869Sjfv LIST_REMOVE(watch, list); 433205869Sjfv xs_unregister_watch(&watch->watch); 434205869Sjfv free(watch->watch.node, M_XENSTORE); 435205869Sjfv free(watch->token, M_XENSTORE); 436205869Sjfv free(watch, M_XENSTORE); 437205869Sjfv } 438205869Sjfv mtx_destroy(&u->lock); 439205869Sjfv 440205869Sjfv free(u, M_XENSTORE); 441205869Sjfv} 442205869Sjfv 443205869Sjfvstatic int 444205869Sjfvxs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 445205869Sjfv{ 446205869Sjfv struct xs_dev_data *u; 447205869Sjfv int error; 448205869Sjfv 449205869Sjfv u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); 450205869Sjfv mtx_init(&u->lock, "xsdev_lock", NULL, MTX_DEF); 451205869Sjfv LIST_INIT(&u->transactions); 452205869Sjfv LIST_INIT(&u->watches); 453205869Sjfv error = devfs_set_cdevpriv(u, xs_dev_dtor); 454205869Sjfv if (error != 0) 455205869Sjfv free(u, M_XENSTORE); 456205869Sjfv 457205869Sjfv return (error); 458205869Sjfv} 459205869Sjfv 460205869Sjfvstatic struct cdevsw xs_dev_cdevsw = { 461205869Sjfv .d_version = D_VERSION, 462205869Sjfv .d_read = xs_dev_read, 463205869Sjfv .d_write = xs_dev_write, 464205869Sjfv .d_open = xs_dev_open, 465205869Sjfv .d_poll = xs_dev_poll, 466205869Sjfv .d_name = "xs_dev", 467205869Sjfv}; 468205869Sjfv 469205869Sjfv/*------------------ Private Device Attachment Functions --------------------*/ 470205869Sjfv/** 471205869Sjfv * \brief Identify instances of this device type in the system. 472205869Sjfv * 473205869Sjfv * \param driver The driver performing this identify action. 474205869Sjfv * \param parent The NewBus parent device for any devices this method adds. 475205869Sjfv */ 476205869Sjfvstatic void 477205869Sjfvxs_dev_identify(driver_t *driver, device_t parent) 478205869Sjfv{ 479205869Sjfv /* 480205869Sjfv * A single device instance for our driver is always present 481205869Sjfv * in a system operating under Xen. 482205869Sjfv */ 483205869Sjfv BUS_ADD_CHILD(parent, 0, driver->name, 0); 484205869Sjfv} 485205869Sjfv 486205869Sjfv/** 487205869Sjfv * \brief Probe for the existence of the Xenstore device 488205869Sjfv * 489205869Sjfv * \param dev NewBus device_t for this instance. 490205869Sjfv * 491205869Sjfv * \return Always returns 0 indicating success. 492205869Sjfv */ 493205869Sjfvstatic int 494205869Sjfvxs_dev_probe(device_t dev) 495205869Sjfv{ 496205869Sjfv 497205869Sjfv device_set_desc(dev, "Xenstore user-space device"); 498 return (0); 499} 500 501/** 502 * \brief Attach the Xenstore device. 503 * 504 * \param dev NewBus device_t for this instance. 505 * 506 * \return On success, 0. Otherwise an errno value indicating the 507 * type of failure. 508 */ 509static int 510xs_dev_attach(device_t dev) 511{ 512 struct cdev *xs_cdev; 513 struct sysctl_ctx_list *sysctl_ctx; 514 struct sysctl_oid *sysctl_tree; 515 516 sysctl_ctx = device_get_sysctl_ctx(dev); 517 sysctl_tree = device_get_sysctl_tree(dev); 518 if (sysctl_ctx == NULL || sysctl_tree == NULL) 519 return (EINVAL); 520 521 SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 522 "max_pending_watch_events", CTLFLAG_RW, &max_pending_watches, 0, 523 "maximum amount of pending watch events to be delivered"); 524 525 xs_cdev = make_dev_credf(MAKEDEV_ETERNAL, &xs_dev_cdevsw, 0, NULL, 526 UID_ROOT, GID_WHEEL, 0400, "xen/xenstore"); 527 if (xs_cdev == NULL) 528 return (EINVAL); 529 530 return (0); 531} 532 533/*-------------------- Private Device Attachment Data -----------------------*/ 534static device_method_t xs_dev_methods[] = { 535 /* Device interface */ 536 DEVMETHOD(device_identify, xs_dev_identify), 537 DEVMETHOD(device_probe, xs_dev_probe), 538 DEVMETHOD(device_attach, xs_dev_attach), 539 540 DEVMETHOD_END 541}; 542 543DEFINE_CLASS_0(xs_dev, xs_dev_driver, xs_dev_methods, 0); 544 545DRIVER_MODULE(xs_dev, xenstore, xs_dev_driver, NULL, NULL); 546